Intercepts various PHP exceptions and errors, and generates alarms when fatal errors occur.

Source: Internet
Author: User
Intercepts various PHP exceptions and errors, and generates alarms when fatal errors occur. all prevention measures are taken before routine development. most people enable the debugging mode in the development environment, disable the debugging mode in the product environment. You can view various errors and exceptions during development, but disable the error display online.

The above situation seems very scientific. some people have explained that it is very safe and others cannot see the error to avoid leaking important information...

But have you ever encountered such a situation? it's good offline, but you cannot run it online. you cannot find the reason...

A script has been running for a long time, and it has never been a problem. one day it was suddenly interrupted and there was no record for any reason...

One online payment, someone else paid clearly, but we didn't record it. it was good to go to the experiment on our own...

All of these errors are caused by disabling error messages and logging errors and exceptions, making it difficult to trace random errors. In this way, the conflict arises, that is, do not display errors, but trace errors again. how can this problem be achieved?

The above problems can be solved through PHP errors, exception mechanisms, built-in functions 'set _ exception_handler', 'set _ error_handler', and 'register _ shutdown_function '.

The 'set _ exception_handler 'function is used to intercept uncaptured exceptions and then hand these exceptions to the user-defined method for processing.

The 'set _ error_handler' function can intercept various errors and hand them to a user-defined method for processing.

The 'register _ shutdown_function 'function is called at the end of the PHP script. it can be used with 'error _ get_last' to obtain the final fatal error.

The general idea is to block errors, exceptions, and fatal errors and hand them over to our custom methods for handling. we can identify whether these errors and exceptions are fatal, if yes, it will record the database or file system, and then use the script to continuously scan these logs, and immediately send an email or send a text message to trigger an alarm if any serious error is found.

First, we define an error interception class. this class is used to intercept errors and exceptions and process them in our own processing method. this class is put in the file named 'errorhandler. class. php, the code is as follows:

/*** File name: baseErrorHandler. class. php * Abstract: error interceptor parent class */require 'errorhandlerexception. class. php '; // exception class errorHandler {public $ argvs = array (); public $ memoryReserveSize = 262144; // backup memory size private $ _ memoryReserve; // backup memory/*** method: custom registration error, exception interceptor * parameter number: void * return: void */public function register () {ini_set ('display _ errors ', 0); set_exception_handler (array ($ this, 'handleexception'); // capture uncaptured exceptions set_er Ror_handler (array ($ this, 'handleerror ')); // you cannot change the location for intercepting all kinds of errors. // you can leave a backup memory to block critical errors later. $ this-> memoryReserveSize> 0 & $ this-> _ memoryReserve = str_repeat ('X ', $ this-> memoryReserveSize); register_shutdown_function (array ($ this, 'handlefatalerror'); // intercepts fatal errors}/*** method: cancel custom error and exception interceptor * parameter: void * return: void */public function unregister () {restore_error_handler (); restore_exception_handler ();} /*** method: Intercepted uncaptured exceptions * parameter: Exception $ exception * return: void */public function handleException ($ exception) {$ this-> unregister (); try {$ this-> logException ($ exception); exit (1) ;}catch (Exception $ e) {exit (1) ;}}/*** method: handle intercepted error * parameter: int $ code error code * parameter: string $ message Error message * parameter: string $ file error file * parameter: int $ line error row * return: boolean */public function handleError ($ code, $ message, $ file, $ line) {// this idea Is to throw an error into an exception and send it to the exception handler for processing if (error_reporting () & $ code )&&! In_array ($ code, array (E_NOTICE, E_WARNING, E_USER_NOTICE, E_USER_WARNING, E_DEPRECATED ))) {// only serious errors are recorded here. do not process all kinds of warning notice. $ exception = new errorHandlerException ($ message, $ code, $ code, $ file, $ line ); $ trace = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS); array_shift ($ trace); // The first element of trace is to remove foreach from the current object ($ trace as $ frame) {if ($ frame ['function'] = '_ toString ') {// if the error occurs in the _ toString method, no exception is thrown. $ this-> handleException ($ exception); exit (1) ;}} throw $ exception ;} return false;}/*** method: intercepted fatal error * parameter number: void * return: void */public function handleFatalError () {unset ($ this-> _ memoryReserve); // release the memory for the following processing program to use $ error = error_get_last (); // The last error message if (errorHandlerException :: isFatalError ($ error) {// handle a fatal error $ exception = new errorHandlerException ($ error ['message'], $ error ['type'], $ error ['type'], $ error ['file'], $ error ['line']); $ this-> logException ($ exception ); exit (1) ;}}/*** method: Get server IP * parameter number: void * return: string */final public function getServerIp () {$ serverIp = ''; if (isset ($ _ SERVER ['server _ ADDR ']) {$ serverIp = $ _ SERVER ['server _ ADDR'];} elseif (isset ($ _ SERVER ['Local _ ADDR ']) {$ serverIp =$ _ SERVER ['Local _ ADDR'];} elseif (isset ($ _ SERVER ['hostname']) {$ serverIp = gethostbyname ($ _ SERVER ['hostname']);} else {$ serverIp = getenv ('server _ ADDR ');} return $ serverIp;}/*** method: Get current URI information * parameter number: void * return: string $ url */public function getCurrentUri () {$ uri = ''; if ($ _ SERVER [" REMOTE_ADDR "]) {// browser browsing mode $ uri = 'http: //'. $ _ SERVER ['server _ name']. $ _ SERVER ['request _ URI '];} else {// command line mode $ params = $ this-> argvs; $ uri = $ params [0]; array_shift ($ params); for ($ I = 0, $ len = count ($ params); $ I <$ len; $ I ++) {$ uri. = ''. $ params [$ I] ;}}return $ uri;}/*** method: record exception information * parameter: errorHandlerException $ e error exception * return: boolean saved successfully */final public function logException ($ e) {$ error = array ('add _ time' => time (), 'title' => errorHandlerException :: getName ($ e-> getCode (), // Obtain the user-friendly type name 'message' => array (), 'server _ IP' => $ this-> getServerIp (), 'code' => errorHandlerException: getLocalCode ($ e-> getCode ()), // define a number for various errors to search for 'file' => $ e-> getFile (), 'line' => $ e-> getLine (), 'URL' => $ this-> getCurrentUri (),); do {// $ e-> getFile (). ':'. $ e-> getLine (). ''. $ e-> getMessage (). '('. $ e-> getCode (). ')' $ message = (string) $ e; $ error ['message'] [] = $ message;} while ($ e = $ e-> getPrevious ()); $ error ['message'] = implode ("\ r \ n", $ error ['message']); $ this-> logError ($ error );} /*** method: record exception information * parameter: array $ error = array (* 'time' => int, * 'title' => 'string ', * 'message' => 'string', * 'code' => int, * 'server _ IP' => 'string' * 'file' => 'string ', * 'line' => int, * 'URL' => 'string', *); * return: whether boolean is saved successfully */public function logError ($ error) {/* here, how to record the error information to the log */}}

In the above code, there is an 'errorhandlerexception' class, which is placed in the file 'errorhandlerexception. class. in php, this class is used to convert an error to an exception, so as to record the file, row number, error code, error information, and other information of the error, the 'isfatalerror' method is used to identify whether the error is fatal. Here, we numbered and named the error to facilitate management. The code for this class is as follows:

