章 51. PHP 和 HTML

PHP 和 HTML 有很多相互作用:PHP 能產生 HTML,HTML 可以向 PHP 傳遞訊息。

1. 當我通過表單/URL 傳值時需要用什麼編碼/解碼方法?
2. 我在試用 <input type="image"> 標記,但是沒有 $foo.x 和 $foo.y 變數,它們哪去了?
3. 怎樣在 HTML 的 <form> 中建立陣列?
4. 怎樣從可多選的 HTML 的 select multiple 標記中得到所有結果?

1. 當我通過表單/URL 傳值時需要用什麼編碼/解碼方法?

在幾個環節上編碼方式很重要。假定你有 string $data,其中包含了你想通過非編碼方式傳遞的字串,那這是相關步驟:

  • HTML 解析。要指定一個任意的字串,你必須將其放在雙引號中,並用 htmlspecialchars 處理整個值。

  • URL:URL 由幾部分組成。如果你希望自己的資料被當作其中一項來解釋,你必須urlencode() 對其編碼。

例子 51-1. 隱藏的 HTML 表單單元

<?php
    echo "<input type=hidden value=\"" . htmlspecialchars($data) . "\">\n";
?>

註: urlencode() 來處理 $data 是錯誤的,因為是瀏覽器的責任來 urlencode() 資料。所有流行的瀏覽器都能正確處理。注意不論何種方法(例如 GET 或 POST)都會這樣。不過你只會在用 GET 請求時注意到這一點,因為 POST 請求通常是隱藏的。

例子 51-2. 等待用戶編輯的資料

<?php
    echo "<textarea name=mydata>\n";
    echo htmlspecialchars($data)."\n";
    echo "</textarea>";
?>

註: 資料會按照預期的顯示在瀏覽器中,因為瀏覽器會解釋 HTML 轉義符號。

當送出時,不論是 GET 或者 POST 方法,資料都會被瀏覽器進行 urlencode 來傳輸,並直接被 PHP urldecode。所以最終你不需要自己處理任何 urlencoding/urldecoding,全都是自動處理的。

例子 51-3. URL 中的例子

<?php
    echo "<a href=\"" . htmlspecialchars("/nextpage.php?stage=23&data=" .
        urlencode($data)) . "\">\n";
?>

註: 事實上你在捏造一個 HTML 的 GET 請求,因此需要手工對資料進行 urlencode()

註: 你需要對整個 URL 進行 htmlspecialchars(),因為 URL 是作為 HTML 屬性的一個值出現的。在本例中,瀏覽器會首先對值進行 un-htmlspecialchars(),然後再傳遞此 URL。PHP 將能正確理解 URL,因為你對資料進行了 urlencoded()

你會注意到 URL 中的 & 被替換成了 &amp;。如果你忘了這一步,儘管大多數瀏覽器都能恢複,但也不總是這樣。因此即使 URL 不是動態的,你也需要對 URL 進行 htmlspecialchars()

2. 我在試用 <input type="image"> 標記,但是沒有 $foo.x 和 $foo.y 變數,它們哪去了?

當送出表單時,可以用圖片代替標準的送出按鈕,用類似這樣的標記:
<input type="image" src="image.gif" name="foo">
當用戶點擊了圖片的任何部分,該表單會被發送到伺服器並加上兩個額外的變數:foo.x 和 foo.y。

因為 $foo.x 和 $foo.y 在 PHP 中是非法的變數名,它們被自動轉換成了 $foo_x 和 $foo_y。也就是用下劃線代替了點。

3. 怎樣在 HTML 的 <form> 中建立陣列?

要使你的 <form> 結果被當成 array 發送到 PHP 腳本,你要對 <input>,<select> 或者 <textarea> 單元這樣命名:
<input name="MyArray[]">
<input name="MyArray[]">
<input name="MyArray[]">
<input name="MyArray[]">
注意變數名後的方括號,這使其成為一個陣列。你可以通過給不同的單元分配相同的名字來把單元分組到不同的陣列裡:
<input name="MyArray[]">
<input name="MyArray[]">
<input name="MyOtherArray[]">
<input name="MyOtherArray[]">
這將產生兩個陣列,MyArray 和 MyOtherArray,並發送給 PHP 腳本。還可以給陣列分配指定的鍵名:
<input name="AnotherArray[]">
<input name="AnotherArray[]">
<input name="AnotherArray[email]">
<input name="AnotherArray[phone]">
AnotherArray 陣列將包含鍵名 0,1,email 和 phone。

註: 指定陣列的鍵名是 HTML 的可選項。如果你不指定鍵名,則陣列被按照單元在表單中出現的順序填充。第一個例子將包含鍵名 0,1,2 和 3。

參見陣列函式庫PHP 的外部變數

4. 怎樣從可多選的 HTML 的 select multiple 標記中得到所有結果?

可多選的 select multiple 標記是 HTML 的一個建構,允許用戶從一個列表中選擇多個項目。這些項目接著被傳遞給該表單 action 中指定的處理程序。問題是它們都會被用同樣的名字傳遞。例如:
<select name="var" multiple>
每個被選項將這樣被傳遞到表單處理程序:
var=option1
var=option2
var=option3
每個選項將覆蓋前面一個 $var 變數的內容。解決方案是用 PHP 的“表單單元陣列”特性。使用方法如下:
<select name="var[]" multiple>
這將告訴 PHP 將 $var 當成陣列對待,每個對 var[] 的設值都會給陣列增加一項。第一項將成為 $var[0],下一個是 $var[1],等等。可以用 count() 函式來測定選擇了多少個項目,必要時可以用 sort() 函式來對選項的陣列進行排序。

注意如果你在 JavaScript 中通過名字來引用單元,單元名字中的 [] 可能會造成問題。用表單單元中的數字序號來替代,或者將變數名用單引號括起來並用其作為單元陣列的索引,例如:
variable = documents.forms[0].elements['var[]'];