Results 1 to 7 of 7

Thread: PHP: Custom error handling

  1. #1
    Join Date
    Mar 2005
    Location
    Isle of Man
    Posts
    1,261
    Thanks
    3
    Thanked 23 Times in 23 Posts

    Default PHP: Custom error handling

    I think I said a few days ago that I would offer up some ideas for creating your very own custom error handler in PHP. I have barely tested it, but it seems to work okay.

    To use the error handler, firstly make sure you have included the class, then add
    PHP Code:
    set_error_handler( array('errorHandler','live') ); 
    or for debugging purposes you could use
    PHP Code:
    set_error_handler( array('errorHandler','debug') ); 
    ps. the directory the specified log file is in must be writable. On RF, if it is outside the web root, you still need to make the directory writable - just send the standard chmod requests, and although they don't strictly speaking chmod, they do enough of something!

    Right, I've added some commenting, but just ask if you want a better explaination.
    PHP Code:
    <?php
    /**
     * This script may be used and modified by anyone, though I take no 
     * liabilities resulting from its usage. The script has not been rigorously
     * tested.
     *
     * @author Nick Thornley Feb 2006 <nick@quesmedia.com>
     */
     
    /**
     * errorHandler class, to be used in replace of PHP's default error handler
     *
     * Live mode implementation:
     * set_error_handler( array('errorHandler','live') );
     *
     * Debug Mode implementation:
     * set_error_handler( array('errorHandler','debug') );
     * 
     */
    class errorHandler
    {
        
    /**
         * @var string absolute path to the log file
         */
        
    private static $log_file 'D:\yoursite.com\phplogs\current.log';
        
    /**
         * @var int size at which to start new log file and archive the old (bytes)
         */
        
    private static $max_filesize 10000;
        
    /**
         * @var string used to store any handler error messages
         */
        
    private static $handler_error;
        
    /**
         * @var string date format string - follows standard date formatting rules
         */
        
    private static $dateformat 'r';
        
    /**
         * @var string seperator between error information in the log
         */
        
    private static $seperator ' ';
        
    /**
         * @var string An nice (un)informative error message to display the public
         */
        
    private static $fatal_mssg 'Our site is experiencing temporary problems.';
        

            
            
        
    /**
         * Callback function to be used to log errors a live site
         *
         * @return bool
         */
        
    public static function live()
        {
            
    //grab the error array from the function arguments
            
    $e func_get_args();
            
            
    //create an array of information we would like to log
            
    $output[] = "[".date(self::$dateformat)."]";
            
    $output[] = $e[0]; //error number
            
    $output[] = $e[2]; //file
            
    $output[] = $e[3]; //line
            
    $output[] = $e[1]; //error message
            //create a string out of the output array
            
    $output implode(self::$seperator,$output);
            
    $output .= "\n";
            
            
    //Call the function to write to the log file
            
    if(self::_writeLogFile($output) === false){
                
    //help, the error logging function has a problem
                //the error has not been logged.
                //an error message is held in the var self::$handler_error
                
    return false;
            }
            
            
    //The following switch statement can be used to provide feedback to the
            //user browsing the site, dependent on the type of error
            
    switch( $e[0] )
            {
                case 
    E_NOTICE:
                case 
    E_WARNING:
                case 
    E_STRICT:
                case 
    E_USER_NOTICE:
                case 
    E_USER_WARNING:
                    
    //do nothing, as the error is not fatal
                
    break;
                
                default:
                    
    //fatal error, so clear any output buffers, display the error
                    //message and exit the script.
                    
    if(ob_get_level()){
                        while (@
    ob_end_clean());
                    }
                    echo 
    self::$fatal_mssg;
                    die();
            }
            return 
    true;
        }
        
    /**/
        
        
        
        
        /**
         * Callback function to be used to display errors to screen for debugging
         *
         * @return bool
         */
        
    public static function debug()
        {
            
    //grab the error array from the function arguments
            
    $e func_get_args();
            
            
    //The following switch statement can be used to provide feedback to the
            //user browsing the site, dependent on the type of error
            
    switch( $e[0] )
            {
                case 
    E_NOTICE:
                case 
    E_WARNING:
                case 
    E_STRICT:
                case 
    E_USER_NOTICE:
                case 
    E_USER_WARNING:
                    
    //non-fatal error, just output a simple inline message
                    
    echo '<span class="error">';
                    echo 
    'Error ('.$e[0].') on line '.$e[3].' - '.$e[2].' - ';
                    echo 
    htmlspecialchars($e[1]);
                    echo 
    '</span> ';
                break;
                
                default:
                    
    //fatal error, so print out the full error array and exit.
                    //the output buffer has not been cleared, so any content already
                    //output will be displayed prior to the error message
                    
    echo "<pre>error:";
                    
    print_r($e);
                    echo 
    "</pre>";
                    die();
            }
            
            return 
    true;
        }
        
    /**/ 


    //============ PRIVATE CLASS FUNCTIONS FOR FILE MANIPULATION =============//



        /**
         * Writes data to a file, by default the it overwrites the previous file
         *
         * @param string absolute file path
         * @param string data to write to file
         * @param string file open more - default 'wb'
         *
         * @return bool
         */
        
    private static function _writeFile($file$data$mode='wb')
        {
            if (!
    $handle fopen($file$mode)) {
                
    self::$handler_error "Cannot open file ($filename)";
                return 
    false;
            }
            
            if (
    fwrite($handle$data) === FALSE) {
                
    self::$handler_error "Cannot write file ($filename)";
                return 
    false;
            }
            
    fclose($handle);
            return 
    true;
        }

        
        
    /**
         * creates and subsequently appends data to the log file.
         *
         * If the log file exceeds the maximum allowed size, the archiveLogFile
         * function will be called to archive the log and start a fresh file.
         *
         * @param string data to write to file
         *
         * @return bool
         */
        
    private static function _writeLogFile$data )
        {
            
    //if the log file exists but exceeds the maximum size,
            
    if( is_file(self::$log_file
                && 
                
    filesize(self::$log_file) > self::$max_filesize ){
                
    //attempt to create an archive copy of the log file
                
    if(!self::_archiveLogFile(self::$log_file)) {
                    return 
    false;
                }
            }
            
    //append/create file with data
            
    return self::_writeFile(self::$log_file$data'ab');
        }


        
    /**
         * Simply returns the contents of a file as a string
         *
         * @param string absolute file path
         *
         * @return string file contents, or false if an error was encountered
         */
        
    private static function _readFileContents($file)
        {
            if (!
    $handle fopen($file'rb')) {
                
    self::$handler_error "Cannot open file ($filename)";
                return 
    false;
            }
            
            if (!
    $contents fread($handlefilesize($file))) {
                
    self::$handler_error "Cannot read file ($filename)";
                return 
    false;
            }

            
    fclose($handle);
            return 
    $contents;
        }

        
    /**
         * Creates a compressed copy of a file + deletes the original (if sucessful)
         *
         * @param string absolute file path
         *
         * @return bool
         */    
        
    private static function _archiveLogFile($file)
        {
            
    //regexp pattern to strip of filename from file path
            
    $pattern '/([^\/\]*.$)/';
            
    //replacement file name
            
    $replacment time().'.gz';
            
    $archivefile preg_replace($pattern$replacment,$file);
            
            
    //read current log file into $contents
            
    $contents self::_readFileContents($file);
            if(
    $contents === false){
                return 
    false;
            }
            
            
    //write new compressed archived file with content
            
    self::_writeFile($archivefilegzencode($contents,9), 'wb');
            if(!
    is_file($file)){
                return 
    false;
            }
            
    //delete the original file
            
    unlink($file);
            return 
    true;
        }
        
    }
    //end errorHandler class definition
    ?>
    pps. Warren, it's damn annoying that these code boxes wrap at less than 80 characters width!

  2. #2
    Join Date
    Feb 2004
    Posts
    4,877
    Thanks
    2
    Thanked 134 Times in 113 Posts

    Default

    Quote Originally Posted by nick
    pps. Warren, it's damn annoying that these code boxes wrap at less than 80 characters width!
    Fixed

    Nice code by the way...
    Warren Ashcroft
    Red Fox UK Limited - Pioneers in Internet Technology
    http://www.redfoxuk.com
    w.ashcroft [at] redfoxuk.com

    NOTE: Forum Private Messaging should not be used to contact staff with support queries.

  3. #3
    Join Date
    Mar 2005
    Location
    Isle of Man
    Posts
    1,261
    Thanks
    3
    Thanked 23 Times in 23 Posts

    Default

    Quote Originally Posted by Warren Ashcroft
    Fixed

    Nice code by the way...
    thanks x 2

  4. #4
    Join Date
    Sep 2005
    Posts
    190
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Default

    Thanks, the coding is a bit beyond me but I may well try to use this in time (I'm unwell at the moment but should be ready to try it in a few days time) as I am another who (which I think was what you picked up on in the mysql thread) who churns out the db error messages, not handling things nicely. Something I could just "include" would be nice. It looks as if it could be realy useful.

  5. #5
    Join Date
    Mar 2005
    Location
    Isle of Man
    Posts
    1,261
    Thanks
    3
    Thanked 23 Times in 23 Posts

    Default

    Quote Originally Posted by Jon Freeman
    Thanks, the coding is a bit beyond me but I may well try to use this in time (I'm unwell at the moment but should be ready to try it in a few days time) as I am another who (which I think was what you picked up on in the mysql thread) who churns out the db error messages, not handling things nicely. Something I could just "include" would be nice. It looks as if it could be realy useful.
    Hope you feel better very soon.
    Let me know if you run into problems getting it working.

  6. #6
    Join Date
    Sep 2005
    Posts
    190
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by nick
    Hope you feel better very soon.
    Let me know if you run into problems getting it working.
    Thanks, either way, I will try to let you know how it works for me.

  7. #7
    Join Date
    Mar 2005
    Location
    Isle of Man
    Posts
    1,261
    Thanks
    3
    Thanked 23 Times in 23 Posts

    Default

    I think I have spotted a typo in my original script, I'm pretty sure I will have meant
    PHP Code:
    //write new compressed archived file with content 
            
    self::_writeFile($archivefilegzencode($contents,9), 'wb'); 
            if(!
    is_file($file)){ 
                return 
    false
            } 
    to be
    PHP Code:
    //write new compressed archived file with content 
            
    self::_writeFile($archivefilegzencode($contents,9), 'wb'); 
            if(!
    is_file($archivefile)){
                return 
    false
            } 
    This way it is checking that the archived file has been created, before deleting the original.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Custom error pages.....
    By jigsawsrusdotcom in forum Sales and Service Feature Enquiries
    Replies: 5
    Last Post: 17th November 2006, 04:54 PM
  2. PHP :: Parse error
    By AndyHearne in forum PHP
    Replies: 15
    Last Post: 11th December 2005, 09:33 PM
  3. Replies: 16
    Last Post: 2nd December 2005, 05:09 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •