* @license PHP License * @package WB * @subpackage base */ /** * specific handler for php errors * * This class handles all PHP errors and reports them to the logger * * The static constructor @link staticConstruct() switches on error reporting * based on parameter "wb/error/reporting". * * Also there is a feature to supress annoying STRICT warnings of third party * libraries such as PEAR (@link http://pear.php.net). Those PHP classes * usually are installed somewhere in the "include_path" * (@link http://php.net/get_include_path), all E_STRICT warnings from one of * those pathes (except ".") will be ignored. * * This also listens to the following parameters * - "wb/error/reporting" sets error erporting (Default: "E_ERROR | E_WARNING") * - "wb/error/ignoreincludepath" * * @version 0.2.2 * @package WB * @subpackage base */ class WBErrorHandler_Php extends WBErrorHandler implements WBParam_Observer { /** * include path * @var array */ protected $includePath = array(); /** * list of erros to be ignored next time * @var array */ static protected $_expect = array(); /** * handle legay PHP4 error * * - "ignore" * - "log" * - "backtrace" * * @var string */ protected $handlePhp4 = 'log'; /** * add error to be expect * * @param string $msg * @return bool true on success */ static public function expect( $msg ) { self::$_expect[] = $msg; return true; } /** * Static constructor * * Sets up error handler */ static public function staticConstruct() { $me = new WBErrorHandler_Php(); set_error_handler(array($me, 'handle')); } /** * private constructor * * setup as parameter observer */ private function __construct() { // preset parameter $ignoreIncludePath = WBParam::get('wb/error/ignoreincludepath', 1); WBParam::set('wb/error/ignoreincludepath', $ignoreIncludePath); $this->setIgnoreIncludePath($ignoreIncludePath); error_reporting(WBParam::get('wb/error/reporting', E_ERROR | E_WARNING)); $this->handlePhp4 = WBParam::get('wb/error/php4', $this->handlePhp4); // see wheather include path was changed WBParam::attach('wb/class/phpincludepath', $this); // listen to parameter WBParam::attach('wb/error/reporting', $this); WBParam::attach('wb/error/ignoreincludepath', $this); WBParam::attach('wb/error/php4', $this); } /** * Interface on set for parameter * * Implement things to be done when parameter is set * * @param string $name * @param mixed $value * @return bool true on success */ public function notifyOnSet($name, $value) { switch( $name ) { case 'wb/error/reporting'; error_reporting($value); break; case 'wb/class/phpincludepath'; $this->setIgnoreIncludePath(WBParam::get('wb/error/ignoreincludepath'), $value); break; case 'wb/error/ignoreincludepath'; $this->setIgnoreIncludePath($value); break; case 'wb/error/php4'; $this->handlePhp4 = strtolower($value); break; default: break; } return true; } /** * extract folders to ignore from include_path * * Usually this is called when parameter changes * * @param bool $ignore * @return bool true on success */ protected function setIgnoreIncludePath($ignore = true, $includePath = null) { $this->includePath = array(); if(!$ignore) { return true; } // get include path from ini parameter if(!is_array($includePath)) { $includePath = explode(PATH_SEPARATOR, get_include_path()); } // remove "." foreach ($includePath as $path) { if ($path == '.') { continue; } $this->includePath[] = realpath($path); } return true; } /** * take care of PHP errors * * Ignore some well knwon errors * * @param int $no error level number * @param string $str error string * @param string $file causing file * @param int $line causing line * @return void sometimes the process is ended * @see set_error_handler() */ public function handle($no, $str, $file, $line) { while (!empty(self::$_expect)) { $expected = array_shift(self::$_expect); if (strncmp($expected, $str, strlen($expected)) == 0) { self::$_expect = array(); return; } } self::$_expect = array(); // only if error reporting is on $er = error_reporting(); if (!($no & $er)) { return; } $log = array( 'type' => 'php', 'msg' => $str, 'file' => $file, 'line' => $line, ); // remove the first entry, cause it show call to this function $backtrace = debug_backtrace(); array_shift($backtrace); $useLogger = $this->checkLogger(); $level = ''; switch ($no) { case E_ERROR; case E_USER_ERROR; $level = 'Error'; // fall through case E_WARNING; case E_USER_WARNING; if (!$level) { $level = 'Warning'; } // fall through case E_NOTICE; case E_USER_NOTICE; if (!$level) { $level = 'Notice'; } // ignore all notices from include_path if (!empty($this->includePath)) { foreach ($this->includePath as $path) { if (strncmp($path, $file, strlen($path)) == 0) { return; } } } if ($useLogger) { WBLog::start('error')->err($log); $this->logBacktrace($backtrace); } break; case E_DEPRECATED: case E_USER_DEPRECATED: $level = 'Deprecated'; // fall through case E_STRICT; if (!$level) { $level = 'Strict'; } if (!$useLogger) { return; } // ignore all strict warning from include_path if (!empty($this->includePath)) { foreach ($this->includePath as $path) { if (strncmp($path, $file, strlen($path)) == 0) { return; } } } // ignore PAT classes if (preg_match('|/pat(.*)\.php$|', $file)) { return; } /* * Ignore some well known error messages, caused by PHP4ish classes * * "Non-static method PEAR::isError() should not be called statically, assuming $this from incompatible context" * "Non-static method patForms::xyz() should not be called statically, assuming $this from incompatible context" * "Non-static method patTemplate::xyz() should not be called statically, assuming $this from incompatible context" */ if (strncmp('Non-static method ', $str, 18) == 0) { // PEAR, patForms and patTemplate if (strncmp('Non-static method PEAR::isError()', $str, 33) == 0 || strncmp('Non-static method patForms::', $str, 28) == 0 || strncmp('Non-static method patTemplate::', $str, 31) == 0 ) { $log['type'] = 'php4'; switch ($this->handlePhp4) { case 'ignore': return; break; case 'backtrace': break; default: case 'log': WBLog::start('error')->debug($log); return; break; } } } WBLog::start('error')->info($log); $this->logBacktrace($backtrace); break; default: $level = 'unknown'; break; } // halt? if (WBParam::get('wb/error/killlevel', E_ERROR) >= $no) { $this->kill(); } return; } } ?>