用PHP开发程序时,如果服务器出现500的时候(有时甚至不报错直接显示空白),如果无法知道究竟是什么原因,就无法进行调试。
如果是属于PHP代码的问题,要让PHP显示错误信息,可以从PHP配置文件 (php.ini)或PHP程序文件入手,另外,如果与IIS整合的时候,还必须考虑web.config文件。
如果是与IIS整合的方式,则需要修改web.config文件,对其中的<system.webServer>项添加<httpErros>条目:
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
</system.webServer>
注意:errorMode="DetailedLocalOnly"不适合于以上线站点的远程访问。
出于安全方面,如果需要,可以先设置为errorMode="Detailed",然后再删除或改回 errorMode="DetailedLocalOnly"
如果是与IIS整合的权限方面的问题,则参见:
https://www.cnblogs.com/dreamyoung/p/17809485.html
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(); ?>
注意@号可以牵连到该代码执行范围内的调用到的其它所有东西(如被调用的函数),所以对于用户自己的函数的调用,最好不要进行@调用。