PHP の致命的なエラーは、ステータス コード 200 として HTTP クライアントに返されます。ステータス コード 500 (内部サーバー エラー) を返すようにするにはどうすればよいですか?
10 に答える
header("HTTP/1.1 500 Internal Server Error");
これはまさに私が昨日抱えていた問題であり、次のように解決策を見つけました。
1) まず、エラー タイプ E_ERROR である PHP の致命的なエラーをキャッチする必要があります。このエラーが発生すると、スクリプトはエラーを保存し、実行を終了します。関数 error_get_last() を呼び出すことで、保存されたエラーを取得できます。
2) スクリプトが終了する前に、コールバック関数 register_shutdown_function() が常に呼び出されます。そのため、この関数でエラー ハンドラーを登録して、必要なことを行う必要があります。この場合、ヘッダー 500 とカスタマイズされた内部エラー ページ (オプション) を返します。
function my_error_handler()
{
$last_error = error_get_last();
if ($last_error && $last_error['type']==E_ERROR)
{
header("HTTP/1.1 500 Internal Server Error");
echo '...';//html for 500 page
}
}
register_shutdown_function('my_error_handler');
注: E_USER* で始まるカスタム エラー タイプをキャッチする場合は、関数 set_error_handler() を使用してエラー ハンドラを登録し、関数 trigger_error によってエラーをトリガーできますが、このエラー ハンドラは E_ERROR エラー タイプを処理できません。エラーハンドラについては、php.net の説明を参照してください。
キャッチされない例外を処理するために「set_exception_handler」を使用しました。
function handleException($ex) {
error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine());
ob_end_clean(); # try to purge content sent so far
header('HTTP/1.1 500 Internal Server Error');
echo 'Internal error';
}
set_exception_handler('handleException');
PHP ドキュメントによると、PHP E_ERROR を処理することはできません: http://www.php.net/manual/en/function.set-error-handler.php
そのリンクに従って、「E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING、およびほとんどの E_STRICT」を処理することもできません。
E_USER_ERROR を含む他のエラー、警告、および通知のハンドラーを提供することはできますが、このエラーはプログラマーが trigger_error() を使用して意図的にスローするだけなので、実際には思ったほど役に立ちません。
もちろん、あらゆる例外をキャッチできます (ネイティブの PHP 関数によってスローされたものも含めて)。
これが問題であることには同意します。アプリケーション コードがクラッシュして焼き付いた場合、サーバーは 200 OK を返すべきではありません。
PHPエラー処理を使用できます
try/catchを使用してスローされたエラーをキャッチし、その catch ブロックを使用して 500 エラーでheader()を送信する必要があります。
try {
...badcode...
throw new Exception('error');
} catch (Exception $e) {
header("Status: 500 Server Error");
var_dump($e->getMessage());
}
致命的な例外が try {} catch ブロックで囲まれていない場合は、グローバル ハンドラーを登録し、register_shutdown_function()
スクリプトの最後でエラーをチェックするために使用する必要があります。
header("HTTP/1.1 200 OK", true, 200);
実行パスの最後の行として設定することを忘れないでください:
//first things first:
header("HTTP/1.1 500 Internal Server Error", true, 500);
//Application code, includes, requires, etc. [...]
//somewhere something happens
//die();
throw new Exception("Uncaught exception!");
//last things last, only reached if code execution was not stopped by uncaught exception or some fatal error
header("HTTP/1.1 200 OK", true, 200);
では、上記の関数をはるかに優れたorにPHP 5.4
置き換えることができます。header
http_response_code(200)
http_response_code(500)
致命的なエラー (セミコロンの欠落などのコンパイル エラー) を処理するときに難しいのは、スクリプトが実行されないことです。そのため、そのスクリプトにステータス コードを設定しても役に立ちません。ただし、スクリプトを含めるか要求すると、含まれるスクリプトのエラーに関係なく、呼び出し元のスクリプトが実行されます。これで、私はこの解決策にたどり着きました:
rock-solid-script.php:
// minimize changes to this script to keep it rock-solid
http_response_code(500); // PHP >= 5.4
require_once("script-i-want-to-guard-for-errors.php");
script-i-want-to-guard-for-errors.php:
// do all the processsing
// don't produce any output
// you might want to use output buffering
http_response_code(200); // PHP >= 5.4
// here you can produce the output
呼び出しを rock-solid-script.php に向ければ、準備完了です。
デフォルトのステータスコードを.htaccess in .htaccessに設定する方がよかったでしょう。それは私にとってよりエレガントに見えますが、私はそれをやってのける方法を見つけることができません。Rewriterule r-flagを試しましたが、これによりPHPの実行が完全に防止されるため、役に立ちません。