现在LNMP架构很流行,
然而有时我们会遇到一个莫名其妙的问题,
就是我们访问php页面时服务器返回"HTTP/1.1 500 Internal Server Error"错误
这个错误让人匪夷所思,还以为是nginx出问题了呢?
其实是php代码语法错误导致的
默认情况下,如果被访问的php脚本中包含语法错误,服务器会返回一个空的“200 ok”页面
在php.ini中的fastcgi.error_header选项允许在这种情况下产生一个HTTP错误码
以使web服务器可以正确拦截并处理这个错误码,类似直接在php代码中调用header()返回500状态码,如
header("HTTP/1.1 500 Internal Server Error");
通过php源码也可以看出来,本次使用的php版本是:php-5.3.26
源文件是:php-5.3.26/main/main.c
第1110行,如下:
if(!PG(display_errors) && !SG(headers_sent) && SG(sapi_headers).http_response_code == 200){ sapi_header_line ctr = {0}; ctr.line = "HTTP/1.0 500 Internal Server Error"; ctr.line_len = strlen(ctr.line); sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); }
通过if条件可以得知,在满足 display_errors=0 和 headers_sent=0即空白页和
http_response_code=200的条件下返回500错误
初看这个500错误容易误认为nginx出错,可以适当调整为其它响应码
只要在php.ini中设置 fastcgi.error_header 选项即可,如返回503:
fastcgi.error_header = "HTTP/1.1 503 PHP Parse Error"
这样就可以显示出错误的根本原因,可以在部署LNMP时加上
没加这个选项时,可以通过下面方法调试:
将访问出错的页面拷贝一个,成测试文件,防止影响线上业务和安全问题
如:cp index.php index.test.php
打开 display_errors 选项,在文件开头加入如下内容:
ini_set('display_errors','1'); error_reporting(E_ALL);
这样就可以将错误暴露出来,完毕!
前几天就遇到了这个500错误问题,情况是这样的:
有开发人员说网站访问出现500错误,他说ie和chrome都访问不了,只有firefox可以访问,我自己也试了试,ie和chrome确实不能访问,我机器没装firefox,所以没试,我突然想起以前公司也遇到过这个问题,所以想到了cookie的问题,就上服务器上排查php程序代码,最后发现这么一段代码:
protected function __construct($domain){ ... session_name(self::sess_name); $this->sess_id = empty($_COOKIE[session_name()]) ? $this->gen_sid() : $_COOKIE[session_name()]; ... } private function gen_sid(){ return md5(uniqid(microtime() . getClientIP(), true)); }
当程序执行到第9行的时候就会发生500错误,最大的可能就是 getClientIP 函数导致的,直接调用这个函数仍然返回500错误,用var_dump(function_exists('getClientIP'))调试,输出false,问题就在这里了,定义好这个函数就解决了。可是为什么firefox可以访问,而ie和chrome不能访问呢?这是因为firefox里面存在cookie了,而ie和chrome都是第一次访问,没有cookie,那为什么没有cookie就会出现这个问题呢?这要归责于:
$this->sess_id = empty($_COOKIE[session_name()]) ? $this->gen_sid() : $_COOKIE[session_name()];
第一次访问没有cookie,所以empty($_COOKIE[session_name()])为true,
就会调用$this->gen_sid(),就会出现上面找不到getClientIP函数的错误,而cookie存在的话就不会调用$this->gen_sid(),而是返回冒号后面的$_COOKIE[session_name()],就没问题了,呵呵!其实这么排查有点啰嗦,直接打开错误报告,错误就会显现出来,如:
ini_set('display_errors','1'); error_reporting(E_ALL);
显示如下错误信息,很容易就发现问题了,good
Fatal error: Call to undefined function getClientIP()
另外在 php-fpm.conf 中设置的php.ini选项优先于在php.ini中设置的选项,如
在 php.ini 中设置 display_errors = on
在 php-fpm.conf 中设置 php_flag[display_errors] = off
那么结果是 off