• 技术文章 >后端开发 >PHP问题

    如何解决php 500错误问题

    藏色散人藏色散人2021-12-29 09:30:29原创188

    php 500错误的解决办法:1、检查PHP脚本并修改;2、捕获异常并记录异常到日志;3、分析日志并处理即可。

    本文操作环境:Windows7系统、PHP7.1版、Dell G3电脑。

    如何解决php 500错误问题?

    PHP与500错误

    PHP开发过程中经常会遇到返回500错误的情况,而且body体中也没有任何调试(可用)内容。这个时候你就需要慢慢调试了(打断点,开调试模式等),但如果是现网,这个错误就比较让人抓狂了,既不好打断点也不能开调试模式。但既然是错误,总是会有处理方法,下面就一步步分析500的成因及处理方案。

    0x01、500错误

    500错误,也叫Internal Server Error(内部服务错误),表示服务因未知错误导致无法处理请求。在PHP站点中一般是由PHP返回,也就是说,500错误一般都是PHP脚本的错误。

    d961c8b11941089ffec544f8f3a1322.png

    php-fpm抓包500

    从上图中可以看出(Nginx+PHP-FPM架构),在PHP调用一个不存在的类时,脚本发生错误并返回500给Nginx(并且将错误信息也做了返回,只不过是卸载STDERR中)。

    0x02、哪些错误异常会导致500

    那么哪类错误会导致500错误呢,PHP所有的错误级别可以在PHP的官方文文档(http://php.net/manual/zh/errorfunc.constants.php)中查询到,而这其中错误级别为E_ERROR、E_PARSE、E_RECOVERABLE_ERROR、E_USER_ERROR以及未捕获的异常等都会导致500错误。

    e7ce6aefccaa7eec2aa130c1f320e0e.png

    E_ERROR级别错误导致的500

    0x03、什么情况下错误不会返回500

    上面说了,这个是PHP脚本的错误导致的,但是PHP脚本有了错误或异常一定会导致500吗?显然不是,即使在脚本有致命错误的情况下,依旧可以返回200。

    4ec263743581382fc44167b986f7d46.png

    display_errors配置选项

    在基于python、nodejs等的web应用中,默认情况下,如果出现异常信息会被打印到控制台(STDERR/STDOUT)中。而在基于PHP-FPM架构的PHP中没有控制台可以打印,它的stderr和stdout被置为FastCGI中对应的STRDERR和STDOUT。如果将错误重定向到STDOUT中,错误会直接输出到响应中,并且状态码也会置为200。这个也是display_errors选项所实现的能力。

    display_errors选项的配置需要通过ini_set来实现,PHP文档中关于display_errors的配置表明该值为字符串类型,实际使用中数字和布尔类型也可以打开或关闭该配置。

    fb4c1464ae0d97dff87bb4b435e36dd.png

    error_reporting配置

    display_errors控制了PHP脚本发生错误时是否显示错误详情以及是否返回错误状态码,而error_reporting项则用来控制哪级别的错误可以被直接打印出来。

    error_reporting的设置项可以通过error_reporting(E_ALL)或ini_set('error_reporting', E_ALL)来配置,函数参数的详情可以参考PHP文档。

    需要注意的是,PHP本身是有错误日志的(error_log和log_errors两个配置项目),若发生错误,PHP会将改错误写入错误日志中,而哪些错误需要被写入是受error_reporting项的控制的。

    4ec263743581382fc44167b986f7d46.png

    在错误级别不匹配的情况下不显示错误详情

    0x04、现网如何合理处理500

    500错误发生已经说明PHP脚本无法正常运行了,这时候能做的只是捕获异常并记录异常到日志,以方便日后的调试和现网bug的处理。


    PHP自带错误日志

    PHP本身已经带了错误日志的记录,可以在php.ini中将log_errors项设置为On,并配合error_log配置项来指定错误日志的存放路径。

    eb14705dc9c603fecbc945233c10755.png

    错误日志记录开关

    6503e8bb8c4379d5161c53fe7c3c1cf.png

    日志路径设置

    该错误日志的的写入不受display_errors的配置的控制。也就是说不管display_errors是否开启,错误都会记录到日志中。但是却受error_reporting配置的控制,如果当前错误级别跟error_reporting中的错误级别不匹配的话,错误不会写入日志中。即如果错误级别是E_ERROR,但是设置却为error_reporting(E_NOTICE),那么日志中不会出现E_ERROR的出错信息。

    fdc393b90790a44d9ce03d25c8f43a5.png

    PHP错误日志记录各种类型的错误

    4b9fb538e6433f6169123a6c732509f.png

    错误级别不匹配导致的日志不写入

    捕获错误异常记录

    PHP提供了set_error_handler、register_shutdown_function、set_exception_handler、error_get_last等相关的错误处理函数。可以通过函数将捕获到的错误信息写入指定日志来实现错误的记录。

    函数的使用详情可以参考http://km.oa.com/group/19368/articles/show/302491,这里提供一个模版:

    $previousHandler = set_exception_handler(function(Exception $ex) use (&$previousHandler) {
        call_user_func('exceptionHandler', $ex, $previousHandler);
    });
    set_error_handler('errorHandler');
    register_shutdown_function('fatalErrorHandler');
    function exceptionHandler(Exception $ex, $previousHandler)
    {
        $info = array(
            $ex->getFile(),
            $ex->getLine(),
            $ex->getCode(),
            $ex->getMessage()
        );
        // 记录日志
        logPHPError($info);
        if (isset($previousHandler) && is_callable($previousHandler)) {
            call_user_func($previousHandler, $ex);
        }
    }
    /**
     * 框架错误处理函数
     * @param $errno
     * @param $errstr
     * @param $errfile
     * @param $errline
     * @return bool
     */
    function errorHandler($errno = 0, $errstr = '', $errfile = '', $errline = 0)
    {
        switch ($errno) {
            case E_WARNING:
                $errname = 'E_WARNING';
                break;
            case E_NOTICE:
                $errname = 'E_NOTICE';
                break;
            case E_STRICT:
                $errname = 'E_STRICT';
                break;
            case E_RECOVERABLE_ERROR:
                $errname = 'E_RECOVERABLE_ERROR';
                break;
            case E_DEPRECATED:
                $errname = 'E_DEPRECATED';
                break;
            case E_USER_ERROR:
                $errname = 'E_USER_ERROR';
                break;
            case E_USER_WARNING:
                $errname = 'E_USER_WARNING';
                break;
            case E_USER_NOTICE:
                $errname = 'E_USER_NOTICE';
                break;
            case E_USER_DEPRECATED:
                $errname = 'E_USER_DEPRECATED';
                break;
            default:
                restore_error_handler();
                return false;
        }
        // 记录日志
        $info = array(
            $errfile,
            $errline,
            $errname,
            $errstr
        );
        logPHPError($info);
        restore_error_handler();
        return false;
    }
    /**
     * Fatal error错误处理
     */
    function fatalErrorHandler()
    {
        if (($e = error_get_last()) && $e['type'] === E_ERROR) {
            $info = array(
                $e['file'],
                $e['line'],
                'E_ERROR',
                $e['message']
            );
            // 记录日志
            logPHPError($info);
        }
    }

    0x05 总结

    总结起来,error_reporting是用于控制向浏览器或PHP错误日志输出错误信息级别的函数或配置,而display_errors则是控制是否向浏览器输出错误和告警信息。

    由于PHP的错误日志是全局的,而且受到error_reporting的控制,因此推荐在业务中实现自己的错误(异常)捕获记录逻辑。

    推荐学习:《PHP视频教程

    以上就是如何解决php 500错误问题的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:php 500错误
    上一篇:如何解决火车头php错误问题 下一篇:怎么修改云空间php.ini

    相关文章推荐

    • 如何解决win2008 php 500错误问题• php导出excel出现500错误怎么办• php7 提示500错误怎么解决• 如何解决iis6 php 500错误问题

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网