English 中文(简体)
我怎样在PHP中获取有用的错误信息?
原标题:
  • 时间:2009-05-10 09:48:12
  •  标签:

Quite often I will try and run a PHP script and just get a blank screen back. No error message; just an empty screen. The cause might have been a simple syntax error (wrong bracket, missing semicolon), or a failed function call, or something else entirely.

很难找出问题出在哪里。我最后不得不注释掉代码,到处输入“echo”语句等等,试图缩小问题范围。但肯定有更好的方法,对吧?

有没有办法让PHP生成一个像Java一样有用的错误消息?

最佳回答

默认情况下,错误显示被关闭,因为您不希望“客户”看到错误信息。

请参阅PHP文档中关于2个指令的信息:error_reporting和display_errors,链接为:这个页面。可能您想要更改的是display_errors。

So you have 3 options:

(1)您可以检查错误日志文件,因为它将包含所有错误(除非已禁用日志记录)。要启用错误记录,请确保将 log_errors 配置指令设置为 On 。当错误不是在PHP中发生而是由Web服务器发出时,日志也是有用的。

(2) You can add the following 2 lines that will help you debug errors that are not syntax errors happened in the same file:

error_reporting(E_ALL);
ini_set( display_errors ,  On );

Note that on a live server the latter should be set to Off (but only the latter, because you still need to learn about all errors happened, from the log file).

但是,对于在同一文件中发生的语法错误,上述命令将无法使用,您需要在php.ini中启用它们。如果您无法修改php.ini,也可以尝试将以下行添加到.htaccess文件中,尽管现在很少受支持。

php_flag  display_errors        on
php_value error_reporting       -1

(3)另一个选择是使用一个在输入时检查错误的编辑器,比如PhpEd,VSCode或PHPStorm。它们都带有调试器,可以提供更详细的信息。(PhpEd调试器非常类似于xdebug,并且直接集成到编辑器中,因此您可以使用一个程序完成所有操作。)

问题回答

The following enables all errors:

ini_set( display_startup_errors , 1);
ini_set( display_errors , 1);
error_reporting(-1);

还可以查看以下链接。

以下代码应该显示所有错误:

<?php

// ----------------------------------------------------------------------------------------------------
// - Display Errors
// ----------------------------------------------------------------------------------------------------
ini_set( display_errors ,  On );
ini_set( html_errors , 0);

// ----------------------------------------------------------------------------------------------------
// - Error Reporting
// ----------------------------------------------------------------------------------------------------
error_reporting(-1);

// ----------------------------------------------------------------------------------------------------
// - Shutdown Handler
// ----------------------------------------------------------------------------------------------------
function ShutdownHandler()
{
    if(@is_array($error = @error_get_last()))
    {
        return(@call_user_func_array( ErrorHandler , $error));
    };

    return(TRUE);
};

register_shutdown_function( ShutdownHandler );

