2017-03-16 55 views
7

我間歇性地得到這個問題在我的PHP腳本(PHP 5.6,Apache 2.2的):PHP 5.6:headers_sent間歇返回true,空文件名和行0

警告:無法修改標題信息 - 頭已經在/path/to/index.php發送上線55

此警告沒有,我在這個其他問題已經看到了部分「由派」,所以我只是說這個代碼在違規之前header()setcookie()來電:

if (headers_sent($filename, $linenum)){ 
    echo("Output buffer: #" . ob_get_contents() . "#"); 
    echo "Headers already sent in $filename on line $linenum: "; 
    print_r(headers_list()); 
} 

這裏發生了問題,當我得到的輸出:

Output buffer: ## 
Headers already sent in on line 0: 
Array (
    [0] => X-Powered-By: PHP/5.6.23 
    [1] => Content-type: text/html; charset=UTF-8 
) 

(附註:我已經output_buffering設置在php.ini 4096個字節,所以不應該在這兩個標題中的63個字符緩衝並且等待更多,而不是被過早發送?)

這個問題出現在我首次啓動一個包含Web服務器的Docker容器。之後,只有(但不是總是)在我第一次訪問我的網站(可能是一兩個小時)時發生,當我撥打header()setcookie()來登錄用戶或重定向到登錄頁。

我看了又看this answer誤差一般「已經發送了頭」,並且,盡我的能力,我已經排除了這些可能的原因:

  1. HTML塊或來電printecho,等我之前我的PHP代碼之外調用setcookie()header()
  2. 空白
  3. 的BOM
  4. auto_prepend_file php.ini中設置
  5. gzip流編碼 - zlib的安裝,但zlib.output_compression是關
  6. 重複extension= php.ini設置

這個答案提到

這是典型的PHP擴展或php.ini中設置,如果沒有錯誤來源具體化。

所以,我現在希望通過我的擴展... get_loaded_extensions給了我這些條目51長度的數組:

Core, date, ereg, libxml, openssl, 
pcre, zlib, filter, hash, Reflection, 
SPL, session, standard, apache2handler, bz2, 
calendar, ctype, curl, dom, exif, 
fileinfo, ftp, gd, gettext, iconv, 
mysqlnd, PDO, Phar, posix, shmop, 
SimpleXML, snmp, soap, sockets, sqlite3, 
sysvmsg, sysvsem, sysvshm, tokenizer, xml, 
xmlwriter, xsl, mysql, mysqli, pdo_mysql, 
pdo_sqlite, wddx, xmlreader, json, zip, mhash 
我不使用所有這些

,所以我打算去通過並刪除未使用的,並希望其中一個導致這個問題。

最糟糕的情況下,我會嘗試碰撞我的output_buffering值或使用ob_start()ob_end_flush()來開始和結束我的文件。我不知道爲什麼這會解決它,當我目前的output_buffering價值4096沒有,我明白,這個解決方法帶來了自己的問題。

我在這裏錯過了什麼 - 是否有其他可能的原因,我需要檢查?我應該嘗試不同的PHP版本,或者在沒有擴展名的純PHP安裝中運行我的代碼的子集?

編輯:添加了ob_get_contents()調用和輸出,以及有關能夠通過旋轉新的Docker容器來持續複製此信息的信息。刪除了有關我的error_reporting值的信息;更改此僅揭示了always_populate_raw_post_data棄用通知,修復對此處描述的問題沒有影響。

+1

請提供您設置的完整PHP文件代碼並檢查裏面的標題。我想這是一個'index.php'?如果包含,則請提供包括索引文件在內的整個包含鏈源。 –

+1

您是否在入口點腳本的開頭調用'ob_start()'?這從你的問題不清楚,但沒有'ob_get_contents()'不會工作。另外,嘗試使用'var_dump(ob_get_contents())'。我認爲這比直接回顯值更好,因爲它會說明字符串的長度。 –

+0

你是怎麼確定修復'always_populate_raw_post_data'這個東西不能解決問題的?這當然是一個原因。另一個說明 - 查看成功加載的擴展將無濟於事;很可能會引發相反的錯誤 - 失敗*來加載擴展。如果它表示第0行,那麼可以確定它與代碼無關,但在PHP本身初始化時會觸發某些事件。 – Narf

回答

1

在取出一些未使用的遺留代碼(包括require_once調用到所有遺留代碼的文件)後,此問題不再發生。它可能在我最初觀察到的「間歇性」條件下復發,但是我的再現方法不再出現這個問題。

我不知道爲什麼這似乎有所幫助 - 刪除的行完全位於<php? ?>標籤內,我檢查刪除的文件中標籤,BOM和CRLF外部的空白。

我也不知道爲什麼這個問題是間歇性的;如果它與刪除的代碼或文件有關,它應該每次都發生。

感謝所有的意見和答案!

1

我已經看到由於過去的行結束格式而出現問題。你是否將文件從一個操作系統環境移動到另一個?

有時隱藏的回車符(/ r)或其他特殊的空白字符可能會導致這種情況,但在文件中不可見。

+0

感謝您的提示;我正在將文件從Windows移動到PHP並返回。然而,我沒有找到任何使用這裏描述的幾種方法的CRLF:http://stackoverflow.com/q/73833/877682 – Aaron

1

它可以是UTF8 BOM字符,或錯誤的換行符,不可打印的字符,錯誤的PHP關閉標籤(我不使用它們,以防止endline問題)。即使沒有這樣的問題,即使你想盡一切辦法來阻止它,它也可以(也將會)在以後發生。問題可能出在FTP服務器,文本編輯器,錯誤的PHP配置,編碼,錯誤的cgi配置上。爲了避免所有這些我用空的輸出緩衝區,剛開始在第一個PHP文件

的index.php buffreing:

if(version_compare(PHP_VERSION, '7.0.0') >= 0 || ob_get_level() < 1) 
    ob_start(); 

HtmlResponce.php:

ob_end_clean(); 
echo $this->getRenderedContent(); 

FileResponce.php:

ob_end_clean(); 
readfile($this->content); 

在php5和php7中輸出緩衝有幾點區別,也可以輸出緩衝可以配置在php.ini中有所不同,並且在cgi和apache mod配置上有所不同。你不應該繼續「默認」配置。要處理警告消息,請使用set_error_handler(),如果您開始新項目時看到symfony components,我在CMS中使用了很多這些消息。這是您有機會通過奇怪的PHP錯誤防止不眠之夜。

+0

正如我的回答中所提到的,我排除了你所描述的常見問題(盡我所能),我想盡可能避免使用'ob_start',因爲性能原因。感謝您的建議;當我開始一個新的PHP項目時,我一定會檢查一下symfony組件。 – Aaron

+1

在這種情況下沒有性能鬆動。輸出前緩衝器關閉。沒有雙緩衝 - 不增加內存使用。 –

+0

經過一番研究之後,我認爲輸出緩衝與性能優勢相關是錯誤的。對於巨大的輸出(比如超過200KB)來說這是一個壞主意,但這不適用於我的情況。謝謝你讓我變直! – Aaron