用PHP開發程序時,如果服務器出現500的時候(有時甚至不報錯直接顯示空白),如果無法知道究竟是什么原因,就無法進行調試。
要讓PHP顯示錯誤信息,可以從PHP配置文件 (php.ini)或PHP程序文件入手,另外,如果與IIS整合的時候,還必須考慮web.config文件。
如果是與IIS整合的方式,則需要修改web.config文件,對其中的<system.webServer>項添加<httpErros>條目:
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
</system.webServer>
php.ini配置文件中涉及的修改:
注意修改完配置文件后需要重啟web服務器(如果是IIS,可以通過IIS管理器中的“FastCgi設置”監聽php.ini的更改,這樣可以不用重啟)。
1、error_reporting = E_ALL
error_reporting 意思是“錯誤-報告形式”,指定了出錯時是否顯示到瀏覽器與記錄到日志文件的方式。
設置錯誤記錄的級別,E_ALL為報告所有 PHP 錯誤,通常在調試錯誤的時候設置為此(也可以設置為-1或E_ALL^警告過期等)。
生產環境為了安全問題,建議設置為0。
error_reporting的默認值為 E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED(PHP5.5.16版,其他版本可能各不同)
其它常見的值為:E_WARNING,E_NOTICE,E_DEPRECATED,這些通常作為排除形式,在非調試情況下與E_ALL搭配使用,比如:
E_ALL ^ E_DEPRECATED -報告所有錯誤但不報告過期(或即將過期)的提示,通常用於舊程序上使用了即將過期方法產生錯誤時,比如使用了mysql_connect導致過期錯誤500。
E_ALL ^ E_NOTICE -報告所有錯誤但不報告警告,通常可以解決Undefined Index或Undefined Variable等提示。
如果error_reporting=0,代表着不顯示、不記錄任何錯誤。
如果error_reporting=E_ALL排除某些形式時,代表着顯示、記錄所有出錯信息,但不顯示、不記錄這些排除了的。
不想顯示出錯信息,在程序中使用了ini_set("error_reporting",0),但仍然顯示出錯信息的情況:
出現解析錯誤(語法問題),此時會導致php.ini中的優化級高於PHP源文件各項,所以如果php.ini中的error_reporting=On,則仍然會報錯。
2、display_errors = On
display_errors 名如其義,“顯示-出錯信息”,它針對的是輸出端(這里是瀏覽器)的顯示與否。
設置為On時,將會對error_reporting所設置的相應級別的出錯信息,顯示到瀏覽器上
(但瀏覽器顯示出錯的信息是否真的來源於它,還需要考慮log_errors與error_log,見后邊)。
設置為Off時,將不輸出相應出錯信息到瀏覽器
(但瀏覽器是否絕對不輸出出錯信息,在error_reporting為On時,還需要考慮log_errors與error_log,見后邊)
display_errors受到error_reporting的限制:
如果error_reporting為0,則display_error設置將失效。
如果error_reporting為排除某些級別,display_error設置為On時將排除指定級別錯誤信息的顯示。
對於“想要顯示錯誤信息”時,直接配置error_reporting=E_ALL、display_errors=On 一般來說是沒有問題的。如果有,則會是:
(1) “頁面空白,但顯示狀態為200正常” - 通常是程序正常輸出前遇到Fatal Error(如擴展未開啟,調用了未定義函數),但使用了@屏敞掉了錯誤並中斷。
(2) “只顯示錯誤信息,但沒有顯示程序中出錯前的其它輸出的內容” - log_errors被設置為On,但error_log日志文件沒有權限或路徑錯誤造成的。可以設置log_errors為Off或者設置正確有權限的error_log路徑。
(3) "只顯示HTTP500內部服務器錯誤,但沒有直觀的具體的錯誤信息” - IE瀏覽器的設置問題 。如果是IE瀏覽器或者是在IE模式下運行,可以切換為其它非IE瀏覽器或非IE模式試試,也可以在瀏覽器 “ 工具 》 Internet屬性 》 高級 》 設置 ” 中,將“顯示友好HTTP錯誤信息” 中的勾選去掉。
3、log_errors = On
log_errors 名如其義,“記錄-出錯信息”,它表示的是日志文件對出錯信息的記錄與否。
設置為On時,代表將相應級別的錯誤記錄到日志文件,如果為On,則必須與error_log項相搭配使用,並且注意error_log的配置問題,否則可能對瀏覽器輸出有影響。
設置為Off時,代表着不在日志文件中記錄出錯信息。設置為Off時,將不會對瀏覽器的輸出有影響。
4、error_log = c:/wamp/php/php5.5.16/error.txt
error_log 意思是“錯誤-日志文件”,指定了出錯信息如果需要記錄時,所記錄到日志文件的位置。
error_log 配置錯誤日志文件位置,通常用於在生產環境下不方便在瀏覽器顯示錯誤時,可以將錯誤記錄到文件,也可用於記錄瀏覽器不能顯示的某些特定的錯誤/警告,如:PHP Warning: PHP Startup: Unable to load dynamic library。
默認為被注釋掉(即為空,它是權限問題造成的原因之一)。
error_log配置時可以使用根路徑、物理路徑、相對路徑等形式,如:
(1) error_log = /xxx/xx/error.txt - 相對於運行文件所在的磁盤根目錄的路徑,windows與linux系統都中可以如此設置。
(2) error_log = error.txt 或 ../error.txt 等 - 相對於正在執行的PHP文件運行文件路徑,通常不這么設置。
(3) error_log = c:/wamp/php/php5.5.16/error.txt - 硬盤路徑,windows系統中通常使用的形式。
當log_errors為On且配置的日志文件沒有權限時,不管display_error為On還是Off,錯誤信息都不寫入日志文件,會直接輸出到瀏覽器上 (這一點在“不想顯示錯誤信息”時要特別注意)
error_log權限問題,在以下情況會出現權限問題(沒有權限):
(1)文件所在的目錄路徑不存在,沒有權限。
(2)位置正確,但文件確實沒有權限
(3) error_log 沒有配置(即被;號注釋了)-這個是最常見的導致出錯日志信息反輸到瀏覽器的權限問題
至此,理解了這4個配置,並進行正確設置,就能顯示或不顯示、記錄或不記錄出錯信息。
除了可以在php.ini中對此4項進行設置,也可以在php文件中使用代碼進行設置:
php文件配置瀏覽器顯示錯誤:
error_reporting(E_ALL);
ini_set('display_errors','On');
ini_set('log_errors','On');
ini_set('error_log','/log.txt');// 配置了正確的有權限的日志文件路徑
php文件配置瀏覽器不顯示錯誤(但日志文件記錄錯誤):
error_reporting(0); ini_set('display_errors','Off'); ini_set('log_errors','On'); ini_set('error_log','/log.txt');// 配置了正確的有權限的日志文件路徑
一般情況下php文件對四個相關配置的設置優先級高於php.ini,並且不需要重啟web服務器就能看到效果。
但如果出錯屬於語法錯誤時,php文件處理不運行狀態,這時php.ini的設置的優先級更高。
判斷瀏覽器上顯示的錯誤是display_errors的還是log_errors的:
display_errors=on 作用下的幾個顯示例子(有加粗效果):
Parse error: syntax error, unexpected ';'
頁面不執行代碼僅顯示錯誤輸出(無法通過@屏敞錯誤輸出)
Fatal error: Call to undefined function
頁面執行到錯誤處,如果有輸出則顯示輸出,之后顯示錯誤輸出,並且中斷后續執行(如果有@可以屏敞該級別的錯誤輸出,但仍然會中斷后續執行)。
Notice: Undefined variable:
頁面執行到錯誤處,如果有輸出則顯示輸出,之后顯示錯誤輸出,但不中斷后續執行(如果有@可以屏敞該級別的錯誤輸出)。
log_errors=on 作用下的幾個顯示例子(無加粗效果,有PHP前綴):
PHP Parse error: syntax error, unexpected ';'
頁面不執行代碼僅顯示錯誤輸出(無法通過@屏敞錯誤輸出)
PHP Fatal error: Call to undefined
頁面執行到錯誤處(有輸出的話也不進行任何輸出),之后僅顯示錯誤輸出,並且中斷后續執行(如果有@可以屏敞錯誤輸出同時將之前程序執行輸出也顯示出來,但仍然會中斷)。
PHP Notice: Undefined variable:
頁面執行到錯誤處(有輸出的話也不進行任何輸出),之后顯示錯誤輸出,但不中斷后續執行(只有頁面中的所有出錯都被@屏敞或者中斷前的出錯都被@屏敞,程序中的正常echo輸出才能顯示。瀏覽器會顯示所有的非中斷錯誤提示,直到中斷)。
說明:
log_errors=On起作用的原因:error_log沒有配置或路徑錯誤或權限問題
當error_log沒配置或不正確時,log_errors=On、display_errors=Off時,瀏覽器顯示無加粗的有PHP前綴的錯誤。當然,當error_log正確配置時,就沒有這種情況。
只讓display_errors=on起作用的話,可以設置log_errors=Off , 也可以設置log_errors=On 並且 error_log=正確的有權限的文件
通過瀏覽器的顯示效果或輸出、中斷效果,可以大概知道php.ini中對display_error及log_errors的配置情形。
通過@可以屏敞錯誤輸出,並且針對log_errors=On起作用的程序輸出也可以進行輸出控制。
導致頁面空白(即響應碼200正常,但不輸出任何html)的兩種情形:
[1].遇到Parse error之類的編譯錯誤,但設置了瀏覽器不進行錯誤顯示,如:
php代碼示例:
<?php
x(;
?>
php.ini示例-形式一:
error_reporting = E_ALL display_errors = Off log_errors = Off
php.ini示例-形式二:
error_reporting = E_ALL display_errors = Off log_errors = On error_log = 正確的有權限的路徑
php.ini示例-形式三:
error_reporting = 0
php.ini示例-形式四:
error_reporting = E_ALL ^ E_PARSE
[2].程序有輸出之前遇到Fatal error之類的中斷錯誤,且用@進行了抑制(此時與display_errors、log_errors都無關),如:
php代碼示例:
<?php
@x();
echo 'begin print msg!'; //不會輸出,已中斷
?>
根據上邊形式,可以知道當MYSQL擴展沒有開啟時,以下代碼執行,頁面顯示空白:
<?php
//此前沒有任何輸出操作
$conn = @mysql_connect('localohst','root','root') or die('連接數據庫出錯!'); echo 'query ......'; //不會輸出,已中斷 $conn->query(); ?>
注意@號可以牽連到該代碼執行范圍內的調用到的其它所有東西(如被調用的函數),所以對於用戶自己的函數的調用,最好不要進行@調用。