Destramic Posted June 29, 2015 Share Posted June 29, 2015 hey guys i read about being able to catch E_ERROR's using: register_shutdown_function('fatal_error_catcher'); function fatal_error_catcher() { $last_error = error_get_last(); if ($last_error['type'] === E_ERROR) { print_r($last_error); } } now I've tried to test it when triggering but it'll just show a warning message trigger_error('test', E_ERROR); my questions are 1. is it even possible to catch a fatal error?...as a fatal error would be caused by the PHP engine itself, which makes me think it wouldn't execute this error catcher? 2. or is it not catching because you can't manual trigger a E_ERROR. some advise on this would be helpful thank you Quote Link to comment Share on other sites More sharing options...
fastsol Posted June 29, 2015 Share Posted June 29, 2015 I'm going to guess it's either cause you can't trigger it that way or because you're using print_r() on the error result. I use 3 error handlers in my cms to db log anything that happens, including fatal errors. This is my error handling function page // Strips the SERVER HOST to main domain name function stripHost() { if(!empty($_SERVER['HTTP_HOST'])) { if(substr($_SERVER['HTTP_HOST'], 0, 4) == "www.") {$server = htmlentities(substr($_SERVER['HTTP_HOST'], 4), ENT_QUOTES);} else {$server = htmlentities($_SERVER['HTTP_HOST'], ENT_QUOTES);} } else{ $server = $_SERVER['SERVER_NAME']; } return $server; } // Determines if the host is your development localhost function isLocalhost() { if(strpos(stripHost(), 'localhost') !== FALSE) { return TRUE; } else{ return FALSE; } } // Attempts to get an accurate IP address from the client function get_ip_address() { $ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'); foreach ($ip_keys as $key) { if (array_key_exists($key, $_SERVER) === true) { foreach (explode(',', $_SERVER[$key]) as $ip) { // trim for safety measures $ip = trim($ip); // attempt to validate IP if (validate_ip($ip)) { return $ip; } } } } return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false; } /** * Ensures an ip address is both a valid IP and does not fall within * a private network range. */ function validate_ip($ip) { if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) { return false; } return true; } function checkUserAgent() { $agent = (!empty($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : ''; if(!empty($agent)) { $apikey = '92a7f5ba'; $useragent = urlencode($agent); $request = file_get_contents("http://useragentapi.com/api/v2/json/$apikey/$useragent"); $result = json_decode($request, true); return $result; } } // Custom error handler function cmsErrorHandler($code, $message, $file, $line) { $code = (int)$code; $line = (int)$line; $user_agent = checkUserAgent(); $fields = ['platform_type', 'platform_name', 'platform_version', 'browser_name', 'browser_version', 'engine_name', 'engine_version']; if(!empty($user_agent)) { foreach($user_agent as $key => $val) { if(in_array($key, $fields)) { $agent[$key] = $val; } } } $last_page = (isset($_SESSION['last_page_queried'])) ? $_SESSION['last_page_queried'] : ''; $params = [ 'error_type' => [$code, 'INT'], 'error_time' => date("Y-m-d H:i:s"), 'error_string' => $message, 'error_file' => $file, 'error_line' => [$line, 'INT'], 'error_ip' => get_ip_address(), 'queried_page' => $last_page ]; $params = (!empty($agent)) ? array_merge($params, $agent) : $params; DB::getInstance()->insert('cms_errors', $params); } function cmsExceptionErrorHandler($e) { cmsErrorHandler($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine()); } // Custom Fatal error handler function cmsFatalErrorShutdownHandler() { $last_error = error_get_last(); if ($last_error['type'] === E_ERROR) { // fatal error cmsErrorHandler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']); header('Location: http://'.stripHost().'/500.html'); } } And this is the set handlers if(isLocalhost() === FALSE) { // Setup custom error_handlers set_error_handler('cmsErrorHandler'); set_exception_handler('cmsExceptionErrorHandler'); register_shutdown_function('cmsFatalErrorShutdownHandler'); } One note, the header() in the fatal error function will only work if the error occurs before any output to the browser, typical cause of the buffer. I made a stripped down 500.html page to redirect to if it's able to. Quote Link to comment Share on other sites More sharing options...
Destramic Posted June 29, 2015 Author Share Posted June 29, 2015 yeah i've used mine to catch exceptions also...although i do like the redirect to 500 error page if occurs...the problem is with my code is that when i try to get the last error print_r(error_get_last()); it returns nothing even when there's a error....any idea why? Quote Link to comment Share on other sites More sharing options...
fastsol Posted June 29, 2015 Share Posted June 29, 2015 Thinking, I believe it won't echo anything out cause with a fatal error, the parser stops immediately when the error happens. So it can't output anything after that point, it can perform some other things, but output is a no go. Quote Link to comment Share on other sites More sharing options...
Destramic Posted June 29, 2015 Author Share Posted June 29, 2015 Even when triggering a warning error it doesn't return nothing... Quote Link to comment Share on other sites More sharing options...
Destramic Posted July 1, 2015 Author Share Posted July 1, 2015 here's what i've made just need to add database now...the one problem i did see though is if using a PHP vesion > 5.3 then you're unable to use the error_get_last(): function...therefor being unable to capture any fatal errors which sucks! <?php class Error_Handler { protected $_handler; protected static $_error_reporting; public function __construct($handler = "Unkown") { set_exception_handler(array($this, 'exception_catcher')); set_error_handler(array($this, 'error_catcher')); $this->_handler = $handler; } public function set_error_reporting($error_reporting = true) { if ($error_reporting !== false) { ini_set('display_startup_errors', 1); ini_set('display_errors', 1); error_reporting(E_ALL); self::$_error_reporting = true; } else { ini_set('display_startup_errors', 0); ini_set('display_errors', 0); error_reporting(0); self::$_error_reporting = false; } } public function debug($name, $data) { $data = $this->desensitize_data($data); if (self::$_error_reporting === true) { if (is_array($data) || is_object($data)) { $data = json_encode($data); } echo "<script>console.log('PHP: " . $name . " - " . $data . "');</script>"; } else { echo "log debug in db."; } } public function log($message, $data) { $handler = $this->_handler; if ($data instanceof Exception) { $traces = $this->trace($data->getTrace()); // log traces // log exception } else { $traces = debug_backtrace(); $traces = array_slice($traces, 3); $traces = $this->trace($traces); // log traces // log exception } } public function exception_catcher($exception) { $this->log('Uncaught Exception', $exception); } public function error_catcher($error_number, $message, $filename, $line, $parameters) { switch ($error_number) { case "2": $type = "E_WARNING"; break; case "8": $type = "E_NOTICE"; break; case "256": $type = "E_USER_ERROR"; break; case "512": $type = "E_USER_WARNING"; break; case "1024": $type = "E_USER_NOTICE"; break; case "16384": $type = "E_USER_DEPRECATED"; break; default: $type = "Unknown"; break; } if (empty($parameters)) { $parameters = null; } else { $parameters = json_encode($parameters); } $this->log($type, array('filename' => $filename, 'line' => $line, 'message' => $message, 'error_number' => $error_number, 'type' => $type, 'parameters' => $parameters )); } protected function trace($data) { $trace_count = count($data); $traces = array(); for ($i = 0; $i < $trace_count; $i++) { if (isset($data[$i]['class'])) { $function = $data[$i]['class'] . $data[$i]['type'] . $data[$i]['function']; } else { $function = $data[$i]['function']; } $function .= "("; $paramters = $data[$i]['args']; $paramter_count = count($paramters); $j = 1; foreach ($paramters as $parameter) { $function .= "'" . $parameter . "'"; if ($paramter_count !== $j) { $function .= ", "; } $j++; } $function .= ");"; $file = $data[$i]['file']; $line = $data[$i]['line']; $traces[] = array ('function' => $function, 'file' => $file, 'line' => $line ); } return $traces; } public function desensitize_data(&$data, $key = null) { if (is_array($data)) { array_walk_recursive($data, array($this, 'desensitize_data')); } else if (preg_match('/(password|pass|pwd|pw)/', $key)) { $data = "*****"; } return $data; } } Quote Link to comment Share on other sites More sharing options...
scootstah Posted July 1, 2015 Share Posted July 1, 2015 You can't use E_ERROR in trigger_error(). You can only use user-space errors, which are: E_USER_NOTICE, E_USER_ERROR, and E_USER_WARNING. The snippet in your first post is indeed how you capture a fatal error, but you're not triggering a fatal error. Just throw an uncaptured exception and I think that will trigger it. Quote Link to comment Share on other sites More sharing options...
Destramic Posted July 2, 2015 Author Share Posted July 2, 2015 Yeah that's all good and we'll but error_get_last() doesn't work for php5 Quote Link to comment Share on other sites More sharing options...
Destramic Posted July 2, 2015 Author Share Posted July 2, 2015 PHP 5.5* Quote Link to comment Share on other sites More sharing options...
scootstah Posted July 2, 2015 Share Posted July 2, 2015 Yes it does. I'm running 5.6.7-1 and it works fine. <?php register_shutdown_function('fatal_error_catcher'); function fatal_error_catcher() { $last_error = error_get_last(); if ($last_error['type'] === E_ERROR) { echo '<pre>'; echo print_r($last_error, true); echo '</pre>'; } } throw new Exception('test');Returns: Array ( [type] => 1 [message] => Uncaught exception 'Exception' with message 'test' in /var/www/phpfreaks/error.php:18 Stack trace: #0 {main} thrown [file] => /var/www/phpfreaks/error.php [line] => 18 ) Quote Link to comment Share on other sites More sharing options...
Destramic Posted July 14, 2015 Author Share Posted July 14, 2015 yeah that worked a charm thank you....after a bit more reading i discovered setting the register_shutdown_function() in my class seemed to have been the problem. is there, or does anyone know how to use the register_shutdown_function() from a method please? <?php class Error_Handler { protected $_handler; public function __construct() { register_shutdown_function(array($this, 'fatal_error_catcher')); } public function fatal_error_catcher() { $last_error = error_get_last(); if ($last_error['type'] === E_ERROR) { echo "yes"; } } } $error_handler = new Error_Handler; throw new Exception('test'); Quote Link to comment Share on other sites More sharing options...
scootstah Posted July 14, 2015 Share Posted July 14, 2015 $error_handler = new Error_Handler; register_shutdown_function(array($error_handler, 'fatal_error_catcher')); Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.