Last active
August 29, 2015 14:10
-
-
Save Flushot/f76c6df80fe5c6334f21 to your computer and use it in GitHub Desktop.
Keeps a clean separation between legitimate content and error messages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env php | |
| <?php | |
| $_emit_shutdown_function_registered = false; | |
| /** | |
| * Emits (using echo()) the return value of a closure function. | |
| * Keeps a clean separation between legitimate content and error messages. | |
| * | |
| * If any type of fatal error or Exception was encountered during evaluation, | |
| * the HTTP status code will be set to 500 and the error message will be emitted in plain text. | |
| * | |
| * Ouput-modifying side effects such as echo() calls or PHP warnings will be swallowed | |
| * and dumped to the error log instead. | |
| * | |
| * Example: | |
| * | |
| * emit(function() { | |
| * return "foo bar\n"; | |
| * }); | |
| * | |
| * @param $fn a Closure returning the value to emit. | |
| */ | |
| function emit($fn) { | |
| global $_emit_shutdown_function_registered; | |
| $error_mask = E_ERROR | E_CORE_ERROR | E_USER_ERROR; | |
| $saved_error_flags = error_reporting(); | |
| // Suppress fatal errors in output, since it's already going to be emitted by shutdown function | |
| error_reporting($saved_error_flags & ~$error_mask); | |
| ob_start(); | |
| // Emit PHP fatal error | |
| if (!$_emit_shutdown_function_registered) { | |
| register_shutdown_function(function() use ($error_mask) { | |
| $error = error_get_last(); | |
| $type = $error['type']; | |
| // Ignore warnings | |
| if (($error_mask & $type) === 0) | |
| return; | |
| if ($error !== NULL) { | |
| $error_map = array( | |
| E_ERROR => 'E_ERROR', | |
| E_WARNING => 'E_WARNING', | |
| E_NOTICE => 'E_NOTICE', | |
| E_CORE_ERROR => 'E_CORE_ERROR', | |
| E_CORE_WARNING => 'E_CORE_WARNING', | |
| E_COMPILE_ERROR => 'E_COMPILE_ERROR', | |
| E_COMPILE_WARNING => 'E_COMPILE_WARNING', | |
| E_USER_ERROR => 'E_USER_ERROR', | |
| E_USER_WARNING => 'E_USER_WARNING', | |
| E_USER_NOTICE => 'E_USER_NOTICE', | |
| E_STRICT => 'E_STRICT', | |
| E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', | |
| E_DEPRECATED => 'E_DEPRECATED', | |
| E_USER_DEPRECATED => 'E_USER_DEPRECATED' | |
| ); | |
| $error_type = $error_map[$type]; | |
| if (!$error_type) | |
| $error_type = $type; | |
| $message = 'Error ' . $error_type . ' (in ' . $error['file'] . | |
| ', line ' . $error['line'] . '): ' . $error['message']; | |
| } | |
| else { | |
| $message = 'Error: Unknown error occurred'; | |
| } | |
| ob_clean(); | |
| debug_print_backtrace(); | |
| $message .= "\n" . ob_get_clean(); | |
| http_response_code(500); | |
| header('Content-Type: text/plain'); | |
| echo $message; | |
| //die(); | |
| }); | |
| } | |
| try { | |
| $result = $fn(); | |
| // Swallow warnings in output, logging them instead | |
| $output = ob_get_clean(); | |
| if ($output) { | |
| $output = strip_tags(preg_replace('/\<br(\s*)?\/?\>/i', "\n", $output)); | |
| error_log('emit() got unexpected PHP output: ' . $output); | |
| } | |
| echo $result; | |
| } | |
| // Emit error on raised exceptions | |
| catch (Exception $ex) { | |
| ob_clean(); | |
| debug_print_backtrace(); | |
| $message = get_class($ex) . ': ' . $ex->getMessage() . "\n" . ob_get_clean(); | |
| http_response_code(500); | |
| header('Content-Type: text/plain'); | |
| echo $message; | |
| } | |
| error_reporting($saved_error_flags); | |
| } | |
| ?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment