在執行我的腳本時,我收到幾個如下錯誤:
警告:無法修改標頭資訊- 標頭已由/some/file.php 中的(輸出從/some/file.php:12 開始)發送<第23行<第23行
錯誤訊息中提到的行包含 header()
和 setcookie()
呼叫。
這可能是什麼原因?又該如何解決呢?
P粉0716024062023-10-10 11:29:08
在傳送 HTTP 標頭之前發送任何內容(使用 setcookie
或 header
)。在 HTTP 標頭之前輸出某些內容的常見原因是:
意外的空格,通常出現在檔案的開頭或結尾,如下所示:
為了避免這種情況,而省略結尾的 ?>
- 無論如何都不需要。
3F 3C
開頭。您可以安全地從檔案開頭刪除 BOM EF BB BF
。 echo
、printf
、readfile
、passthru
、 之前的程式碼>
等display_errors
php.ini屬性已設定。 php 不會因程式設計師錯誤而崩潰,而是默默地修復錯誤並發出警告。雖然您可以修改 display_errors
或 error_reporting 配置,您應該解決問題。 $_POST['input']
而不使用empty
## 或isset
進行測試是否設定了輸入),或使用未定義的常數而不是字串文字(如$_POST[input] 中,請注意缺少的引號)。
輸出緩衝應該可以解決問題;呼叫ob_start 後的所有輸出都緩衝在記憶體中,直到您釋放緩衝區,例如與ob_end_flush
。
P粉0879514422023-10-10 09:54:05
在進行任何輸出之前,必須呼叫發送/修改 HTTP 標頭的函數。 摘要⇊# 否則呼叫失敗:
修改 HTTP 標頭的一些函數是:
輸出可以是:
無意:
# 之前或 ?>
之後的空格
故意:
#print
、echo
和其他產生輸出的函數 程式碼之前的原始
部分。
要理解為什麼必須在輸出之前發送標頭,這是必要的 查看典型的 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-8PHP page output page Content
Some more output follows...
and
頁面/輸出總是跟隨標題。 PHP 必須透過 首先將標頭髮送到網頁伺服器。它只能這樣做一次。 雙換行之後就再也不能修改它們了。
當 PHP 收到第一個輸出(print
、echo
、)時,它將
刷新所有收集的標頭。之後它可以發送所有輸出
它想要。但是發送進一步的 HTTP 標頭是不可能的。
header()
警告包含所有相關資訊
定位問題原因:
此處「第 100 行」指的是 header()
呼叫 失敗的腳本。
括號內的「輸出開始於」註解更為重要。
它表示先前輸出的來源。在此範例中,它是 auth.php
#
和第52
#行。這就是您必須尋找過早輸出的地方。
典型原因:
print
和 echo
語句的有意輸出將終止發送 HTTP 標頭的機會。必須重組應用程式流程以避免這種情況。使用函數
和模板方案。確保 header()
呼叫發生在訊息之前
都寫出來了。
產生輸出的函數包括
列印
、echo
、printf
、vprintf
#trigger_error
、ob_flush
、ob_end_flush
、var_dump
、print_r
readfile
、passthru
、flush
、imagepng
、imagejpeg
以及其他和使用者定義的函數。
.php 檔案中未解析的 HTML 部分也是直接輸出。
必須注意將觸發 header()
呼叫的腳本條件
在任何原始區塊之前。
使用模板方案將處理與輸出邏輯分開。
之前的空格表示「script.php 第 1 行」警告
#如果警告引用內聯輸出1
,那麼主要是
開頭 標記之前的前導空格、文字或 HTML。
類似地,附加腳本或腳本部分也可能發生這種情況:
?>PHP 實際上會在關閉標籤後佔用一個單一換行符號。但它不會 補償移入此類間隙的多個換行符、製表符或空格。
##僅換行符和空格就可能是一個問題。但也有“看不見的”
可能導致這種情況的字元序列。最著名的是
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
在整個包含或專案目錄上使用是安全的。
後面有空格? >
如果後面提到了錯誤來源
關閉 ?>
#
那麼這就是一些空白或原始文本被寫出的地方。
PHP 結束標記此時不會終止腳本執行。其後的任何文字/空格字元都會作為頁面內容寫出
仍然。
通常建議,特別是對於新手,尾隨 ?>
PHP
應省略關閉標籤。這避開了這些案例中的一小部分。
(很常見 include()d
腳本是罪魁禍首。)
如果沒有錯誤來源,通常是 PHP 擴充或 php.ini 設定 具體化了。
gzip
流編碼設定
或 ob_gzhandler
。 extension=
模組
產生隱式 PHP 啟動/警告訊息。 如果另一個 PHP 語句或表達式導致警告訊息或 注意被印出來,這也算是過早輸出。
在這種情況下,您需要避免錯誤,
延遲語句執行,或使用例如抑制訊息
isset()
或 @()
# -
當任何一個都不會妨礙稍後的調試時。
如果您根據 php.ini
停用了 error_reporting
或 display_errors
,
那就不會出現任何警告。但忽略錯誤並不能解決問題
離開。過早輸出後仍然無法發送標頭。
因此,當 header("Location: ...")
重定向默默失敗時,這是非常嚴重的
建議探測警告。使用兩個簡單的命令重新啟用它們
在呼叫腳本之上:
error_reporting(E_ALL); ini_set("display_errors", 1);
或set_error_handler("var_dump");
如果其他方法都失敗了。
說到重定向標頭,您應該經常使用這樣的習慣用法 這是最終的程式碼路徑:
exit(header("Location: /finished.html"));
最好是一個列印用戶訊息的實用函數
如果 header()
失敗。
PHP 輸出緩衝 是緩解此問題的解決方法。它通常工作可靠,但不應該 取代正確的應用程式結構並將輸出與控制分開 邏輯。它的實際目的是最大限度地減少到網路伺服器的分塊傳輸。
output_buffering=
#
不過,設定還是有幫助的。
在 php.ini 中配置它
或透過 .htaccess
甚至 .user.ini
現代 FPM/FastCGI 設定。
啟用它將允許 PHP 緩衝輸出,而不是立即將其傳遞到網頁伺服器。 PHP 因此可以聚合 HTTP 標頭。
它同樣可以透過呼叫 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。
大多數瀏覽器仍然接受它。
作為替代方案,JavaScript 重定向 可用於頁面重定向:
sssccc
雖然這通常比 解決方法更符合 HTML,
它會導致對支援 JavaScript 的客戶端的依賴。
然而,當真正的 HTTP header() 時,這兩種方法都會產生可接受的後備 呼叫失敗。理想情況下,您總是將其與用戶友好的訊息結合起來, 作為最後手段的可點擊連結。 (例如,http_redirect() PECL 擴充確實如此。 )
setcookie()
和session_start()
也受到影響setcookie()
和 session_start()
都需要傳送 Set-Cookie:
HTTP 標頭。
因此,適用相同的條件,並將產生類似的錯誤訊息
用於過早輸出的情況。
(當然,它們也受到瀏覽器中禁用 cookie 的影響 甚至代理問題。會話功能顯然也依賴免費 磁碟空間和其他 php.ini 設定等)