Skip to content

Instantly share code, notes, and snippets.

@Flushot
Last active August 29, 2015 14:10
Show Gist options
  • Select an option

  • Save Flushot/f76c6df80fe5c6334f21 to your computer and use it in GitHub Desktop.

Select an option

Save Flushot/f76c6df80fe5c6334f21 to your computer and use it in GitHub Desktop.
Keeps a clean separation between legitimate content and error messages
#!/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