eZ Publish  [trunk]
ezexecution.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZExecution class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package lib
00009  */
00010 
00011 /*!
00012   \class eZExecution ezexecution.php
00013   \brief Handles proper script execution, fatal error detection and handling.
00014 
00015   By registering a fatal error handler it's possible for the PHP script to
00016   catch fatal errors, such as "Call to a member function on a non-object".
00017 
00018   By registering a cleanup handler it's possible to make sure the script can
00019   end properly.
00020 */
00021 
00022 class eZExecution
00023 {
00024     /*!
00025      Sets the clean exit flag to on,
00026      this notifies the exit handler that everything finished properly.
00027     */
00028     static function setCleanExit()
00029     {
00030         self::$hasCleanExit = true;
00031     }
00032 
00033     /*!
00034      Calls the cleanup handlers to make sure that the script is ready to exit.
00035     */
00036     static function cleanup()
00037     {
00038         $handlers = eZExecution::cleanupHandlers();
00039         foreach ( $handlers as $handler )
00040         {
00041             if ( is_callable( $handler ) )
00042                 call_user_func( $handler );
00043             else
00044                 eZDebug::writeError('Could not call cleanup handler, is it a static public function?', __METHOD__ );
00045         }
00046     }
00047 
00048     /*!
00049      Adds a cleanup handler to the end of the list,
00050      \a $handler must contain the name of the function to call.
00051      The function is called at the end of the script execution to
00052      do some cleanups.
00053     */
00054     static function addCleanupHandler( $handler )
00055     {
00056         self::registerShutdownHandler();
00057         self::$cleanupHandlers[] = $handler;
00058     }
00059 
00060     /*!
00061      \return An array with cleanup handlers.
00062     */
00063     static function cleanupHandlers()
00064     {
00065         return self::$cleanupHandlers;
00066     }
00067 
00068     /*!
00069      Adds a fatal error handler to the end of the list,
00070      \a $handler must contain the name of the function to call.
00071      The handler will be called whenever a fatal error occurs,
00072      which usually happens when the script did not finish.
00073     */
00074     static function addFatalErrorHandler( $handler )
00075     {
00076         self::registerShutdownHandler();
00077         self::$fatalErrorHandlers[] = $handler;
00078     }
00079 
00080     /*!
00081      \return An array with fatal error handlers.
00082     */
00083     static function fatalErrorHandlers()
00084     {
00085         return self::$fatalErrorHandlers;
00086     }
00087 
00088     /*!
00089      \return true if the request finished properly.
00090     */
00091     static function isCleanExit()
00092     {
00093         return self::$hasCleanExit;
00094     }
00095 
00096     /*!
00097      Sets the clean exit flag and exits the page.
00098      Use this if you want premature exits instead of the \c exit function.
00099     */
00100     static function cleanExit()
00101     {
00102         eZExecution::cleanup();
00103         eZExecution::setCleanExit();
00104         exit;
00105     }
00106 
00107     /*!
00108      Exit handler which called after the script is done, if it detects
00109      that eZ Publish did not exit cleanly it will issue an error message
00110      and display the debug.
00111     */
00112     static function uncleanShutdownHandler()
00113     {
00114         // Need to change the current directory, since this information is lost
00115         // when the callbackfunction is called. eZDocumentRoot is set in ::registerShutdownHandler
00116         if ( self::$eZDocumentRoot !== null )
00117         {
00118             chdir( self::$eZDocumentRoot );
00119         }
00120 
00121         if ( eZExecution::isCleanExit() )
00122             return;
00123         eZExecution::cleanup();
00124         $handlers = eZExecution::fatalErrorHandlers();
00125         foreach ( $handlers as $handler )
00126         {
00127             if ( is_callable( $handler ) )
00128                 call_user_func( $handler );
00129             else
00130 
00131                 eZDebug::writeError('Could not call fatal error handler, is it a static public function?', __METHOD__ );
00132         }
00133     }
00134 
00135     /*!
00136      Register ::uncleanShutdownHandler as shutdown function
00137     */
00138     static public function registerShutdownHandler( $documentRoot = false )
00139     {
00140         if ( !self::$shutdownHandle )
00141         {
00142             register_shutdown_function( array('eZExecution', 'uncleanShutdownHandler') );
00143             /*
00144                 see:
00145                 - http://www.php.net/manual/en/function.session-set-save-handler.php
00146                 - http://bugs.php.net/bug.php?id=33635
00147                 - http://bugs.php.net/bug.php?id=33772
00148             */
00149             register_shutdown_function( array('eZSession', 'stop') );
00150             set_exception_handler( array('eZExecution', 'defaultExceptionHandler') );
00151             self::$shutdownHandle = true;
00152         }
00153 
00154         // Needed by the error handler, since the current directory is lost when
00155         // the callback function eZExecution::uncleanShutdownHandler is called.
00156         if ( $documentRoot )
00157         {
00158             self::$eZDocumentRoot = $documentRoot;
00159         }
00160         else if ( self::$eZDocumentRoot === null )
00161         {
00162             self::$eZDocumentRoot = getcwd();
00163         }
00164     }
00165 
00166     /**
00167      * Installs the default Exception handler
00168      *
00169      * @params Exception the exception
00170      * @return void
00171      */
00172     static public function defaultExceptionHandler( Exception $e )
00173     {
00174         if( PHP_SAPI != 'cli' )
00175         {
00176             header( 'HTTP/1.x 500 Internal Server Error' );
00177             header( 'Content-Type: text/html' );
00178 
00179             echo "An unexpected error has occurred. Please contact the webmaster.<br />";
00180 
00181             if( eZDebug::isDebugEnabled() )
00182             {
00183                 echo $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine();
00184             }
00185         }
00186         else
00187         {
00188             $cli = eZCLI::instance();
00189             $cli->error( "An unexpected error has occurred. Please contact the webmaster.");
00190 
00191             if( eZDebug::isDebugEnabled() )
00192             {
00193                 $cli->error( $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine() );
00194             }
00195         }
00196 
00197         eZLog::write( 'Unexpected error, the message was : ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine(), 'error.log' );
00198 
00199         eZExecution::cleanup();
00200         eZExecution::setCleanExit();
00201         exit( 1 );
00202     }
00203 
00204     static private $eZDocumentRoot = null;
00205     static private $hasCleanExit = false;
00206     static private $shutdownHandle = false;
00207     static private $fatalErrorHandlers = array();
00208     static private $cleanupHandlers = array();
00209 }
00210 
00211 
00212 ?>