首頁 >後端開發 >PHP問題 >如何解決php 500錯誤問題

如何解決php 500錯誤問題

藏色散人
藏色散人原創
2021-12-29 09:30:2912599瀏覽

php 500錯誤的解決方法:1、檢查PHP腳本並修改;2、捕獲異常並記錄異常到日誌;3、分析日誌並處理即可。

如何解決php 500錯誤問題

本文操作環境:Windows7系統、PHP7.1版、Dell G3電腦。

如何解決php  500錯誤問題?

#PHP與500錯誤

PHP開發過程中經常會遇到返回500錯誤的情況,而且body體中也沒有任何調試(可用)內容。這時候你就需要慢慢調試了(打斷點,開調試模式等),但如果是現網,這個錯誤就比較讓人抓狂了,既不好打斷點也不能開調試模式。但既然是錯誤,總是會有處理方法,以下就一步步分析500的成因及處理方案。

0x01、500錯誤

500錯誤,也叫Internal Server Error(內部服務錯誤),表示服務因未知錯誤導致無法處理要求。在PHP站點中一般是由PHP傳回,也就是說,500錯誤一般都是PHP腳本的錯誤。

如何解決php 500錯誤問題

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錯誤。

如何解決php 500錯誤問題

E_ERROR等級錯誤所導致的500

0x03、什麼情況下錯誤不會回傳500

#上面說了,這是PHP腳本的錯誤導致的,但PHP腳本有了錯誤或異常一定會導致500嗎?顯然不是,即使在腳本有致命錯誤的情況下,依舊可以回傳200。

如何解決php 500錯誤問題

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的配置表示該值為字串類型,實際使用中數字和布林類型也可以開啟或關閉該配置。

如何解決php 500錯誤問題

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項的控制的。

如何解決php 500錯誤問題

在錯誤等級不符的情況下不顯示錯誤詳情

0x04、現網如何合理處理500

500錯誤發生已經說明PHP腳本無法正常運作了,這時候能做的只是捕獲異常並記錄異常到日誌,以方便日後的調試和現網bug的處理。


PHP自帶錯誤日誌

#PHP本身已經帶了錯誤日誌的記錄,可以在php.ini中將log_errors項目設定為On,並配合error_log配置項目來指定錯誤日誌的存放路徑。

如何解決php 500錯誤問題

錯誤日誌記錄開關

如何解決php 500錯誤問題

日誌路徑設定

該錯誤日誌的寫入不受display_errors的配置的控制。也就是說不管display_errors是否開啟,錯誤都會記錄到日誌中。但是卻受error_reporting配置的控制,如果目前錯誤等級跟error_reporting中的錯誤等級不符的話,錯誤不會寫入日誌中。也就是如果錯誤等級是E_ERROR,但是設定卻為error_reporting(E_NOTICE),那麼日誌中不會出現E_ERROR的出錯訊息。

如何解決php 500錯誤問題

PHP錯誤日誌記錄各種類型的錯誤

如何解決php 500錯誤問題

錯誤等級不符合導致的日誌不寫入

捕獲錯誤異常記錄

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