From 903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Thu, 12 Jul 2012 11:21:01 +0000 Subject: standardize the use of unix eol; use svn properties to enforce native eol --- framework/Exceptions/TErrorHandler.php | 826 ++++++++++++++++---------------- framework/Exceptions/TException.php | 832 ++++++++++++++++----------------- 2 files changed, 829 insertions(+), 829 deletions(-) (limited to 'framework/Exceptions') diff --git a/framework/Exceptions/TErrorHandler.php b/framework/Exceptions/TErrorHandler.php index 7940fcae..f105cd1a 100644 --- a/framework/Exceptions/TErrorHandler.php +++ b/framework/Exceptions/TErrorHandler.php @@ -1,413 +1,413 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Exceptions - */ - -/** - * TErrorHandler class - * - * TErrorHandler handles all PHP user errors and exceptions generated during - * servicing user requests. It displays these errors using different templates - * and if possible, using languages preferred by the client user. - * Note, PHP parsing errors cannot be caught and handled by TErrorHandler. - * - * The templates used to format the error output are stored under System.Exceptions. - * You may choose to use your own templates, should you not like the templates - * provided by Prado. Simply set {@link setErrorTemplatePath ErrorTemplatePath} - * to the path (in namespace format) storing your own templates. - * - * There are two sets of templates, one for errors to be displayed to client users - * (called external errors), one for errors to be displayed to system developers - * (called internal errors). The template file name for the former is - * error[StatusCode][-LanguageCode].html, and for the latter it is - * exception[-LanguageCode].html, where StatusCode refers to response status - * code (e.g. 404, 500) specified when {@link THttpException} is thrown, - * and LanguageCode is the client user preferred language code (e.g. en, zh, de). - * The templates error.html and exception.html are default ones - * that are used if no other appropriate templates are available. - * Note, these templates are not Prado control templates. They are simply - * html files with keywords (e.g. %%ErrorMessage%%, %%Version%%) - * to be replaced with the corresponding information. - * - * By default, TErrorHandler is registered with {@link TApplication} as the - * error handler module. It can be accessed via {@link TApplication::getErrorHandler()}. - * You seldom need to deal with the error handler directly. It is mainly used - * by the application object to handle errors. - * - * TErrorHandler may be configured in application configuration file as follows - * - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TErrorHandler extends TModule -{ - /** - * error template file basename - */ - const ERROR_FILE_NAME='error'; - /** - * exception template file basename - */ - const EXCEPTION_FILE_NAME='exception'; - /** - * number of lines before and after the error line to be displayed in case of an exception - */ - const SOURCE_LINES=12; - - /** - * @var string error template directory - */ - private $_templatePath=null; - - /** - * Initializes the module. - * This method is required by IModule and is invoked by application. - * @param TXmlElement module configuration - */ - public function init($config) - { - $this->getApplication()->setErrorHandler($this); - } - - /** - * @return string the directory containing error template files. - */ - public function getErrorTemplatePath() - { - if($this->_templatePath===null) - $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; - return $this->_templatePath; - } - - /** - * Sets the path storing all error and exception template files. - * The path must be in namespace format, such as System.Exceptions (which is the default). - * @param string template path in namespace format - * @throws TConfigurationException if the template path is invalid - */ - public function setErrorTemplatePath($value) - { - if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) - $this->_templatePath=$templatePath; - else - throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); - } - - /** - * Handles PHP user errors and exceptions. - * This is the event handler responding to the Error event - * raised in {@link TApplication}. - * The method mainly uses appropriate template to display the error/exception. - * It terminates the application immediately after the error is displayed. - * @param mixed sender of the event - * @param mixed event parameter (if the event is raised by TApplication, it refers to the exception instance) - */ - public function handleError($sender,$param) - { - static $handling=false; - // We need to restore error and exception handlers, - // because within error and exception handlers, new errors and exceptions - // cannot be handled properly by PHP - restore_error_handler(); - restore_exception_handler(); - // ensure that we do not enter infinite loop of error handling - if($handling) - $this->handleRecursiveError($param); - else - { - $handling=true; - if(($response=$this->getResponse())!==null) - $response->clear(); - if(!headers_sent()) - header('Content-Type: text/html; charset=UTF-8'); - if($param instanceof THttpException) - $this->handleExternalError($param->getStatusCode(),$param); - else if($this->getApplication()->getMode()===TApplicationMode::Debug) - $this->displayException($param); - else - $this->handleExternalError(500,$param); - } - } - - - /** - * @param string $value - * @param Exception|null$exception - * @return string - * @since 3.1.6 - */ - protected static function hideSecurityRelated($value, $exception=null) - { - $aRpl = array(); - if($exception !== null && $exception instanceof Exception) - { - $aTrace = $exception->getTrace(); - foreach($aTrace as $item) - { - if(isset($item['file'])) - $aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '' . DIRECTORY_SEPARATOR; - } - } - $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}'; - $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}'; - $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR; - if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]); - $aRpl = array_reverse($aRpl, true); - - return str_replace(array_keys($aRpl), $aRpl, $value); - } - - /** - * Displays error to the client user. - * THttpException and errors happened when the application is in Debug - * mode will be displayed to the client user. - * @param integer response status code - * @param Exception exception instance - */ - protected function handleExternalError($statusCode,$exception) - { - if(!($exception instanceof THttpException)) - error_log($exception->__toString()); - - $content=$this->getErrorTemplate($statusCode,$exception); - - $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:''; - - $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug; - - $errorMessage = $exception->getMessage(); - if($isDebug) - $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); - else - { - $version=''; - $errorMessage = self::hideSecurityRelated($errorMessage, $exception); - } - $tokens=array( - '%%StatusCode%%' => "$statusCode", - '%%ErrorMessage%%' => htmlspecialchars($errorMessage), - '%%ServerAdmin%%' => $serverAdmin, - '%%Version%%' => $version, - '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) - ); - - $CGI=substr(php_sapi_name(), 0, 3) == 'cgi'; // FastCGI / IIS - if($isDebug) - { - if ($CGI) - header("Status: $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode)); - else - header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode)); - } else { - if ($CGI) - header("Status: $statusCode", true, TPropertyValue::ensureInteger($statusCode)); - else - header("HTTP/1.0 $statusCode", true, TPropertyValue::ensureInteger($statusCode)); - } - - echo strtr($content,$tokens); - } - - /** - * Handles error occurs during error handling (called recursive error). - * THttpException and errors happened when the application is in Debug - * mode will be displayed to the client user. - * Error is displayed without using existing template to prevent further errors. - * @param Exception exception instance - */ - protected function handleRecursiveError($exception) - { - if($this->getApplication()->getMode()===TApplicationMode::Debug) - { - echo "Recursive Error\n"; - echo "

Recursive Error

\n"; - echo "
".$exception->__toString()."
\n"; - echo ""; - } - else - { - error_log("Error happened while processing an existing error:\n".$exception->__toString()); - header('HTTP/1.0 500 Internal Error'); - } - } - - /** - * Displays exception information. - * Exceptions are displayed with rich context information, including - * the call stack and the context source code. - * This method is only invoked when application is in Debug mode. - * @param Exception exception instance - */ - protected function displayException($exception) - { - if(php_sapi_name()==='cli') - { - echo $exception->getMessage()."\n"; - echo $exception->getTraceAsString(); - return; - } - - if($exception instanceof TTemplateException) - { - $fileName=$exception->getTemplateFile(); - $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName); - $source=$this->getSourceCode($lines,$exception->getLineNumber()); - if($fileName==='') - $fileName='---embedded template---'; - $errorLine=$exception->getLineNumber(); - } - else - { - if(($trace=$this->getExactTrace($exception))!==null) - { - $fileName=$trace['file']; - $errorLine=$trace['line']; - } - else - { - $fileName=$exception->getFile(); - $errorLine=$exception->getLine(); - } - $source=$this->getSourceCode(@file($fileName),$errorLine); - } - - if($this->getApplication()->getMode()===TApplicationMode::Debug) - $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); - else - $version=''; - - $tokens=array( - '%%ErrorType%%' => get_class($exception), - '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())), - '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')', - '%%SourceCode%%' => $source, - '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()), - '%%Version%%' => $version, - '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) - ); - - $content=$this->getExceptionTemplate($exception); - - echo strtr($content,$tokens); - } - - /** - * Retrieves the template used for displaying internal exceptions. - * Internal exceptions will be displayed with source code causing the exception. - * This occurs when the application is in debug mode. - * @param Exception the exception to be displayed - * @return string the template content - */ - protected function getExceptionTemplate($exception) - { - $lang=Prado::getPreferredLanguage(); - $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html'; - if(!is_file($exceptionFile)) - $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html'; - if(($content=@file_get_contents($exceptionFile))===false) - die("Unable to open exception template file '$exceptionFile'."); - return $content; - } - - /** - * Retrieves the template used for displaying external exceptions. - * External exceptions are those displayed to end-users. They do not contain - * error source code. Therefore, you might want to override this method - * to provide your own error template for displaying certain external exceptions. - * The following tokens in the template will be replaced with corresponding content: - * %%StatusCode%% : the status code of the exception - * %%ErrorMessage%% : the error message (HTML encoded). - * %%ServerAdmin%% : the server admin information (retrieved from Web server configuration) - * %%Version%% : the version information of the Web server. - * %%Time%% : the time the exception occurs at - * - * @param integer status code (such as 404, 500, etc.) - * @param Exception the exception to be displayed - * @return string the template content - */ - protected function getErrorTemplate($statusCode,$exception) - { - $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME; - $lang=Prado::getPreferredLanguage(); - if(is_file("$base$statusCode-$lang.html")) - $errorFile="$base$statusCode-$lang.html"; - else if(is_file("$base$statusCode.html")) - $errorFile="$base$statusCode.html"; - else if(is_file("$base-$lang.html")) - $errorFile="$base-$lang.html"; - else - $errorFile="$base.html"; - if(($content=@file_get_contents($errorFile))===false) - die("Unable to open error template file '$errorFile'."); - return $content; - } - - private function getExactTrace($exception) - { - $trace=$exception->getTrace(); - $result=null; - // if PHP exception, we want to show the 2nd stack level context - // because the 1st stack level is of little use (it's in error handler) - if($exception instanceof TPhpErrorException) - $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; - else if($exception instanceof TInvalidOperationException) - { - // in case of getter or setter error, find out the exact file and row - if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null) - $result=$this->getPropertyAccessTrace($trace,'__set'); - } - if($result!==null && strpos($result['file'],': eval()\'d code')!==false) - return null; - - return $result; - } - - private function getPropertyAccessTrace($trace,$pattern) - { - $result=null; - foreach($trace as $t) - { - if(isset($t['function']) && $t['function']===$pattern) - $result=$t; - else - break; - } - return $result; - } - - private function getSourceCode($lines,$errorLine) - { - $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0; - $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines); - - $source=''; - for($i=$beginLine;$i<$endLine;++$i) - { - if($i===$errorLine-1) - { - $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); - $source.="
".$line."
"; - } - else - $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); - } - return $source; - } - - private function addLink($message) - { - $baseUrl='http://www.pradosoft.com/docs/classdoc'; - return preg_replace('/\b(T[A-Z]\w+)\b/',"\${1}",$message); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Exceptions + */ + +/** + * TErrorHandler class + * + * TErrorHandler handles all PHP user errors and exceptions generated during + * servicing user requests. It displays these errors using different templates + * and if possible, using languages preferred by the client user. + * Note, PHP parsing errors cannot be caught and handled by TErrorHandler. + * + * The templates used to format the error output are stored under System.Exceptions. + * You may choose to use your own templates, should you not like the templates + * provided by Prado. Simply set {@link setErrorTemplatePath ErrorTemplatePath} + * to the path (in namespace format) storing your own templates. + * + * There are two sets of templates, one for errors to be displayed to client users + * (called external errors), one for errors to be displayed to system developers + * (called internal errors). The template file name for the former is + * error[StatusCode][-LanguageCode].html, and for the latter it is + * exception[-LanguageCode].html, where StatusCode refers to response status + * code (e.g. 404, 500) specified when {@link THttpException} is thrown, + * and LanguageCode is the client user preferred language code (e.g. en, zh, de). + * The templates error.html and exception.html are default ones + * that are used if no other appropriate templates are available. + * Note, these templates are not Prado control templates. They are simply + * html files with keywords (e.g. %%ErrorMessage%%, %%Version%%) + * to be replaced with the corresponding information. + * + * By default, TErrorHandler is registered with {@link TApplication} as the + * error handler module. It can be accessed via {@link TApplication::getErrorHandler()}. + * You seldom need to deal with the error handler directly. It is mainly used + * by the application object to handle errors. + * + * TErrorHandler may be configured in application configuration file as follows + * + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TErrorHandler extends TModule +{ + /** + * error template file basename + */ + const ERROR_FILE_NAME='error'; + /** + * exception template file basename + */ + const EXCEPTION_FILE_NAME='exception'; + /** + * number of lines before and after the error line to be displayed in case of an exception + */ + const SOURCE_LINES=12; + + /** + * @var string error template directory + */ + private $_templatePath=null; + + /** + * Initializes the module. + * This method is required by IModule and is invoked by application. + * @param TXmlElement module configuration + */ + public function init($config) + { + $this->getApplication()->setErrorHandler($this); + } + + /** + * @return string the directory containing error template files. + */ + public function getErrorTemplatePath() + { + if($this->_templatePath===null) + $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; + return $this->_templatePath; + } + + /** + * Sets the path storing all error and exception template files. + * The path must be in namespace format, such as System.Exceptions (which is the default). + * @param string template path in namespace format + * @throws TConfigurationException if the template path is invalid + */ + public function setErrorTemplatePath($value) + { + if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) + $this->_templatePath=$templatePath; + else + throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); + } + + /** + * Handles PHP user errors and exceptions. + * This is the event handler responding to the Error event + * raised in {@link TApplication}. + * The method mainly uses appropriate template to display the error/exception. + * It terminates the application immediately after the error is displayed. + * @param mixed sender of the event + * @param mixed event parameter (if the event is raised by TApplication, it refers to the exception instance) + */ + public function handleError($sender,$param) + { + static $handling=false; + // We need to restore error and exception handlers, + // because within error and exception handlers, new errors and exceptions + // cannot be handled properly by PHP + restore_error_handler(); + restore_exception_handler(); + // ensure that we do not enter infinite loop of error handling + if($handling) + $this->handleRecursiveError($param); + else + { + $handling=true; + if(($response=$this->getResponse())!==null) + $response->clear(); + if(!headers_sent()) + header('Content-Type: text/html; charset=UTF-8'); + if($param instanceof THttpException) + $this->handleExternalError($param->getStatusCode(),$param); + else if($this->getApplication()->getMode()===TApplicationMode::Debug) + $this->displayException($param); + else + $this->handleExternalError(500,$param); + } + } + + + /** + * @param string $value + * @param Exception|null$exception + * @return string + * @since 3.1.6 + */ + protected static function hideSecurityRelated($value, $exception=null) + { + $aRpl = array(); + if($exception !== null && $exception instanceof Exception) + { + $aTrace = $exception->getTrace(); + foreach($aTrace as $item) + { + if(isset($item['file'])) + $aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '' . DIRECTORY_SEPARATOR; + } + } + $aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}'; + $aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}'; + $aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR; + if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]); + $aRpl = array_reverse($aRpl, true); + + return str_replace(array_keys($aRpl), $aRpl, $value); + } + + /** + * Displays error to the client user. + * THttpException and errors happened when the application is in Debug + * mode will be displayed to the client user. + * @param integer response status code + * @param Exception exception instance + */ + protected function handleExternalError($statusCode,$exception) + { + if(!($exception instanceof THttpException)) + error_log($exception->__toString()); + + $content=$this->getErrorTemplate($statusCode,$exception); + + $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:''; + + $isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug; + + $errorMessage = $exception->getMessage(); + if($isDebug) + $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); + else + { + $version=''; + $errorMessage = self::hideSecurityRelated($errorMessage, $exception); + } + $tokens=array( + '%%StatusCode%%' => "$statusCode", + '%%ErrorMessage%%' => htmlspecialchars($errorMessage), + '%%ServerAdmin%%' => $serverAdmin, + '%%Version%%' => $version, + '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) + ); + + $CGI=substr(php_sapi_name(), 0, 3) == 'cgi'; // FastCGI / IIS + if($isDebug) + { + if ($CGI) + header("Status: $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode)); + else + header("HTTP/1.0 $statusCode ".$exception->getMessage(), true, TPropertyValue::ensureInteger($statusCode)); + } else { + if ($CGI) + header("Status: $statusCode", true, TPropertyValue::ensureInteger($statusCode)); + else + header("HTTP/1.0 $statusCode", true, TPropertyValue::ensureInteger($statusCode)); + } + + echo strtr($content,$tokens); + } + + /** + * Handles error occurs during error handling (called recursive error). + * THttpException and errors happened when the application is in Debug + * mode will be displayed to the client user. + * Error is displayed without using existing template to prevent further errors. + * @param Exception exception instance + */ + protected function handleRecursiveError($exception) + { + if($this->getApplication()->getMode()===TApplicationMode::Debug) + { + echo "Recursive Error\n"; + echo "

Recursive Error

\n"; + echo "
".$exception->__toString()."
\n"; + echo ""; + } + else + { + error_log("Error happened while processing an existing error:\n".$exception->__toString()); + header('HTTP/1.0 500 Internal Error'); + } + } + + /** + * Displays exception information. + * Exceptions are displayed with rich context information, including + * the call stack and the context source code. + * This method is only invoked when application is in Debug mode. + * @param Exception exception instance + */ + protected function displayException($exception) + { + if(php_sapi_name()==='cli') + { + echo $exception->getMessage()."\n"; + echo $exception->getTraceAsString(); + return; + } + + if($exception instanceof TTemplateException) + { + $fileName=$exception->getTemplateFile(); + $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName); + $source=$this->getSourceCode($lines,$exception->getLineNumber()); + if($fileName==='') + $fileName='---embedded template---'; + $errorLine=$exception->getLineNumber(); + } + else + { + if(($trace=$this->getExactTrace($exception))!==null) + { + $fileName=$trace['file']; + $errorLine=$trace['line']; + } + else + { + $fileName=$exception->getFile(); + $errorLine=$exception->getLine(); + } + $source=$this->getSourceCode(@file($fileName),$errorLine); + } + + if($this->getApplication()->getMode()===TApplicationMode::Debug) + $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); + else + $version=''; + + $tokens=array( + '%%ErrorType%%' => get_class($exception), + '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())), + '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')', + '%%SourceCode%%' => $source, + '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()), + '%%Version%%' => $version, + '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) + ); + + $content=$this->getExceptionTemplate($exception); + + echo strtr($content,$tokens); + } + + /** + * Retrieves the template used for displaying internal exceptions. + * Internal exceptions will be displayed with source code causing the exception. + * This occurs when the application is in debug mode. + * @param Exception the exception to be displayed + * @return string the template content + */ + protected function getExceptionTemplate($exception) + { + $lang=Prado::getPreferredLanguage(); + $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html'; + if(!is_file($exceptionFile)) + $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html'; + if(($content=@file_get_contents($exceptionFile))===false) + die("Unable to open exception template file '$exceptionFile'."); + return $content; + } + + /** + * Retrieves the template used for displaying external exceptions. + * External exceptions are those displayed to end-users. They do not contain + * error source code. Therefore, you might want to override this method + * to provide your own error template for displaying certain external exceptions. + * The following tokens in the template will be replaced with corresponding content: + * %%StatusCode%% : the status code of the exception + * %%ErrorMessage%% : the error message (HTML encoded). + * %%ServerAdmin%% : the server admin information (retrieved from Web server configuration) + * %%Version%% : the version information of the Web server. + * %%Time%% : the time the exception occurs at + * + * @param integer status code (such as 404, 500, etc.) + * @param Exception the exception to be displayed + * @return string the template content + */ + protected function getErrorTemplate($statusCode,$exception) + { + $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME; + $lang=Prado::getPreferredLanguage(); + if(is_file("$base$statusCode-$lang.html")) + $errorFile="$base$statusCode-$lang.html"; + else if(is_file("$base$statusCode.html")) + $errorFile="$base$statusCode.html"; + else if(is_file("$base-$lang.html")) + $errorFile="$base-$lang.html"; + else + $errorFile="$base.html"; + if(($content=@file_get_contents($errorFile))===false) + die("Unable to open error template file '$errorFile'."); + return $content; + } + + private function getExactTrace($exception) + { + $trace=$exception->getTrace(); + $result=null; + // if PHP exception, we want to show the 2nd stack level context + // because the 1st stack level is of little use (it's in error handler) + if($exception instanceof TPhpErrorException) + $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; + else if($exception instanceof TInvalidOperationException) + { + // in case of getter or setter error, find out the exact file and row + if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null) + $result=$this->getPropertyAccessTrace($trace,'__set'); + } + if($result!==null && strpos($result['file'],': eval()\'d code')!==false) + return null; + + return $result; + } + + private function getPropertyAccessTrace($trace,$pattern) + { + $result=null; + foreach($trace as $t) + { + if(isset($t['function']) && $t['function']===$pattern) + $result=$t; + else + break; + } + return $result; + } + + private function getSourceCode($lines,$errorLine) + { + $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0; + $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines); + + $source=''; + for($i=$beginLine;$i<$endLine;++$i) + { + if($i===$errorLine-1) + { + $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); + $source.="
".$line."
"; + } + else + $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); + } + return $source; + } + + private function addLink($message) + { + $baseUrl='http://www.pradosoft.com/docs/classdoc'; + return preg_replace('/\b(T[A-Z]\w+)\b/',"\${1}",$message); + } +} + diff --git a/framework/Exceptions/TException.php b/framework/Exceptions/TException.php index 5e266e17..c9f9d530 100644 --- a/framework/Exceptions/TException.php +++ b/framework/Exceptions/TException.php @@ -1,424 +1,424 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Exceptions - */ - -/** - * TException class - * - * TException is the base class for all PRADO exceptions. - * - * TException provides the functionality of translating an error code - * into a descriptive error message in a language that is preferred - * by user browser. Additional parameters may be passed together with - * the error code so that the translated message contains more detailed - * information. - * - * By default, TException looks for a message file by calling - * {@link getErrorMessageFile()} method, which uses the "message-xx.txt" - * file located under "System.Exceptions" folder, where "xx" is the - * code of the user preferred language. If such a file is not found, - * "message.txt" will be used instead. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TException extends Exception -{ - private $_errorCode=''; + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Exceptions + */ + +/** + * TException class + * + * TException is the base class for all PRADO exceptions. + * + * TException provides the functionality of translating an error code + * into a descriptive error message in a language that is preferred + * by user browser. Additional parameters may be passed together with + * the error code so that the translated message contains more detailed + * information. + * + * By default, TException looks for a message file by calling + * {@link getErrorMessageFile()} method, which uses the "message-xx.txt" + * file located under "System.Exceptions" folder, where "xx" is the + * code of the user preferred language. If such a file is not found, + * "message.txt" will be used instead. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TException extends Exception +{ + private $_errorCode=''; static $_messageCache=array(); - - /** - * Constructor. - * @param string error message. This can be a string that is listed - * in the message file. If so, the message in the preferred language - * will be used as the error message. Any rest parameters will be used - * to replace placeholders ({0}, {1}, {2}, etc.) in the message. - */ - public function __construct($errorMessage) - { - $this->_errorCode=$errorMessage; - $errorMessage=$this->translateErrorMessage($errorMessage); - $args=func_get_args(); - array_shift($args); - $n=count($args); - $tokens=array(); - for($i=0;$i<$n;++$i) - $tokens['{'.$i.'}']=TPropertyValue::ensureString($args[$i]); - parent::__construct(strtr($errorMessage,$tokens)); - } - - /** - * Translates an error code into an error message. - * @param string error code that is passed in the exception constructor. - * @return string the translated error message - */ - protected function translateErrorMessage($key) - { - $msgFile=$this->getErrorMessageFile(); + + /** + * Constructor. + * @param string error message. This can be a string that is listed + * in the message file. If so, the message in the preferred language + * will be used as the error message. Any rest parameters will be used + * to replace placeholders ({0}, {1}, {2}, etc.) in the message. + */ + public function __construct($errorMessage) + { + $this->_errorCode=$errorMessage; + $errorMessage=$this->translateErrorMessage($errorMessage); + $args=func_get_args(); + array_shift($args); + $n=count($args); + $tokens=array(); + for($i=0;$i<$n;++$i) + $tokens['{'.$i.'}']=TPropertyValue::ensureString($args[$i]); + parent::__construct(strtr($errorMessage,$tokens)); + } + + /** + * Translates an error code into an error message. + * @param string error code that is passed in the exception constructor. + * @return string the translated error message + */ + protected function translateErrorMessage($key) + { + $msgFile=$this->getErrorMessageFile(); // Cache messages if (!isset(self::$_messageCache[$msgFile])) { - if(($entries=@file($msgFile))!==false) - { - foreach($entries as $entry) - { - @list($code,$message)=explode('=',$entry,2); + if(($entries=@file($msgFile))!==false) + { + foreach($entries as $entry) + { + @list($code,$message)=explode('=',$entry,2); self::$_messageCache[$msgFile][trim($code)]=trim($message); - } - } + } + } } - return isset(self::$_messageCache[$msgFile][$key]) ? self::$_messageCache[$msgFile][$key] : $key; - } - - /** - * @return string path to the error message file - */ - protected function getErrorMessageFile() - { - $lang=Prado::getPreferredLanguage(); - $msgFile=Prado::getFrameworkPath().'/Exceptions/messages/messages-'.$lang.'.txt'; - if(!is_file($msgFile)) - $msgFile=Prado::getFrameworkPath().'/Exceptions/messages/messages.txt'; - return $msgFile; - } - - /** - * @return string error code - */ - public function getErrorCode() - { - return $this->_errorCode; - } - - /** - * @param string error code - */ - public function setErrorCode($code) - { - $this->_errorCode=$code; - } - - /** - * @return string error message - */ - public function getErrorMessage() - { - return $this->getMessage(); - } - - /** - * @param string error message - */ - protected function setErrorMessage($message) - { - $this->message=$message; - } -} - -/** - * TSystemException class - * - * TSystemException is the base class for all framework-level exceptions. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TSystemException extends TException -{ -} - -/** - * TApplicationException class - * - * TApplicationException is the base class for all user application-level exceptions. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TApplicationException extends TException -{ -} - -/** - * TInvalidOperationException class - * - * TInvalidOperationException represents an exception caused by invalid operations. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TInvalidOperationException extends TSystemException -{ -} - -/** - * TInvalidDataTypeException class - * - * TInvalidDataTypeException represents an exception caused by invalid data type. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TInvalidDataTypeException extends TSystemException -{ -} - -/** - * TInvalidDataValueException class - * - * TInvalidDataValueException represents an exception caused by invalid data value. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TInvalidDataValueException extends TSystemException -{ -} - -/** - * TConfigurationException class - * - * TConfigurationException represents an exception caused by invalid configurations, - * such as error in an application configuration file or control template file. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TConfigurationException extends TSystemException -{ -} - -/** - * TTemplateException class - * - * TTemplateException represents an exception caused by invalid template syntax. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.1 - */ -class TTemplateException extends TConfigurationException -{ - private $_template=''; - private $_lineNumber=0; - private $_fileName=''; - - /** - * @return string the template source code that causes the exception. This is empty if {@link getTemplateFile TemplateFile} is not empty. - */ - public function getTemplateSource() - { - return $this->_template; - } - - /** - * @param string the template source code that causes the exception - */ - public function setTemplateSource($value) - { - $this->_template=$value; - } - - /** - * @return string the template file that causes the exception. This could be empty if the template is an embedded template. In this case, use {@link getTemplateSource TemplateSource} to obtain the actual template content. - */ - public function getTemplateFile() - { - return $this->_fileName; - } - - /** - * @param string the template file that causes the exception - */ - public function setTemplateFile($value) - { - $this->_fileName=$value; - } - - /** - * @return integer the line number at which the template has error - */ - public function getLineNumber() - { - return $this->_lineNumber; - } - - /** - * @param integer the line number at which the template has error - */ - public function setLineNumber($value) - { - $this->_lineNumber=TPropertyValue::ensureInteger($value); - } -} - -/** - * TIOException class - * - * TIOException represents an exception related with improper IO operations. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TIOException extends TSystemException -{ -} - -/** - * TDbException class - * - * TDbException represents an exception related with DB operations. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TDbException extends TSystemException -{ -} - -/** - * TDbConnectionException class - * - * TDbConnectionException represents an exception caused by DB connection failure. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TDbConnectionException extends TDbException -{ -} - -/** - * TNotSupportedException class - * - * TNotSupportedException represents an exception caused by using an unsupported PRADO feature. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TNotSupportedException extends TSystemException -{ -} - -/** - * TPhpErrorException class - * - * TPhpErrorException represents an exception caused by a PHP error. - * This exception is mainly thrown within a PHP error handler. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class TPhpErrorException extends TSystemException -{ - /** - * Constructor. - * @param integer error number - * @param string error string - * @param string error file - * @param integer error line number - */ - public function __construct($errno,$errstr,$errfile,$errline) - { - static $errorTypes=array( - E_ERROR => "Error", - E_WARNING => "Warning", - E_PARSE => "Parsing Error", - E_NOTICE => "Notice", - E_CORE_ERROR => "Core Error", - E_CORE_WARNING => "Core Warning", - E_COMPILE_ERROR => "Compile Error", - E_COMPILE_WARNING => "Compile Warning", - E_USER_ERROR => "User Error", - E_USER_WARNING => "User Warning", - E_USER_NOTICE => "User Notice", - E_STRICT => "Runtime Notice" - ); - $errorType=isset($errorTypes[$errno])?$errorTypes[$errno]:'Unknown Error'; - parent::__construct("[$errorType] $errstr (@line $errline in file $errfile)."); - } -} - - -/** - * THttpException class - * - * THttpException represents an exception that is caused by invalid operations - * of end-users. The {@link getStatusCode StatusCode} gives the type of HTTP error. - * It is used by {@link TErrorHandler} to provide different error output to users. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Exceptions - * @since 3.0 - */ -class THttpException extends TSystemException -{ - private $_statusCode; - - /** - * Constructor. - * @param integer HTTP status code, such as 404, 500, etc. - * @param string error message. This can be a string that is listed - * in the message file. If so, the message in the preferred language - * will be used as the error message. Any rest parameters will be used - * to replace placeholders ({0}, {1}, {2}, etc.) in the message. - */ - public function __construct($statusCode,$errorMessage) - { - $this->_statusCode=$statusCode; - $this->setErrorCode($errorMessage); - $errorMessage=$this->translateErrorMessage($errorMessage); - $args=func_get_args(); - array_shift($args); - array_shift($args); - $n=count($args); - $tokens=array(); - for($i=0;$i<$n;++$i) - $tokens['{'.$i.'}']=TPropertyValue::ensureString($args[$i]); - parent::__construct(strtr($errorMessage,$tokens)); - } - - /** - * @return integer HTTP status code, such as 404, 500, etc. - */ - public function getStatusCode() - { - return $this->_statusCode; - } -} - + return isset(self::$_messageCache[$msgFile][$key]) ? self::$_messageCache[$msgFile][$key] : $key; + } + + /** + * @return string path to the error message file + */ + protected function getErrorMessageFile() + { + $lang=Prado::getPreferredLanguage(); + $msgFile=Prado::getFrameworkPath().'/Exceptions/messages/messages-'.$lang.'.txt'; + if(!is_file($msgFile)) + $msgFile=Prado::getFrameworkPath().'/Exceptions/messages/messages.txt'; + return $msgFile; + } + + /** + * @return string error code + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * @param string error code + */ + public function setErrorCode($code) + { + $this->_errorCode=$code; + } + + /** + * @return string error message + */ + public function getErrorMessage() + { + return $this->getMessage(); + } + + /** + * @param string error message + */ + protected function setErrorMessage($message) + { + $this->message=$message; + } +} + +/** + * TSystemException class + * + * TSystemException is the base class for all framework-level exceptions. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TSystemException extends TException +{ +} + +/** + * TApplicationException class + * + * TApplicationException is the base class for all user application-level exceptions. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TApplicationException extends TException +{ +} + +/** + * TInvalidOperationException class + * + * TInvalidOperationException represents an exception caused by invalid operations. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TInvalidOperationException extends TSystemException +{ +} + +/** + * TInvalidDataTypeException class + * + * TInvalidDataTypeException represents an exception caused by invalid data type. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TInvalidDataTypeException extends TSystemException +{ +} + +/** + * TInvalidDataValueException class + * + * TInvalidDataValueException represents an exception caused by invalid data value. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TInvalidDataValueException extends TSystemException +{ +} + +/** + * TConfigurationException class + * + * TConfigurationException represents an exception caused by invalid configurations, + * such as error in an application configuration file or control template file. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TConfigurationException extends TSystemException +{ +} + +/** + * TTemplateException class + * + * TTemplateException represents an exception caused by invalid template syntax. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.1 + */ +class TTemplateException extends TConfigurationException +{ + private $_template=''; + private $_lineNumber=0; + private $_fileName=''; + + /** + * @return string the template source code that causes the exception. This is empty if {@link getTemplateFile TemplateFile} is not empty. + */ + public function getTemplateSource() + { + return $this->_template; + } + + /** + * @param string the template source code that causes the exception + */ + public function setTemplateSource($value) + { + $this->_template=$value; + } + + /** + * @return string the template file that causes the exception. This could be empty if the template is an embedded template. In this case, use {@link getTemplateSource TemplateSource} to obtain the actual template content. + */ + public function getTemplateFile() + { + return $this->_fileName; + } + + /** + * @param string the template file that causes the exception + */ + public function setTemplateFile($value) + { + $this->_fileName=$value; + } + + /** + * @return integer the line number at which the template has error + */ + public function getLineNumber() + { + return $this->_lineNumber; + } + + /** + * @param integer the line number at which the template has error + */ + public function setLineNumber($value) + { + $this->_lineNumber=TPropertyValue::ensureInteger($value); + } +} + +/** + * TIOException class + * + * TIOException represents an exception related with improper IO operations. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TIOException extends TSystemException +{ +} + +/** + * TDbException class + * + * TDbException represents an exception related with DB operations. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TDbException extends TSystemException +{ +} + +/** + * TDbConnectionException class + * + * TDbConnectionException represents an exception caused by DB connection failure. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TDbConnectionException extends TDbException +{ +} + +/** + * TNotSupportedException class + * + * TNotSupportedException represents an exception caused by using an unsupported PRADO feature. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TNotSupportedException extends TSystemException +{ +} + +/** + * TPhpErrorException class + * + * TPhpErrorException represents an exception caused by a PHP error. + * This exception is mainly thrown within a PHP error handler. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class TPhpErrorException extends TSystemException +{ + /** + * Constructor. + * @param integer error number + * @param string error string + * @param string error file + * @param integer error line number + */ + public function __construct($errno,$errstr,$errfile,$errline) + { + static $errorTypes=array( + E_ERROR => "Error", + E_WARNING => "Warning", + E_PARSE => "Parsing Error", + E_NOTICE => "Notice", + E_CORE_ERROR => "Core Error", + E_CORE_WARNING => "Core Warning", + E_COMPILE_ERROR => "Compile Error", + E_COMPILE_WARNING => "Compile Warning", + E_USER_ERROR => "User Error", + E_USER_WARNING => "User Warning", + E_USER_NOTICE => "User Notice", + E_STRICT => "Runtime Notice" + ); + $errorType=isset($errorTypes[$errno])?$errorTypes[$errno]:'Unknown Error'; + parent::__construct("[$errorType] $errstr (@line $errline in file $errfile)."); + } +} + + +/** + * THttpException class + * + * THttpException represents an exception that is caused by invalid operations + * of end-users. The {@link getStatusCode StatusCode} gives the type of HTTP error. + * It is used by {@link TErrorHandler} to provide different error output to users. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Exceptions + * @since 3.0 + */ +class THttpException extends TSystemException +{ + private $_statusCode; + + /** + * Constructor. + * @param integer HTTP status code, such as 404, 500, etc. + * @param string error message. This can be a string that is listed + * in the message file. If so, the message in the preferred language + * will be used as the error message. Any rest parameters will be used + * to replace placeholders ({0}, {1}, {2}, etc.) in the message. + */ + public function __construct($statusCode,$errorMessage) + { + $this->_statusCode=$statusCode; + $this->setErrorCode($errorMessage); + $errorMessage=$this->translateErrorMessage($errorMessage); + $args=func_get_args(); + array_shift($args); + array_shift($args); + $n=count($args); + $tokens=array(); + for($i=0;$i<$n;++$i) + $tokens['{'.$i.'}']=TPropertyValue::ensureString($args[$i]); + parent::__construct(strtr($errorMessage,$tokens)); + } + + /** + * @return integer HTTP status code, such as 404, 500, etc. + */ + public function getStatusCode() + { + return $this->_statusCode; + } +} + -- cgit v1.2.3