Я новичок в написании переносного пользовательского обработчика ошибок, который при необходимости отображает страницу с ошибкой. Проблема в том, что делать, если заголовки или HTML уже отправлены. Вы не можете перенаправить и не можете предсказать, что уже отображается в браузере.
Я знаю, что этого не случится с хорошим кодом. Это последнее средство для тех офигенных событий.
Код работает, добавляя к странице некоторые html-хаки типа «умело работай», пытаясь либо принудительно заставить браузер перенаправить, либо, если это не удается, отобразить красивую страницу с ошибкой в разделении, которое появляется, чтобы скрыть все, что уже есть на странице. ,
Является ли приведенный ниже код разумным или смешным, или PHP предлагает лучшее решение? Кроме того, есть ли еще что я должен сделать, чтобы сделать его твердым?
<?PHP
// oh crap! something bad happened but...
// yay, my custom error handler caught it.
// It now does some error handler stuff, records the error, sends me a nasty email, etc.
// Decides the error was fatal. Time to display an error page.
// But wait! Alas, what if headers were sent?
// What if a single empty space was already sent to the browser?
// "ominous music".if (!headers_sent()) {
// whew! no problem. display a pretty error page.
}else{
// dammit! somebodies getting fired.
// lets see if we can salvage this and show the viewer something nice.
$mySafeErrorPage = "http://root.com/somePage.html";
// Step one: Stop as much HTML as possible.
// Dump anything still in the buffers.
while (ob_get_level() > 0 && ob_get_status() != false) {
ob_end_clean();
}
// Step two: Make sure our hack isn't stuck inside a comment or script.
echo'// -- > </script>';
// Step three: Make sure the safe page exist and is really safe.
// Insert two redirect hacks. One for JavaScript. The other if script is disabled.
$headersArray = @get_headers($mySafeErrorPage);
$headersString = (is_array($headersArray))?implode("\n",$headersArray):$headersArray;
$validated = (bool)preg_match('#HTTP/.*\s+[(200|301|302)]+\s#i',$headersString);
if ($validated) {
echo'
<script language="javascript" type="text/javascript">
window.location.href="'.$mySafePage.'"</script>
<meta http-equiv="refresh" content="0; url= '.$mySafeErrorPage.'" />';
}
// Step four:
// If we're still here, the redirect failed.
// Display the error page in a giant pop-up block division
// to hide anything already sent to browser.
echo'
<div style = "z-index:9998;display:block;position:absolute;top:0px;left:0px;height:3000px;width:3000px;background-color:#FFF">
<div style = "z-index:9999;display:block;position:absolute;top:0px;left:0px;width:300px;height:300px;background-color:#FFF;color:#000">
MY HTTP 500 MESSAGE
</div>
</div>';
exit;
}
Во-первых, вы пытаетесь устранить эффект, а не причину проблемы. Во-вторых, где бы вы разместили этот код? Перед тем, как страница отображается? Не будет работать, так как в это время заголовки не отправляются. После того, как страница отображается? Не будет работать, так как все заголовки отправляются в это время.
Другим недостатком этого кода является тот факт, что разработчики должны будут помнить, чтобы включать его в каждую страницу, что может быть обременительным и может привести к ошибкам.
Если вы действительно хотите избежать ошибки «заголовки уже отправлены», добавьте пользовательскую функцию my_header (), которая оборачивает PHP-функцию header () и которая проверяет headers_sent (). И запретить кому-либо еще использовать встроенную функцию PHP.
Пример для my_header (объявление функции скопировано из оригинальной функции header ()):
function my_header($string, $replace = true, $http_response_code) {
if(headers_sent()) {
throw new Exception("Headers were already sent");
}
header($string, $replace, $http_response_code);
}
Вы можете наложить некоторые правила на проект, например, каждый должен использовать my_header () вместо header (), и во время проверки кода вы можете отклонить код, который напрямую вызывает header (). Если вы единственный в проекте, то все проще 🙂
Других решений пока нет …