章 55. PHP 和 HTML

PHP 和 HTML 有很多相互作用:PHP 能建立 HTML,HTML 可以向 PHP 傳遞訊息。在閱讀這些常見問題之前,先學會怎樣從 PHP 之外取得變量很重要。此主旨的手冊頁也內含很多例子。還要仔細留意 register_globals 對你意味著什麼。

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

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

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

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

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

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

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

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

例子 55-2. 等待會員編輯的資料

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

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

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

例子 55-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.xfoo.y

因為 foo.xfoo.y 在 PHP 中會成為非法的變量名,它們被自動轉換成了 foo_xfoo_y。也就是用下劃線代替了點。因此,可以按照在來自 PHP 之外的變量這一節中說明的那樣訪問這些變量。例如,$_GET['foo_x']

注: 請求變量名中的空格被轉換為下劃線。

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="yes">
每個被選項將這樣被傳遞到表單處理程式:
var=option1
var=option2
var=option3
每個選項將覆蓋前面一個 $var 變量的內容。解決專案是用 PHP 的「表單單元陣列」特性。使用方法如下:
<select name="var[]" multiple="yes">
這將告訴 PHP 將 $var 當成陣列對待,每個對 var[] 的賦值都會給陣列增加一項。第一項將成為 $var[0],下一個是 $var[1],等等。可以用 count() 函數來測定選取了多少個項目,必要時可以用 sort() 函數來對選項的陣列進行排序。

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

5. 怎樣從 Javascript 傳遞一個變量到 PHP?

由於 Javascript (通常情況下)是用戶端技術,而 PHP (通常情況下)是伺服器端技術,而且 HTTP 是一種「無狀態」協定,因此兩種語系之間不能直接共享變量。

但是,有可能在二者之間傳遞變量。一種實現的方法是用 PHP 建立 Javascript 代碼,並讓瀏覽器自動重整,將特定的變量傳遞回 PHP 腳本。以下例子顯示了如何這樣做--讓 PHP 代碼取得顯示螢幕的高度和寬度,通常只能在用戶端這麼做。

<?php
if (isset($_GET['width']) AND isset($_GET['height'])) {
  
// output the geometry variables
  
echo "Screen width is: "$_GET['width'] ."<br />\n";
  echo 
"Screen height is: "$_GET['height'] ."<br />\n";
} else {
  
// pass the geometry variables
  // (preserve the original query string
  //   -- post variables will need to handled differently)

  
echo "<script language='javascript'>\n";
  echo 
"  location.href=\"${_SERVER['SCRIPT_NAME']}?${_SERVER['QUERY_STRING']}"
            
"&width=\" + screen.width + \"&height=\" + screen.height;\n";
  echo 
"</script>\n";
  exit();
}
?>