_prev_ex_handler = $prev_ex_handler; } /** * Store error handler that was previously set * * @param callable|null $_prev_er_handler * * @return void Method does not return */ public function set_prev_er_handler( $prev_er_handler ) { $this->_prev_er_handler = $prev_er_handler; } /** * Constructor accepts names of classes to be handled * * @param string $exception_class Name of exceptions base class to handle * @param string $error_class Name of errors base class to handle * * @return void Constructor newer returns */ public function __construct( $exception_class, $error_class ) { $this->_exception_class = $exception_class; $this->_error_exception_class = $error_class; $this->_nonfatal_errors = array( E_USER_WARNING => true, E_WARNING => true, E_USER_NOTICE => true, E_NOTICE => true, E_STRICT => true, ); if ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) { // wrapper `constant( 'XXX' )` is used to avoid compile notices // on earlier PHP versions. $this->_nonfatal_errors[constant( 'E_DEPRECATED' )] = true; $this->_nonfatal_errors[constant( 'E_USER_DEPRECATED') ] = true; } } /** * Global exceptions handling method * * @param Exception $exception Previously thrown exception to handle * * @return void Exception handler is not expected to return */ public function handle_exception( Exception $exception ) { if ( defined( 'AI1EC_DEBUG' ) && true === AI1EC_DEBUG ) { echo '
';
			var_dump( $exception );
			echo '
'; die(); } // if it's something we handle, handle it $backtrace = '

' . nl2br( $exception ); if ( $exception instanceof $this->_exception_class ) { // check if it has a methof for deatiled html $message = method_exists( $exception, 'get_html_message' ) ? $exception->get_html_message() : $exception->getMessage(); $this->soft_deactivate_plugin( $message . $backtrace ); } // if it's a PHP error in our plugin files, deactivate and redirect else if ( $exception instanceof $this->_error_exception_class ) { $this->soft_deactivate_plugin( $exception->getMessage() . $backtrace ); } // if another handler was set, let it handle the exception if ( is_callable( $this->_prev_ex_handler ) ) { call_user_func( $this->_prev_ex_handler, $exception ); } } /** * Throws an Ai1ec_Error_Exception if the error comes from our plugin * * @param int $errno Error level as integer * @param string $errstr Error message raised * @param string $errfile File in which error was raised * @param string $errline Line in which error was raised * @param array $errcontext Error context symbols table copy * * @throws Ai1ec_Error_Exception If error originates from within Ai1EC * * @return boolean|void Nothing when error is ours, false when no * other handler exists */ public function handle_error( $errno, $errstr, $errfile, $errline, $errcontext ) { // if the error is not in our plugin, let PHP handle things. if ( false === strpos( $errfile, AI1EC_PLUGIN_NAME ) ) { if ( is_callable( $this->_prev_er_handler ) ) { return call_user_func_array( $this->_prev_er_handler, func_get_args() ); } return false; } // do not disable plugin in production if the error is rather low if ( isset( $this->_nonfatal_errors[$errno] ) && ( ! defined( 'AI1EC_DEBUG' ) || false === AI1EC_DEBUG ) ) { $message = sprintf( 'All-in-One Event Calendar: %s @ %s:%d #%d', $errstr, $errfile, $errline, $errno ); return error_log( $message, 0 ); } throw new Ai1ec_Error_Exception( $errstr, $errno, 0, $errfile, $errline ); } /** * Perform what's needed to deactivate the plugin softly * * @param string $message Error message to be displayed to admin * * @return void Method does not return */ protected function soft_deactivate_plugin( $message ) { add_option( self::DB_DEACTIVATE_MESSAGE, $message ); $this->redirect(); } /** * Perform what's needed to reactivate the plugin * * @return boolean Success */ public function reactivate_plugin() { return delete_option( self::DB_DEACTIVATE_MESSAGE ); } /** * Get message to be displayed to admin if any * * @return string|boolean Error message or false if plugin is not disabled */ public function get_disabled_message() { global $wpdb; $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", self::DB_DEACTIVATE_MESSAGE ) ); if ( is_object( $row ) ) { return $row->option_value; } else { // option does not exist, so we must cache its non-existence return false; } } /** * Add an admin notice * * @param string $message Message to be displayed to admin * * @return void Method does not return */ public function show_notices( $message ) { // save the message to use it later $this->_message = $message; add_action( 'admin_notices', array( $this, 'render_admin_notice' ) ); } /** * Render HTML snipped to be displayd as a notice to admin * * @hook admin_notices When plugin is soft-disabled * * @return void Method does not return */ public function render_admin_notice() { $redirect_url = add_query_arg( self::DB_REACTIVATE_PLUGIN, 'true', get_admin_url( $_SERVER['REQUEST_URI'] ) ); $label = __( 'All In One Event Calendar has been disabled due to an error:', AI1EC_PLUGIN_NAME ); $message = '
'. '

' . $label . '

' . '

' . $this->_message . '

'; $message .= sprintf( __( '

If you corrected the error and wish to try reactivating the plugin, click here.

', AI1EC_PLUGIN_NAME ), $redirect_url ); $message .= '
'; echo $message; } /** * Redirect the user either to the front page or the dashbord page * * @return void Method does not return */ protected function redirect() { if ( is_admin() ) { Ai1ec_Http_Response_Helper::redirect( get_admin_url() ); } else { Ai1ec_Http_Response_Helper::redirect( get_site_url() ); } } }