// ----------------------------------------------------------------------------------------------------
// - Error Handler
// ----------------------------------------------------------------------------------------------------
function ErrorHandler($type, $message, $file, $line)
{
    $_ERRORS = Array(
        0x0001 =>  E_ERROR ,
        0x0002 =>  E_WARNING ,
        0x0004 =>  E_PARSE ,
        0x0008 =>  E_NOTICE ,
        0x0010 =>  E_CORE_ERROR ,
        0x0020 =>  E_CORE_WARNING ,
        0x0040 =>  E_COMPILE_ERROR ,
        0x0080 =>  E_COMPILE_WARNING ,
        0x0100 =>  E_USER_ERROR ,
        0x0200 =>  E_USER_WARNING ,
        0x0400 =>  E_USER_NOTICE ,
        0x0800 =>  E_STRICT ,
        0x1000 =>  E_RECOVERABLE_ERROR ,
        0x2000 =>  E_DEPRECATED ,
        0x4000 =>  E_USER_DEPRECATED 
    );

    if(!@is_string($name = @array_search($type, @array_flip($_ERRORS))))
    {
        $name =  E_UNKNOWN ;
    };

    return(print(@sprintf("%s Error in file xBB%sxAB at line %d: %s
", $name, @basename($file), $line, $message)));
};

$old_error_handler = set_error_handler("ErrorHandler");

// other php code

?>

只有在关机处理程序中出现错误时,才能使用此代码生成空白页面。我从自己的CMS中复制并粘贴了它,但我确信它可以工作。

You can include the following lines in the file you want to debug:

error_reporting(E_ALL);
ini_set( display_errors ,  1 );

This overrides the default settings in php.ini, which just make PHP report the errors to the log.

错误和警告通常会显示在....logsphp_error.log....logsapache_error.log中,这取决于您的php.ini设置。

也有用的错误通常会直接指向浏览器,但由于它们不是有效的 HTML,因此不会显示。

So "tail -f" your log files and when you get a blank screen use IEs "view" -> "source" menu options to view the raw output.

PHP Configuration

2 entries in php.ini dictate the output of errors:

  1. display_errors
  2. error_reporting

生产环境中,display_errors通常设置为Off(这是一件好事,因为在生产站点中显示错误通常是不可取的!)。

However, in development, it should be set to On, so that errors get displayed. Check!

error_reporting (as of PHP 5.3) is set by default to E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED (meaning, everything is shown except for notices, strict standards and deprecation notices). When in doubt, set it to E_ALL to display all the errors. Check!

Whoa whoa! No check! I can t change my php.ini!

真遗憾。通常,共享主机不允许更改他们的php.ini文件,因此,该选项遗憾不可用。但不要担心!我们有其他选项!

Runtime configuration

In the desired script, we can alter the php.ini entries in runtime! Meaning, it ll run when the script runs! Sweet!

error_reporting(E_ALL);
ini_set("display_errors", "On");

这两行代码将产生与上述更改php.ini条目相同的效果!太棒了!

I still get a blank page/500 error!

这意味着脚本甚至没有运行!这通常发生在您有一个语法错误时!

带有语法错误的脚本甚至都无法进入运行时。它会在编译时失败,这意味着它将使用php.ini中的值,如果您没有更改,可能不允许显示错误。

Error logs

In addition, PHP by default logs errors. In shared hosting, it may be in a dedicated folder or on the same folder as the offending script.

如果您可以访问php.ini,则可以在 error_log 项目下找到它。

我总是在 PHP 脚本的最顶端使用这个语法。

ini_set( error_reporting , E_ALL);
ini_set( display_errors ,  On );  //On or Off

有一个非常有用的扩展名叫做“xdebug”,可以使您的报告更美观。

For quick, hands-on troubleshooting I normally suggest here on SO:

error_reporting(~0); ini_set( display_errors , 1);

放到故障排查下的脚本开头。这并不完美,完美的做法是在php.ini中启用,并记录PHP中的错误以捕获语法和启动错误。

这里描述的设置显示所有错误,通知和警告,包括严格的,无论使用哪个PHP版本。

Next things to consider:

  • Install Xdebug and enable remote-debugging with your IDE.

同时参见:

可以注册钩子来使最后的错误或警告可见。

function shutdown(){
  var_dump(error_get_last());
}

register_shutdown_function( shutdown );

adding this code to the beginning of you index.php will help you debug the problems.

如果你非常酷,你可以尝试:

$test_server = $_SERVER[ SERVER_NAME ] == "127.0.0.1" || $_SERVER[ SERVER_NAME ] == "localhost" || substr($_SERVER[ SERVER_NAME ],0,3) == "192";

ini_set( display_errors ,$test_server);
error_reporting(E_ALL|E_STRICT);

仅在本地运行时才会显示错误。它还为您提供了test_server变量,可在其他适当的地方使用。

Any errors that happen before the script runs won t be caught, but for 99% of errors that I make, that s not an issue.

在页面顶部选择一个参数。

error_reporting(E_ERROR | E_WARNING | E_PARSE);

This is a problem of loaded vs. runtime configuration

重要的是认识到,语法错误或解析错误发生在编译或解析阶段,这意味着PHP在执行任何代码之前就会停止。因此,如果您在运行时修改PHP的display_errors配置(这包括从代码中使用ini_set到使用.htaccess,这是一个运行时配置文件),那么只有默认的加载配置设置生效。

How to always avoid WSOD in development

为避免WSOD,您需要确保您的加载配置文件中开启了display_errors并将error_reporting设置为-1这相当于E_ALL,因为它确保所有位都被打开,无论您运行哪个版本的PHP)。不要将E_ALL的常量值硬编码,因为该值可能会在不同版本的PHP之间发生更改。

Loaded configuration is either your loaded php.ini file or your apache.conf or httpd.conf or virtualhost file. Those files are only read once during the startup stage (when you first start apache httpd or php-fpm, for example) and only overridden by runtime configuration changes. Making sure that display_errors = 1 and error_reporting = -1 in your loaded configuration file ensures that you will never see a WSOD regardless of syntax or parse error that occur before a runtime change like ini_set( display_errors , 1); or error_reporting(E_ALL); can take place.

How to find your (php.ini) loaded configuration files

To locate your loaded configuration file(s) just create a new PHP file with only the following code...

<?php
phpinfo();

然后将您的浏览器指向那里,查看 Loaded Configuration FileAdditional .ini files parsed,它们通常位于您的 phpinfo() 的顶部,并包括所有已加载配置文件的绝对路径。

如果你看到的是(none)而不是文件,那就意味着在配置文件 (php.ini) 目录下没有找到 php.ini。所以你可以从这里下载 PHP 捆绑的标准 php.ini 文件,并将其复制到你的配置文件路径中命名为 php.ini,然后确保你的 PHP 用户有足够的权限读取该文件。你需要重新启动 httpd 或者 php-fpm 才能加载文件。请记住,这是 PHP 源代码捆绑的开发 php.ini 文件,所以请不要在生产环境中使用!


Just don t do this in production

This really is the best way to avoid a WSOD in development. Anyone suggesting that you put ini_set( display_errors , 1); or error_reporting(E_ALL); at the top of your PHP script or using .htaccess like you did here, is not going to help you avoid a WSOD when a syntax or parse error occurs (like in your case here) if your loaded configuration file has display_errors turned off.

Many people (and stock installations of PHP) will use a production-ini file that has display_errors turned off by default, which typically results in this same frustration you ve experienced here. Because PHP already has it turned off when it starts up, then encounters a syntax or parse error, and bails with nothing to output. You expect that your ini_set( display_errors ,1); at the top of your PHP script should have avoided that, but it won t matter if PHP can t parse your code because it will never have reached the runtime.

为了保持并使其舒适,您可以编辑您的php.ini文件。它通常存储在/etc/php.ini/etc/php/php.ini中,但更多本地php.ini文件可能会覆盖它,这取决于您的托管提供商的设置指南。请在顶部检查phpinfo()文件的Loaded Configuration File,以确定最后加载哪个文件。

Search for display_errors in that file. There should be only 3 instances, of which 2 are commented.

Change the uncommented line to:

display_errors = stdout
ini_set( display_errors , 1);
ini_set( display_startup_errors , 1);
error_reporting(E_ALL);

我不知道这是否有帮助,但这是我用于PHP项目的标准配置文件的一部分。即使在自己的服务器上,我倾向于不太依赖于apache配置。

I never have the disappearing error problem, so perhaps something here will give you an idea.

编辑以显示APPLICATON_LIVE

/*
APPLICATION_LIVE will be used in process to tell if we are in a development or production environment.  It s generally set as early as possible (often the first code to run), before any config, url routing, etc.
*/

if ( preg_match( "%^(www.)?livedomain.com$%", $_SERVER["HTTP_HOST"]) ) {
    define( APPLICATION_LIVE , true);
} elseif ( preg_match( "%^(www.)?devdomain.net$%", $_SERVER["HTTP_HOST"]) ) {
    define( APPLICATION_LIVE , false);
} else {
    die("INVALID HOST REQUEST (".$_SERVER["HTTP_HOST"].")");
    // Log or take other appropriate action.
}


/*
--------------------------------------------------------------------
DEFAULT ERROR HANDLING
--------------------------------------------------------------------
Default error logging.  Some of these may be changed later based on APPLICATION_LIVE.
*/
error_reporting(E_ALL & ~E_STRICT);
ini_set ( "display_errors", "0");
ini_set ( "display_startup_errors", "0");
ini_set ( "log_errors", 1);
ini_set ( "log_errors_max_len", 0);
ini_set ( "error_log", APPLICATION_ROOT."logs/php_error_log.txt");
ini_set ( "display_errors", "0");
ini_set ( "display_startup_errors", "0");

if ( ! APPLICATION_LIVE ) {
    // A few changes to error handling for development.
    // We will want errors to be visible during development.
    ini_set ( "display_errors", "1");
    ini_set ( "display_startup_errors", "1");
    ini_set ( "html_errors", "1");
    ini_set ( "docref_root", "http://www.php.net/");
    ini_set ( "error_prepend_string", "<div style= color:red; font-family:verdana; border:1px solid red; padding:5px; >");
    ini_set ( "error_append_string", "</div>");
}
error_reporting(E_ALL | E_STRICT);
ini_set( display_errors , 1);
ini_set( html_errors , 1);

另外,您可以通过 xdebug 获得更详细的信息。

I recommend Nette Tracy for better visualization of errors and exceptions in PHP:

将此翻译成中文:Nette Tracy 截图

error_reporting(E_ALL | E_STRICT);

并在php.ini中打开显示错误。

You can register your own error handler in PHP. Dumping all errors to a file might help you in these obscure cases, for example. Note that your function will get called, no matter what your current error_reporting is set to. Very basic example:

function dump_error_to_file($errno, $errstr) {
    file_put_contents( /tmp/php-errors , date( Y-m-d H:i:s -  ) . $errstr, FILE_APPEND);
}
set_error_handler( dump_error_to_file );

获取 PHP 有用错误的两个关键行是:

ini_set( display_errors ,1);
 error_reporting(E_ALL);

正如其他贡献者所指出的那样,出于安全原因,这些功能默认关闭。作为一个有用的提示-在设置您的站点时,通过为不同的环境进行开关操作,这些错误在您的本地和开发环境中默认开启是非常方便的。这可以通过以下代码实现(最好在您的index.php或config文件中,以便从一开始就启用):

switch($_SERVER[ SERVER_NAME ])
{
    // local
    case  yourdomain.dev :
    // dev
    case  dev.yourdomain.com :
        ini_set( display_errors ,1);
        error_reporting(E_ALL);
    break;
    //live
    case  yourdomain.com :
        //...
    break;
}

open your php.ini, make sure it s set to:

display_errors = On

restart your server.

您也可以尝试使用PHPStorm作为您的代码编辑器。它会在您在编辑器中打字时找到许多PHP和其他语法错误。

if you are a ubuntu user then goto your terminal and run this command

sudo tail -50f /var/log/apache2/error.log

where it will display recent 50 errors. There is a error file error.log for apache2 which logs all the errors.

要开启完整的错误报告,请将以下内容添加到您的脚本中:

error_reporting(E_ALL);

这会导致即使是最小的警告也会显示出来。而且,以防万一:

ini_set( display_errors ,  1 );

Will force the display of errors. This should be turned off in production servers, but not when you re developing.

“错误”是开发人员了解自己错误并解决问题,使系统工作完美的最有用的东西。

PHP 提供了一些更好的方式让开发人员了解他们的代码为什么出错以及出错的位置,因此通过了解这些错误,开发人员可以以许多方式改进他们的代码。

Best ways to write following two lines on the top of script to get all errors messages:

error_reporting(E_ALL);
ini_set("display_errors", 1);

另一种使用调试器工具(如xdebug)在您的IDE中的方法。

In addition to all the wonderful answers here, I d like to throw in a special mention for the MySQLi and PDO libraries.

为了... (wèi le...)

  1. Always see database related errors, and
  2. Avoid checking the return types for methods to see if something went wrong

最佳选项是将库配置为抛出异常

MySQLi

请将以下代码添加到脚本顶部

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

This is best placed before you use new mysqli() or mysqli_connect().

PDO

在连接实例上设置PDO :: ATTR_ERRMODE属性为PDO :: ERRMODE_EXCEPTION。您可以在构造函数中执行此操作

$pdo = new PDO( driver:host=localhost;... ,  username ,  password , [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

or after creation

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

你可以启用完整的错误报告(包括注意事项和严格消息)。一些人觉得这种报告过于冗长,但值得一试。在你的php.ini中将error_reporting设为E_ALL | E_STRICT

error_reporting = E_ALL | E_STRICT

E_STRICT 会通知您有关弃用函数并为您提供有关执行某些任务的最佳方法的建议。

If you don t want notices, but you find other message types helpful, try excluding notices:

error_reporting = (E_ALL | E_STRICT) & ~E_NOTICE

还要确保在 php.ini 中启用了 display_errors。如果您的 PHP 版本早于 5.2.4,则将其设置为 On

display_errors = "On"

如果您的版本是5.2.4或更高版本,请使用:

display_errors = "stderr"

除了error_reporting和display_errors ini设置之外,您可以从Web服务器的日志文件中获得SYNTAX错误。当我开发PHP时,我会将我的开发系统的web服务器日志加载到我的编辑器中。每当我测试页面并获得空白屏幕时,日志文件变得陈旧,我的编辑器会询问我是否要重新加载它。当我这样做时,我跳到底部,那里就是语法错误。例如:

[Sun Apr 19 19:09:11 2009] [error] [client 127.0.0.1] PHP Parse error:  syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in D:\webroot\test\test.php on line 9

This answer is brought to you by the department of redundancy department.

  1. ini_set() / php.ini / .htaccess / .user.ini

    现在已经充分讨论了 display_errorserror_reporting 这些设置选项。但是为了概括一下,何时使用哪个选项:

    • ini_set() and error_reporting() apply for runtime errors only.
    • php.ini should primarily be edited for development setups. (Webserver and CLI version often have different php.ini s)
    • .htaccess flags only work for dated setups (Find a new hoster! Well managed servers are cheaper.)
    • .user.ini are partial php.ini s for modern setups (FCGI/FPM)

    And as crude alternative for runtime errors you can often use:

    set_error_handler("var_dump");   // ignores error_reporting and `@` suppression
    
  2. error_get_last() 的中文翻译为:获取最近一次错误的信息。

    当禁用 error_display 时,可用于检索上次运行时的注意/警告/错误。

  3. 将此翻译成中文: $php_errormsg $php_errormsg

    这是一个超局部变量,也包含最后一个PHP运行时的消息。

  4. <强><代码>isset()消失吧!

    我知道这会让很多人不高兴,但是新手不应该使用issetempty。你可以在验证代码有效性之后添加通知抑制,但是绝不要在此之前。

    A lot of the "something doesn t work" questions we get lately are the result of typos like:

    if(isset($_POST[ sumbit ]))
    #                  ↑↑
    

    如果您的代码中充斥着isset / empty / array_keys_exists,则不会得到任何有用的通知。有时更明智的做法是使用@,这样至少可以将通知和警告记录到日志中。

  5. assert_options(ASSERT_ACTIVE|ASSERT_WARNING);

    To get warnings for assert() sections. (Pretty uncommon, but more proficient code might contain some.)

    PHP7要求在php.ini中也需要< a href="https://www.php.net/manual/en/ini.core.php#ini.zend.assertions" rel="nofollow noreferrer">< code>zend.assertions=1

  6. 声明(strict_types=1);

    将PHP弯曲成严格类型语言不会修复大量的逻辑错误,但它绝对是一个用于调试的选项。

  7. PDO / MySQLi

    @Phil已经提到了选项。当然,其他数据库API也有类似的选项。

  8. json_last_error() + json_last_error_msg 的中文翻译为:最后一个JSON错误() + 最新的JSON错误消息。

    用于JSON解析。

  9. preg_last_error()

    对于正则表达式。

  10. CURLOPT_VERBOSE (请点击链接查看)

    调试curl请求,至少需要使用CURLOPT_VERBOSE。

  11. 将此翻译成中文: shell/exec() shell/exec()函数

    同样地,Shell命令的执行本身不会产生错误。您始终需要2>&1并查看$ errno。





相关问题