登入
首頁 所有文章 PHP PHP輸出緩衝與header函式
長也   2018-05-20 20:23:10(1年前)    560點閱   0喜歡  0收藏
PHP輸出緩衝與header函式  

此次升級PHP7遇到一個問題,header()函數沒辦法正常運作,被報錯以下訊息:

PHP Warning: Cannot modify header information - headers already sent by (output started at /xxx/xxx/xxx.php:3) in /xxx/xxx/xxx.php on line 4

這項錯誤是說header已經發送,無法再更改,為何會這樣?本文在此討論。

PHP的輸出緩衝機制

在PHP當中具有一個輸出緩衝的機制,可使即將被echo、print的文字被儲存在PHP的緩衝區中,而不會直接傳給瀏覽器,這種機制的設定方式有兩種:一是由php.ini當中的output_buffering來設定,預設是4096KB;二是由PHP內建函式來設定,如ob_start()等函數,下方整理成表:

函數

功能

ob_start()

打開緩衝區

ob_clean()

清空緩衝區但不回傳

ob_get_contents()

回傳緩衝區內容

ob_end_flush()

ob_get_clean()

回傳並清除緩衝區

這兩者最大的差異就是若由php.ini設定是固定大小,而ob_start()會提供足夠大小的緩衝區。

header與緩衝區關係之分析

知道緩衝區的設定方式後,我們來看一些簡單的例子,這兩個例子都在header前先輸出了30次的"Header ERROR"字串

echo str_repeat("Header ERROR",30);
header("Location: /");

一般在html文件當中,header前並不會有任何的輸出,所以在PHP的header函式中也不允許header前有輸出,但是這段代碼在一些主機上是可以正常運作,但是某些主機會被報錯,通常就是本文一開始的錯誤訊息。

ob_end_flush();
echo str_repeat("Header ERROR",30);
header("Location: /");

但是這一段程式碼呢?應該是沒辦法正常運作的,最大的差異就是第一行我們調用了ob_end_flush()函式,功能就是表格整理的"回傳並清除緩衝區",這樣就能清楚知道問題在於"緩衝區"。

PHP當中的header

請注意,在PHP當中的header並不會經過緩衝區,會直接被發送給瀏覽器。

header前不能有輸出

前面提到的HTML中header前並不會有輸出,是因為header標籤是為了聲明我們的網站所要呈現的內容,因此不能在聲明前就輸出任何內容,這樣不符合http的規範。

Cannot modify header information之錯誤解釋

上面的範例當中,因為第一個範例並沒有提前關閉緩衝區,因此echo會進入緩衝當中header就會先被發送,所以在預設啟用緩衝的主機上可以正常運作;但是在第二個範例中,因為清除且輸出緩衝區,因此echo會先被輸出,這樣就造成了"header前有輸出"的情況而無法發送header。

結論

如果無法確認使用header()函式前的輸出可以被緩衝區容納,最好把header()寫在最前端,避免錯誤。

參考資料

php緩衝區與header函數之間的秘密 - 簡書

本文作者:長也

糾結與想不開的資管系學生,之前常碰PHP,現在常碰到的是Python,閒暇之餘就記錄一些筆記。

             

如要發表回覆,請先 登入

  0則回覆