章 50. 使用 PHP

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

1. 我想寫一個可以處理任何表單來的資料的通用 PHP 腳本。我怎麼知道哪個 POST 方法變數可用呢?
2. 我需要把所有的單引號(')轉換為反斜線後面跟著單引號。怎樣用正則表達式做到呢?
3. 當我這樣做時,輸出顯示的次序是錯的:
function myfunc($argument)
{
    echo $argument + 10;
}
$variable = 10;
echo "myfunc($variable) = " . myfunc($variable);
這是怎麼回事?
4. 下面代碼怎麼沒有分成兩行顯示?
<pre>
<?php echo "This should be the first line."; ?>
<?php echo "This should show up after the new line above."; ?>
</pre>
5. 我得到消息“Warning: Cannot send session cookie - headers already sent...”或者“Cannot add header information - headers already sent...”。
6. 我需要直接連接請求報頭中的訊息,怎麼能辦到?
7. 當我用 IIS 進行 HTTP 認証時得到“No Input file specified”消息。
8. 我的 PHP 腳本在 IE 和 Lynx 下能工作,但是在 Netscape 中有的輸出丟失了。當我用“查看源文件”時可以在 IE 中看到內容,但是 Netscape 中不能。
9. 我怎樣混合使用 XML 和 PHP?它不認我的 <?xml> 標記!
10. 怎樣用 FrontPage 或者其它非要把我的代碼移來移去的 HTML 編輯器來編輯 PHP?
11. 哪裡可以找到所有可用的預定義變數的完整列表?為什麼在 PHP 文檔中沒有?
12. 我試著在用戶自定義函式中連接一個標準的 CGI 變數(例如 $DOCUMENT_ROOT 或 $HTTP_REFERER),但是找不到,哪裡出了錯?

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

確保在 php.ini 文件中啟動了 track_vars 特性。自從 PHP 4.0.3 開始,此特性總是打開的。當 track_vars 打開時,會建立一些相關的陣列,這裡最重要的是:$_POST(在 PHP 4.1.0 之前叫做 $HTTP_POST_VARS)。因此要寫出處理 POST 方法變數的通用腳本你需要一些類似如下的方法:
foreach ($_POST as $var => $value) {
    echo "$var = $value<br>\n";
}

2. 我需要把所有的單引號(')轉換為反斜線後面跟著單引號。怎樣用正則表達式做到呢?

首先看看 addslashes() 函式。它正是做這件事的。同樣也看看你的 php.ini 文件中的 magic_quotes_gpc 選項。

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

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

4. 下面代碼怎麼沒有分成兩行顯示?
<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 頁面的源文件的格式很難讀。

5. 我得到消息“Warning: Cannot send session cookie - headers already sent...”或者“Cannot add header information - headers already sent...”。

函式 header()setcookie() 和 session 函式需要在輸出流中增加報頭。但是報頭只能在其它任何輸出內容之前發送,檢查你的代碼是否在任何已經發送的內容後面發送報頭。

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

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

7. 當我用 IIS 進行 HTTP 認証時得到“No Input file specified”消息。

IIS 的安全模型這裡有毛病。這是所有 IIS 下執行的 CGI 程序所共有的問題。一個解決辦法是建立一個純 HTML 文件(不經過 PHP 解析)作為要進入認証目錄的登錄頁面,然後用 META 標記來重定向到 PHP 頁面,或者用一個連接到 PHP 頁面。然後 PHP 就可以正確識別認証訊息了。如果是用 ISAPI 模塊,那沒有這個問題。其它 NT 下的 web 伺服器不受此影響。更多訊息見:http://support.microsoft.com/support/kb/articles/q160/4/22.asp

8. 我的 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 都會。

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

你需要在 php.ini 文件中通過設定 short_tags 為 0 來關閉 PHP 的簡短標記格式,或者通過相應的 Apache 選項。你甚至應該用 <File> 段落來選擇性地這樣做。

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

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

11. 哪裡可以找到所有可用的預定義變數的完整列表?為什麼在 PHP 文檔中沒有?

最好的方法是把 <?php phpinfo(); ?> 粘貼到某一頁並打開來看看。它將顯示你的 PHP 的所有分類的設置,包括環境變數和 web 伺服器設定的特殊變數的列表。這個列表不能放在 PHP 文檔中,因為它在不同的伺服器中會改變的。

12. 我試著在用戶自定義函式中連接一個標準的 CGI 變數(例如 $DOCUMENT_ROOT 或 $HTTP_REFERER),但是找不到,哪裡出了錯?

環境變數通常都是全域變數,因此你必須在你的函式中聲明它們為全域變數(例如用 global $DOCUMENT_ROOT;),或者用全域變數陣列(例如 $GLOBALS["DOCUMENT_ROOT"])。