/*** File name: errorHandlerException. class. php * Abstract: The custom error exception class inherits from the built-in error exception class in PHP */class errorHandlerException extends ErrorException {public static $ localCode = array (E_COMPILE_ERROR => 4001, e_COMPILE_WARNING => 4002, E_CORE_ERROR => 4003, E_CORE_WARNING => 4004, E_DEPRECATED => 4005, E_ERROR => 4006, E_NOTICE => 4007, E_PARSE => 4008, E_RECOVERABLE_ERROR => 4009, e_STRICT => 4010, E_USER_DEPRECATED => 4011, E_USER_ERROR => 4012, E_USER_NOTICE => 4013, E_USER_WARNING => 4014, E_WARNING => 4015,401 6 => 4016 ,); public static $ localName = array (E_COMPILE_ERROR => 'php Compile error', E_COMPILE_WARNING => 'php Compile warning', E_CORE_ERROR => 'php Core error ', e_CORE_WARNING => 'php Core warning', E_DEPRECATED => 'php Deprecated warning', E_ERROR => 'php Fatal error', E_NOTICE => 'php Notice ', e_PARSE => 'php Parse error', E_RECOVERABLE_ERROR => 'php Recoverable error', E_STRICT => 'php Strict warning', E_USER_DEPRECATED => 'php User Deprecated warning ', e_USER_ERROR => 'php User error', E_USER_NOTICE => 'php User notic', E_USER_WARNING => 'php User warning', E_WARNING => 'php warning ', 4016 => 'customer's error',);/*** method: constructor * Abstract: For more information, see http://php.net/manual/en/errorexception.construct.php ** Parameter: string $ message exception information (optional) * int $ code exception code (optional) * int $ severity * string $ filename exception File (optional) * int $ line (optional) number of abnormal rows * Exception $ previous (optional) ** return: void */public function _ construct ($ message = '', $ code = 0, $ severity = 1, $ filename = _ FILE __, $ line = _ LINE __, Exception $ previous = null) {parent :: __construct ($ message, $ code, $ severity, $ filename, $ line, $ previous);}/*** method: is it caused? Fatal error * parameter: array $ error * return: boolean */public static function isFatalError ($ error) {$ fatalErrors = array (E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, e_COMPILE_ERROR, E_COMPILE_WARNING); return isset ($ error ['type']) & in_array ($ error ['type'], $ fatalErrors);}/*** method: obtain the local error code * parameter number based on the original error code: int $ code * Back: int $ localCode */public static function getLocalCode ($ code) {return isset (self: $ LocalCode [$ code])? Self: $ localCode [$ code]: self: $ localCode [4016];}/*** method: get user-friendly name * parameters based on the original error code: int * return: string $ name */public static function getName ($ code) {return isset (self: $ localName [$ code])? Self ::$ localName [$ code]: self ::$ localName [4016];}

In the error interception class, you need to define the method ('logexception') for implementing error records. Note that some errors may occur continuously for a period of time, therefore, you only need to record it once. you can use the error code, File, row number, and error details to generate an MD5 value to record whether the error has been recorded) record is not required if it has already been recorded.

Then we define a file for instantiating the above classes to capture various errors and exceptions. This file is named 'registererrorhandler. php', as shown in the following figure.

/** Usage: * introduce the file at the entrance, and then define the DEBUG mode constant 'debug _ error' in the file '**
 * // *** Debug error mode: * 0 => Non-debug mode. no exception or error information is displayed, but an exception or error message is recorded. * 1 => debug mode, displays exceptions and ERROR messages, but does not record exceptions and ERROR messages */define ('debug _ error', 0); require 'errorhandler. class. php '; class registerErrorHandler {/*** method: registration exception, error interception * parameter number: void * return: void */public static function register () {global $ argv; if (DEBUG_ERROR) {// if debug mode ini_set ('display _ errors ', 1) is enabled; return ;} // if the debug mode ini_set ('error _ report',-1); ini_set ('display _ errors ', 0); $ handler = new errorHandler (); $ handler-> argvs = $ argv; // Get the parameter $ handler-> register () ;}} registerErrorHandler: register () in command line mode ();

The rest is that you need to introduce this file in your portal file, define the debugging mode, and then implement your own method of recording errors.

It should be noted that some errors have occurred before you register, and the script interruption cannot be recorded, because 'registererrorhandler: register () 'has not been executed yet.

In addition, the 'set _ error_handler 'function cannot capture the following types of errors: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, and E_COMPILE_WARNING. this can be seen in the official documentation, but it does not matter, because the above errors are parsing and compilation errors and none of them are passed, you cannot publish them online.

The above code has been strictly tested and applied to the online environment. you can change and use it as needed.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.