解決PHP中的「Headers already sent」錯誤的方法
P粉210405394
P粉210405394 2023-10-09 21:06:28
0
2
556

在執行我的腳本時,我收到幾個如下錯誤:

警告:無法修改標頭資訊- 標頭已由/some/file.php 中的(輸出從/some/file.php:12 開始)發送<第23行<第23行

錯誤訊息中提到的行包含 header()setcookie() 呼叫。

這可能是什麼原因?又該如何解決呢?

P粉210405394
P粉210405394

全部回覆(2)
P粉071602406

在傳送 HTTP 標頭之前發送任何內容(使用 setcookieheader)。在 HTTP 標頭之前輸出某些內容的常見原因是:

  • 意外的空格,通常出現在檔案的開頭或結尾,如下所示:

       為了避免這種情況,而省略結尾的 ?> - 無論如何都不需要。

開啟

輸出緩衝應該可以解決問題;呼叫ob_start 後的所有輸出都緩衝在記憶體中,直到您釋放緩衝區,例如與ob_end_flush

然而,雖然輸出緩衝可以避免這些問題,但您應該真正確定應用程式在 HTTP 標頭之前輸出 HTTP 正文的原因。這就像接電話並討論你的一天和天氣,然後告訴打電話的人他撥錯了號碼。

P粉087951442

發送標頭之前沒有輸出!

在進行任何輸出之前,必須呼叫發送/修改 HTTP 標頭的函數摘要⇊# 否則呼叫失敗:

修改 HTTP 標頭的一些函數是:

輸出可以是:

  • 故意:

    • #printecho 和其他產生輸出的函數
    • 程式碼之前的原始 部分。

為什麼會發生這種情況?

要理解為什麼必須在輸出之前發送標頭,這是必要的 查看典型的 HTTP 回覆. PHP腳本主要產生HTML內容,同時也傳遞一個 傳送到網頁伺服器的 HTTP/CGI 標頭集:

HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

PHP page output page

Content

Some more output follows...

and

頁面/輸出總是跟隨標題。 PHP 必須透過 首先將標頭髮送到網頁伺服器。它只能這樣做一次。 雙換行之後就再也不能修改它們了。

當 PHP 收到第一個輸出(printecho)時,它將 刷新所有收集的標頭。之後它可以發送所有輸出 它想要。但是發送進一步的 HTTP 標頭是不可能的。

如何找出過早輸出發生的位置?

header() 警告包含所有相關資訊 定位問題原因:

此處「第 100 行」指的是 header() 呼叫 失敗的腳本。

括號內的「輸出開始於」註解更為重要。 它表示先前輸出的來源。在此範例中,它是 auth.php# 和52#行。這就是您必須尋找過早輸出的地方。

典型原因:

  1. #列印、回顯

    printecho 語句的有意輸出將終止發送 HTTP 標頭的機會。必須重組應用程式流程以避免這種情況。使用函數 和模板方案。確保 header() 呼叫發生在訊息之前 都寫出來了。

    產生輸出的函數包括

    • 列印echoprintfvprintf
    • #trigger_errorob_flushob_end_flushvar_dumpprint_r
    • readfilepassthruflushimagepngimagejpeg


    以及其他和使用者定義的函數。

  2. 原始 HTML 區域

    .php 檔案中未解析的 HTML 部分也是直接輸出。 必須注意將觸發 header() 呼叫的腳本條件 在任何原始區塊之前。

    
    

    使用模板方案將處理與輸出邏輯分開。

    • 將表單處理程式碼置於腳本之上。
    • 使用臨時字串變數來延遲訊息。
    • 實際的輸出邏輯和混合的 HTML 輸出應該放在最後。

  3. 之前的空格表示「script.php 第 1 行」警告

    #如果警告引用內聯輸出1,那麼主要是 開頭 標記之前的前導空格、文字或 HTML。

    
    

    類似地,附加腳本或腳本部分也可能發生這種情況:

    ?>
    
    
    

    PHP 實際上會在關閉標籤後佔用一個單一換行符號。但它不會 補償移入此類間隙的多個換行符、製表符或空格。

  4. UTF-8 BOM

    ##僅換行符和空格就可能是一個問題。但也有“看不見的” 可能導致這種情況的字元序列。最著名的是 UTF-8 BOM(位元組順序標記) 大多數文字編輯器不會顯示它。它是一個位元組序列 EF BB BF,對於 UTF-8 編碼的文檔來說,它是可選且冗餘的。然而 PHP 必須將其視為原始輸出。它可能在輸出中顯示為字元  (如果客戶端將文件解釋為 Latin-1)或類似的「垃圾」。

    特別是圖形編輯器和基於 Java 的 IDE 並沒有註意到它 在場。他們沒有將其視覺化(Unicode 標準規定)。 然而,大多數程式設計師和控制台編輯器都會:

    這樣很容易儘早發現問題。其他編輯可能會識別 它存在於檔案/設定選單中(Windows 上的 Notepad 可以識別並 解決問題), 檢查 BOM 存在的另一個選擇是使用十六進位編輯器。 在 *nix 系統上 hexdump 通常可用, 如果不是簡化審核這些問題和其他問題的圖形變體:

    一個簡單的解決方法是將文字編輯器設定為將檔案儲存為“UTF-8(無 BOM)” 或類似這樣的命名法。通常,新手會求助於建立新文件,然後將先前的程式碼複製並貼上回來。

    修正實用程式

    還有自動化工具來檢查和重寫文字文件 (sed/awk代码>重新編碼)。 對於 PHP,特別是 phptags 標記 tidier。 它將關閉和打開標籤重寫為長和短形式,而且也很容易 修正了前導和尾隨空格、Unicode 和 UTF-x BOM 問題:

    phptags  --whitespace  *.php

    在整個包含或專案目錄上使用是安全的。

  5. 後面有空格? >

    如果後面提到了錯誤來源 關閉 ?># 那麼這就是一些空白或原始文本被寫出的地方。 PHP 結束標記此時不會終止腳本執行。其後的任何文字/空格字元都會作為頁面內容寫出 仍然。

    通常建議,特別是對於新手,尾隨 ?> PHP 應省略關閉標籤。這避開了這些案例中的一小部分。 (很常見 include()d 腳本是罪魁禍首。)

  6. 錯誤來源稱為「第 0 行未知」

    如果沒有錯誤來源,通常是 PHP 擴充或 php.ini 設定 具體化了。

    • 有時是 gzip 流編碼設定 ob_gzhandler
    • 但它也可以是任何雙重載入的 extension= 模組 產生隱式 PHP 啟動/警告訊息。

  7. 前面的錯誤訊息

    如果另一個 PHP 語句或表達式導致警告訊息或 注意被印出來,這也算是過早輸出。

    在這種情況下,您需要避免錯誤, 延遲語句執行,或使用例如抑制訊息 isset()@()# - 當任何一個都不會妨礙稍後的調試時。

