<?php class TErrorHandler extends TComponent implements IModule { const ERROR_FILE_NAME='error'; const EXCEPTION_FILE_NAME='exception'; /** * @var string module ID */ private $_id; /** * @var TApplication application instance */ private $_application; /** * @var string error template directory */ private $_templatePath=null; /** * Initializes the module. * This method is required by IModule and is invoked by application. * @param TApplication application * @param TXmlElement module configuration */ public function init($application,$config) { $this->_application=$application; $application->attachEventHandler('Error',array($this,'handleError')); $application->setErrorHandler($this); } /** * @return string id of this module */ public function getID() { return $this->_id; } /** * @param string id of this module */ public function setID($value) { $this->_id=$value; } public function getErrorTemplatePath() { return $this->_templatePath; } public function setErrorTemplatePath($value) { if(($templatePath=Prado::getPathOfNamespace($this->_templatePath))!==null && is_dir($templatePath)) $this->_templatePath=$templatePath; else throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); } public function handleError($sender,$param) { static $handling=false; // We need to restore error and exception handlers, // otherwise because errors occured in error handler // will not be handled properly. restore_error_handler(); restore_exception_handler(); if($handling) // ensure that we do not enter infinite loop of error handling $this->handleRecursiveError($param); else { $handling=true; if(($response=Prado::getApplication()->getResponse())!==null) $response->clear(); if($param instanceof THttpException) $this->handleExternalError($param->getStatusCode(),$param); else if(Prado::getApplication()->getMode()==='Debug') $this->displayException($param); else $this->handleExternalError(500,$param); } exit(1); } protected function handleExternalError($statusCode,$exception) { if(!($exception instanceof THttpException)) error_log($exception->__toString()); if($this->_templatePath===null) $this->_templatePath=dirname(__FILE__); $base=$this->_templatePath.'/'.self::ERROR_FILE_NAME; $lang=array_shift(explode('-',array_shift(Prado::getUserLanguages()))); if(!empty($lang) && !ctype_alpha($lang)) die('No hack attempt please.'); if(is_file("$base$statusCode-$lang.tpl")) $errorFile="$base$statusCode-$lang.tpl"; else if(is_file("$base$statusCode.tpl")) $errorFile="$base$statusCode.tpl"; else if(is_file("$base-$lang.tpl")) $errorFile="$base-$lang.tpl"; else $errorFile="$base.tpl"; if(($content=@file_get_contents($errorFile))===false) die("Unable to open error template file '$errorFile'."); $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:''; $fields=array( '%%StatusCode%%', '%%ErrorMessage%%', '%%ServerAdmin%%', '%%Version%%', '%%Time%%' ); $values=array( "$statusCode", htmlspecialchars($exception->getMessage()), $serverAdmin, $_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion(), strftime('%Y-%m-%d %H:%m',time()) ); echo str_replace($fields,$values,$content); } protected function handleRecursiveError($exception) { if(Prado::getApplication()->getMode()==='Debug') { echo "<html><head><title>Recursive Error</title></head>\n"; echo "<body><h1>Recursive Error</h1>\n"; echo "<pre>".$exception."</pre>\n"; echo "</body></html>"; } else { error_log("Error happened while processing an existing error:\n".$param->__toString()); header('HTTP/1.0 500 Internal Error'); } } protected function displayException($exception) { $lines=file($exception->getFile()); $errorLine=$exception->getLine(); $beginLine=$errorLine-9>=0?$errorLine-9:0; $endLine=$errorLine+8<=count($lines)?$errorLine+8:count($lines); $source=''; for($i=$beginLine;$i<$endLine;++$i) { if($i===$errorLine-1) { $line=highlight_string(sprintf("Line %4d: %s",$i+1,$lines[$i]),true); $source.="<div style=\"background-color: #ffeeee\">".$line."</div>"; } else $source.=highlight_string(sprintf("Line %4d: %s",$i+1,$lines[$i]),true); } $fields=array( '%%ErrorType%%', '%%ErrorMessage%%', '%%SourceFile%%', '%%SourceCode%%', '%%StackTrace%%', '%%Version%%', '%%Time%%' ); $values=array( get_class($exception), htmlspecialchars($exception->getMessage()), htmlspecialchars($exception->getFile()).' ('.$exception->getLine().')', $source, htmlspecialchars($exception->getTraceAsString()), $_SERVER['SERVER_SOFTWARE'].' <a href="http://www.pradosoft.com/">PRADO</a>/'.Prado::getVersion(), strftime('%Y-%m-%d %H:%m',time()) ); $lang=array_shift(explode('-',array_shift(Prado::getUserLanguages()))); if(!empty($lang) && !ctype_alpha($lang)) die('No hack attempt please.'); $exceptionFile=dirname(__FILE__).'/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.tpl'; if(!is_file($exceptionFile)) $exceptionFile=dirname(__FILE__).'/'.self::EXCEPTION_FILE_NAME.'.tpl'; if(($content=@file_get_contents($exceptionFile))===false) die("Unable to open exception template file '$exceptionFile'."); echo str_replace($fields,$values,$content); } } ?>