章 54. 使用 PHP

本節彙集了你在寫 PHP 腳本時可能碰到的大多數普通錯誤。

1. 我想寫一個可以處理任何表單來的資料的通用 PHP 腳本。我怎麼知道哪個 POST 方法變量可用呢?
2. 我需要在所有的單引號(')前加一個反斜線(\),使它們變成(\'),我如何能夠通過正則表達式來實現?我同樣希望能夠將(")轉換成(\"),將(\)轉換成(\\)。
3. 我所有的(")和(')都被變成了(\")和(\'),我如何才能去掉這些不必要的反斜線?它們為什麼及如何出現?
4. 當我這樣做時,輸出顯示的次序是錯的:
<?php
function myfunc($argument)
{
    echo 
$argument 10;
}
$variable 10;
echo 
"myfunc($variable) = " myfunc($variable);
?>
這是怎麼回事?
5. 下面代碼怎麼沒有分紅兩行顯示?
<pre>
<?php echo "This should be the first line."?>
<?php 
echo "This should show up after the new line above."?>
</pre>
6. 我得到訊息「Warning: Cannot send session cookie - headers already sent...」或是「Cannot add header information - headers already sent...」。
7. 我需要直接訪問請求報頭中的訊息,怎麼能辦到?
8. 當我用 IIS 進行 HTTP 認證時得到「No Input file specified」訊息。
9. Windows:不能訪問另一台電腦上用 IIS 共享的檔案。
10. 我的 PHP 腳本在 IE 和 Lynx 下能工作,但是在 Netscape 中有的輸出丟失了。當我用「檢視源檔案」時可以在 IE 中看到內容,但是 Netscape 中不能。
11. 我怎樣混合使用 XML 和 PHP?它不認我的 <?xml 旗標!
12. 怎樣用 FrontPage 或是其它非要把我的代碼移來移去的 HTML 編輯器來編輯 PHP?
13. 哪裡可以找到所有可用的 PHP 預定義變量的完整清單?
14. 怎樣才能不用非免費的商業庫 ClibPDFPDFLib 來建立 PDF 文件?我想要個免費的並且不需要再連線別的 PDF 庫。
15. 我試著在會員自訂函數中訪問一個標準的 CGI 變量(例如 $DOCUMENT_ROOT 或 $HTTP_REFERER),但是找不到,哪裡出了錯?
16. 有些 PHP 選項可以接受縮寫的位元組值,與僅能接受 integer 位元組值相反。都有哪些縮寫位元組值?可以將其用於 php.ini 之外嗎?

1. 我想寫一個可以處理任何表單來的資料的通用 PHP 腳本。我怎麼知道哪個 POST 方法變量可用呢?

PHP 提供很多「預定義變量」,例如超全局變量 $_POST。可以遍歷 $_POST 變量,因為它是一個和所有通過 POST 方法傳遞資料相聯繫的陣列。例如,可以用 foreach 簡單地遍歷它,檢查 empty() 值,以及將它們輸出。
<?php
$empty 
$post = array();
foreach (
$_POST as $varname => $varvalue) {
    if (empty(
$varvalue)) {
        
$empty[$varname] = $varvalue;
    } else {
        
$post[$varname] = $varvalue;
    }
}

print 
"<pre>";
if (empty(
$empty)) {
    print 
"None of the POSTed values are empty, posted:\n";
    
var_dump($post);
} else {
    print 
"We have " count($empty) . " empty values\n";
    print 
"Posted:\n"var_dump($post);
    print 
"Empty:\n";  var_dump($empty);
    exit;
}
?>

Superglobals 可用性說明: 自 PHP 4.1.0 起,可以使用超全局陣列變量例如 $_GET$_POST$_SERVER 等等。更多訊息請閱讀手冊中的 superglobals

2. 我需要在所有的單引號(')前加一個反斜線(\),使它們變成(\'),我如何能夠通過正則表達式來實現?我同樣希望能夠將(")轉換成(\"),將(\)轉換成(\\)。

函數 addslashes() 能夠實現這種動作。請參閱函數 mysql_escape_string()。另外,還可以用函數 stripslashes() 來去掉反斜線。

magic_quotes_gpc 設定選項說明: PHP 的設定選項 magic_quotes_gpc 的預設值為 on。這相當於自動對所有的 GET、POST、COOKIE 資料使用了 addslashes() 函數。可以用 stripslashes() 函數來去掉它們。

3. 我所有的(")和(')都被變成了(\")和(\'),我如何才能去掉這些不必要的反斜線?它們為什麼及如何出現?

PHP 函數 stripslashes() 能夠從 string 中去掉所有的反斜線。這些反斜線出現最有可能的原因是 PHP 設定項 magic_quotes_gpc 被開啟。

magic_quotes_gpc 設定選項說明: PHP 的設定選項 magic_quotes_gpc 的預設值為 on。這相當於自動對所有的 GET、POST、COOKIE 資料使用了 addslashes() 函數。可以用 stripslashes() 函數來去掉它們。

4. 當我這樣做時,輸出顯示的次序是錯的:
<?php
function myfunc($argument)
{
    echo 
$argument 10;
}
$variable 10;
echo 
"myfunc($variable) = " myfunc($variable);
?>
這是怎麼回事?

要在一個表達式中(例如在上面的例子中和其它字串連線)使用函數的結果,需要 return() 這個值,而不是 echo() 它。

5. 下面代碼怎麼沒有分紅兩行顯示?
<pre>
<?php echo "This should be the first line."?>
<?php 
echo "This should show up after the new line above."?>
</pre>

在 PHP 中,一段代碼的結束旗標要麼是「?>」要麼是「?>\n」(\n 表示換行)。因此在上面的例子中,輸出的句子將顯示在同一行中,因為 PHP 忽略了代碼結束旗標後面的換行。這意味著若果要輸出一個換行符,需要在每段 PHP 代碼的結束旗標後面多加一個換行。

PHP 為什麼這麼做呢?因為在格式化標準的 HTML 時,這樣通常會更容易。假如輸出了換行而你不需要這個換行時,就不得不用一個非常長的行來達到這樣的效果,或是讓產生的 HTML 頁面的源檔案的格式很難讀。

6. 我得到訊息「Warning: Cannot send session cookie - headers already sent...」或是「Cannot add header information - headers already sent...」。

函數 header()setcookie()session 函數需要在輸出流中增加頭訊息。但是頭訊息只能在其它任何輸出內容之前傳送。在使用這些函數前不能有任何(如 HTML)的輸出。函數 headers_sent() 能夠檢查腳本是否已經傳送了頭訊息。請參閱輸出控制函數

7. 我需要直接訪問請求報頭中的訊息,怎麼能辦到?

若果以 Apache 的模組模式運行 PHP,那麼函數 getallheaders() 可以做這件事。因此下面的代碼可以顯示所有的請求報頭:
<?php
$headers 
getallheaders();
foreach (
$headers as $name => $content) {
    echo 
"headers[$name] = $content<br />\n";
}
?>

請參閱函數 apache_lookup_uri()apache_response_headers()fsockopen()

8. 當我用 IIS 進行 HTTP 認證時得到「No Input file specified」訊息。

IIS 的安全模型這裡有毛病。這是所有 IIS 下運行的 CGI 程式所共有的問題。一個解決辦法是建立一個純 HTML 檔案(不經由 PHP 解析)作為要進入認證目錄的登入頁面,然後用 META 旗標來重導至 PHP 頁面,或是用一個連線到 PHP 頁面。然後 PHP 就可以正確識別認證訊息了。若果是用 ISAPI 模組,那沒有這個問題。其它 NT 下的 web 伺服器不受此影響。更多訊息見 http://support.microsoft.com/kb/q160422/HTTP 認證一章。

9. Windows:不能訪問另一台電腦上用 IIS 共享的檔案。

必須要做些修改。開啟 Internet 訊息服務,找到你的 PHP 檔案並開啟屬性頁,選取檔案安全性標籤,點閱匿名訪問和身份驗證控制的「編輯」按鈕。

解決此問題有兩個方法,一是不要選中匿名訪問並且選中整合 Windows 身份驗證,二是選中匿名訪問並編輯匿名訪問使用的帳戶,改成一個有權限的。

10. 我的 PHP 腳本在 IE 和 Lynx 下能工作,但是在 Netscape 中有的輸出丟失了。當我用「檢視源檔案」時可以在 IE 中看到內容,但是 Netscape 中不能。

Netscape 在關於 HTML 旗標(例如 table)上比 IE 更嚴格。用一個 HTML 驗證器,例如 validator.w3.org 來驗證你的 HTML 輸出可能會有說明。例如漏了 </table> 可能會導致這樣的結果。

同樣,IE 和 Lynx 都忽略了 HTML 流中的任何 NULs(\0),Netscape 就不。最好的檢查方法是編譯 PHP 的指令行模式版本(也稱為 CGI 版本)並從指令行運行你的腳本。在 *nix 中,用管道傳遞到 od -c 並檢視任何 \0 字元。若果在 Windows 下你需要能夠檢視二進位檔案格式的編輯器或程式。當 Netscape 碰到 NUL 時就不會輸出之後該行的任何內容而 IE 和 Lynx 都會。

11. 我怎樣混合使用 XML 和 PHP?它不認我的 <?xml 旗標!

要能夠在 PHP 代碼中直接內嵌 <?xml,需要將 PHP 設定項 short_open_tags 設定為 0 以關閉短旗標格式。無法通過函數 ini_set() 來變更這項設定。不管 short_open_tags 是開或是關,都可以用類似於 <?php echo '<?xml'; ?> 的方法達到目的。該項設定的預設值為開。

12. 怎樣用 FrontPage 或是其它非要把我的代碼移來移去的 HTML 編輯器來編輯 PHP?

最簡單的方法是讓 PHP 代碼也能使用 ASP 旗標。這可以讓你用 ASP 風格的 <% 和 %> 代碼定界符。一些流行的 HTML 編輯器在處理此格式上更加智慧化一些(目前如此)。要使用 ASP 風格的旗標,需要在 php.ini 中開啟 asp_tags,或是用相應的 Apache 配置選項。

13. 哪裡可以找到所有可用的 PHP 預定義變量的完整清單?

請閱讀手冊中的預定義變量一章,該部分的文件已經包括了一部分可以用於你的腳本的預定義變量的清單。可用變量的完整清單(及更多訊息)可以通過呼叫 phpinfo() 函數來查閱。請務必閱讀手冊中來自 PHP 之外的變量一節,這部分文件闡述了外部變量的概念,例如來自 HTML 表單、Cookie 和 URL 的變量。

register_globals 重要說明: 自 PHP 4.2.0 起,PHP 中的選項 register_globals 的預設值被設為 off。PHP 社區鼓勵大家不要依賴於這個選項,用其它方法替代,例如superglobals

14. 怎樣才能不用非免費的商業庫 ClibPDFPDFLib 來建立 PDF 文件?我想要個免費的並且不需要再連線別的 PDF 庫。

15. 我試著在會員自訂函數中訪問一個標準的 CGI 變量(例如 $DOCUMENT_ROOT 或 $HTTP_REFERER),但是找不到,哪裡出了錯?

首先非常重要的一點是 PHP 設定項 register_globals 同樣會對伺服器端和環境變量產生影響。當 register_globals = off (從 PHP 4.2.0 開始其預設值為 off),變量 $DOCUMENT_ROOT 將不會存在,而只有 $_SERVER['DOCUMENT_ROOT']。若果 register_globals = on 則變量 $DOCUMENT_ROOT$GLOBALS['DOCUMENT_ROOT'] 將同時存在。

若果確認 register_globals = on 但不知道為什麼 $DOCUMENT_ROOT 在函數內定不可用,這是因為它和其它的變量一樣需要在函數中執行 global $DOCUMENT_ROOT。請參閱手冊中的變量範圍一節。建議在 register_globals = off 的情況下進行編碼。

Superglobals 可用性說明: 自 PHP 4.1.0 起,可以使用超全局陣列變量例如 $_GET$_POST$_SERVER 等等。更多訊息請閱讀手冊中的 superglobals

16. 有些 PHP 選項可以接受縮寫的位元組值,與僅能接受 integer 位元組值相反。都有哪些縮寫位元組值?可以將其用於 php.ini 之外嗎?

可用的選取有 K(對應 Kilobytes),M(對應 Megabytes)和 G(對應 Gigabytes;自 PHP 5.1.0 起可用),區分大小寫。其餘的都認為是位元組。1M 等於一個 Megabyte,即 1048576 位元組。1K 等於一個 Kilobyte,即 1024 位元組。不能在 php.ini 之外使用這些符號,最好用整數的 integer 位元組值。參見 ini_get() 文件中的轉換示例。