沒有錯誤訊息

如果您根據 php.ini 停用了 error_reportingdisplay_errors, 那就不會出現任何警告。但忽略錯誤並不能解決問題 離開。過早輸出後仍然無法發送標頭。

因此,當 header("Location: ...") 重定向默默失敗時,這是非常嚴重的 建議探測警告。使用兩個簡單的命令重新啟用它們 在呼叫腳本之上:

error_reporting(E_ALL);
ini_set("display_errors", 1);

set_error_handler("var_dump");如果其他方法都失敗了。

說到重定向標頭,您應該經常使用這樣的習慣用法 這是最終的程式碼路徑:

exit(header("Location: /finished.html"));

最好是一個列印用戶訊息的實用函數 如果 header() 失敗。

輸出緩衝作為解決方法

PHP 輸出緩衝 是緩解此問題的解決方法。它通常工作可靠,但不應該 取代正確的應用程式結構並將輸出與控制分開 邏輯。它的實際目的是最大限度地減少到網路伺服器的分塊傳輸。

  1. output_buffering=# 不過,設定還是有幫助的。 在 php.ini 中配置它 或透過 .htaccess 甚至 .user.ini 現代 FPM/FastCGI 設定。
    啟用它將允許 PHP 緩衝輸出,而不是立即將其傳遞到網頁伺服器。 PHP 因此可以聚合 HTTP 標頭。

  2. 它同樣可以透過呼叫 ob_start(); 在呼叫腳本之上。然而,由於多種原因,它不太可靠:

    • 即使 開始第一個腳本,空格或 BOM 可能會在渲染之前被打亂無效

    • 它可以隱藏 HTML 輸出的空白。但是,一旦應用程式邏輯嘗試發送二進位內容(例如生成的圖像), 緩衝的無關輸出成為一個問題。 (需要ob_clean()) 作為進一步的解決方法。 )

    • 緩衝區的大小有限,如果保留預設值,很容易溢位。 這種情況也不少見,很難追蹤一个> 當它發生時。

因此,這兩種方法都可能變得不可靠 - 特別是在兩者之間切換時 開發設定和/或生產伺服器。這就是為什麼輸出緩衝是 廣泛認為只是一個拐杖/嚴格來說是一種解決方法。

另請參閱基本用法範例 在手冊中,以及更多優點和缺點:

但它在其他伺服器上工作! ?

如果您之前沒有收到標頭警告,則輸出緩衝 php.ini 設定 已經改變。當前/新伺服器上可能未配置它。

使用headers_sent()檢查

您總是可以使用 headers_sent() 來偵測是否 仍然可以...發送標頭。這對於有條件列印很有用 資訊或應用其他後備邏輯。

if (headers_sent()) {
    die("Redirect failed. Please click on this link: ");
}
else{
    exit(header("Location: /user.php"));
}

有用的後備解決方法是:

  • HTML 標籤

    如果您的應用程式在結構上很難修復,那麼一個簡單的(但 有點不專業)允許重定向的方法是注入 HTML 標籤。可以透過以下方式實現重定向:

    或短暫延遲:

    當使用超過 部分時,這會導致無效的 HTML。 大多數瀏覽器仍然接受它。

  • JavaScript 重定向

    作為替代方案,JavaScript 重定向 可用於頁面重定向:

    sssccc

    雖然這通常比 解決方法更符合 HTML, 它會導致對支援 JavaScript 的客戶端的依賴。

然而,當真正的 HTTP header() 時,這兩種方法都會產生可接受的後備 呼叫失敗。理想情況下,您總是將其與用戶友好的訊息結合起來, 作為最後手段的可點擊連結。 (例如,http_redirect() PECL 擴充確實如此。 )

為什麼setcookie()session_start()也受到影響

setcookie()session_start() 都需要傳送 Set-Cookie: HTTP 標頭。 因此,適用相同的條件,並將產生類似的錯誤訊息 用於過早輸出的情況。

(當然,它們也受到瀏覽器中禁用 cookie 的影響 甚至代理問題。會話功能顯然也依賴免費 磁碟空間和其他 php.ini 設定等)

更多連結

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板