diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 90b9ddc..c7c8c05 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -22,14 +22,6 @@ defined('YII_DEBUG') or define('YII_DEBUG', false); */ defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 0); /** - * This constant defines whether exception handling should be enabled. Defaults to true. - */ -defined('YII_ENABLE_EXCEPTION_HANDLER') or define('YII_ENABLE_EXCEPTION_HANDLER', true); -/** - * This constant defines whether error handling should be enabled. Defaults to true. - */ -defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', true); -/** * This constant defines the framework installation directory. */ defined('YII_PATH') or define('YII_PATH', __DIR__); diff --git a/framework/base/Application.php b/framework/base/Application.php index f951c8e..2a12317 100644 --- a/framework/base/Application.php +++ b/framework/base/Application.php @@ -91,8 +91,6 @@ abstract class Application extends Module public $sourceLanguage = 'en_us'; private $_runtimePath; - private $_globalState; - private $_stateChanged; private $_ended = false; private $_language; @@ -417,95 +415,6 @@ abstract class Application extends Module } /** - * Returns a global value. - * - * A global value is one that is persistent across users sessions and requests. - * @param string $key the name of the value to be returned - * @param mixed $defaultValue the default value. If the named global value is not found, this will be returned instead. - * @return mixed the named global value - * @see setGlobalState - */ - public function getGlobalState($key, $defaultValue = null) - { - if ($this->_globalState === null) { - $this->loadGlobalState(); - } - return isset($this->_globalState[$key]) ? $this->_globalState[$key] : $defaultValue; - } - - /** - * Sets a global value. - * - * A global value is one that is persistent across users sessions and requests. - * Make sure that the value is serializable and unserializable. - * @param string $key the name of the value to be saved - * @param mixed $value the global value to be saved. It must be serializable. - * @param mixed $defaultValue the default value. If the named global value is the same as this value, it will be cleared from the current storage. - * @see getGlobalState - */ - public function setGlobalState($key, $value, $defaultValue = null) - { - if ($this->_globalState === null) { - $this->loadGlobalState(); - } - - $changed = $this->_stateChanged; - if ($value === $defaultValue) { - if (isset($this->_globalState[$key])) { - unset($this->_globalState[$key]); - $this->_stateChanged = true; - } - } elseif (!isset($this->_globalState[$key]) || $this->_globalState[$key] !== $value) { - $this->_globalState[$key] = $value; - $this->_stateChanged = true; - } - - if ($this->_stateChanged !== $changed) { - $this->on('afterRequest', array($this, 'saveGlobalState')); - } - } - - /** - * Clears a global value. - * - * The value cleared will no longer be available in this request and the following requests. - * @param string $key the name of the value to be cleared - */ - public function clearGlobalState($key) - { - $this->setGlobalState($key, null); - } - - /** - * Loads the global state data from persistent storage. - * @see getStatePersister - * @throws \yii\base\Exception if the state persister is not available - */ - public function loadGlobalState() - { - $persister = $this->getStatePersister(); - if (($this->_globalState = $persister->load()) === null) { - $this->_globalState = array(); - } - $this->_stateChanged = false; - $this->off('afterRequest', array($this, 'saveGlobalState')); - } - - /** - * Saves the global state data into persistent storage. - * @see getStatePersister - * @throws \yii\base\Exception if the state persister is not available - */ - public function saveGlobalState() - { - if ($this->_stateChanged) { - $this->_stateChanged = false; - $this->off('afterRequest', array($this, 'saveGlobalState')); - $this->getStatePersister()->save($this->_globalState); - } - } - - /** * Handles uncaught PHP exceptions. * * This method is implemented as a PHP exception handler. It requires @@ -666,36 +575,6 @@ abstract class Application extends Module } /** - * Raised when an uncaught PHP exception occurs. - * - * An event handler can set the {@link ExceptionEvent::handled handled} - * property of the event parameter to be true to indicate no further error - * handling is needed. Otherwise, the {@link getErrorHandler errorHandler} - * application component will continue processing the error. - * - * @param ExceptionEvent $event event parameter - */ - public function onException($event) - { - $this->trigger('exception', $event); - } - - /** - * Raised when a PHP execution error occurs. - * - * An event handler can set the {@link ErrorEvent::handled handled} - * property of the event parameter to be true to indicate no further error - * handling is needed. Otherwise, the {@link getErrorHandler errorHandler} - * application component will continue processing the error. - * - * @param ErrorEvent $event event parameter - */ - public function onError($event) - { - $this->trigger('error', $event); - } - - /** * Displays the captured PHP error. * This method displays the error in HTML when there is * no active error handler. diff --git a/framework/base/ErrorHandler.php b/framework/base/ErrorHandler.php index f96f402..d5df70e 100644 --- a/framework/base/ErrorHandler.php +++ b/framework/base/ErrorHandler.php @@ -1,23 +1,22 @@ * @link http://www.yiiframework.com/ - * @copyright Copyright © 2008-2011 Yii Software LLC + * @copyright Copyright © 2008-2012 Yii Software LLC * @license http://www.yiiframework.com/license/ */ -Yii::import('CHtml',true); +namespace yii\base; /** - * CErrorHandler handles uncaught PHP errors and exceptions. + * ErrorHandler handles uncaught PHP errors and exceptions. * * It displays these errors using appropriate views based on the * nature of the error and the mode the application runs at. * It also chooses the most preferred language for displaying the error. * - * CErrorHandler uses two sets of views: + * ErrorHandler uses two sets of views: *
exception.php
;
* error<StatusCode>.php
;
@@ -33,7 +32,7 @@ Yii::import('CHtml',true);
* For security reasons, they only display the error message without any
* sensitive information.
*
- * CErrorHandler looks for the view templates from the following locations in order:
+ * ErrorHandler looks for the view templates from the following locations in order:
* themes/ThemeName/views/system
: when a theme is active.protected/views/system
' . $exception->getMessage() . ' (' . $exception->getFile() . ':' . $exception->getLine() . ')
'; + echo '' . $exception->getTraceAsString() . ''; + } else + { + echo '
' . $exception->getMessage() . '
'; + } + } /** - * Handles the exception/error event. - * This method is invoked by the application whenever it captures - * an exception or PHP error. - * @param CEvent $event the event containing the exception/error information + * @param \Exception $exception */ - public function handle($event) + public function handleException($exception) { - // set event as handled to prevent it from being handled by other event handlers - $event->handled=true; + $this->exception = $exception; - if($this->discardOutput) - { - // the following manual level counting is to deal with zlib.output_compression set to On - for($level=ob_get_level();$level>0;--$level) - { - @ob_end_clean(); + // disable error capturing to avoid recursive errors + restore_error_handler(); + restore_exception_handler(); + + $this->logException($exception); + if ($this->discardExistingOutput) { + $this->clearOutput(); + } + + if ($this->compactOutput === null) { + // not in Web application, or not in AJAX request + $this->compactOutput = !(\Yii::$application instanceof \yii\web\Application) || isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'; + } + + if ($this->compactOutput) { + $this->simple(); + return; + } + + if (($trace = $this->getExactTrace($exception)) === null) { + $fileName = $exception->getFile(); + $errorLine = $exception->getLine(); + } else { + $fileName = $trace['file']; + $errorLine = $trace['line']; + } + + $trace = $exception->getTrace(); + foreach ($trace as $i => $t) { + if (!isset($t['file'])) { + $trace[$i]['file'] = 'unknown'; + } + if (!isset($t['line'])) { + $trace[$i]['line'] = 0; } + if (!isset($t['function'])) { + $trace[$i]['function'] = 'unknown'; + } + unset($trace[$i]['object']); + } + + $this->_error = $data = array( + 'code' => $exception instanceof HttpException ? $exception->statusCode : 500, + 'type' => get_class($exception), + 'errorCode' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'file' => $fileName, + 'line' => $errorLine, + 'trace' => $exception->getTraceAsString(), + 'traces' => $trace, + ); + + if (!headers_sent()) { + header("HTTP/1.0 {$data['code']} " . get_class($exception)); } - if($event instanceof CExceptionEvent) - $this->handleException($event->exception); - else // CErrorEvent - $this->handleError($event); + if ($exception instanceof HttpException || !YII_DEBUG) { + $this->render('error', $data); + } else { + $this->render('exception', $data); + } } /** @@ -130,103 +210,38 @@ class CErrorHandler extends CApplicationComponent } /** - * Handles the exception. - * @param Exception $exception the exception captured - */ - protected function handleException($exception) - { - $app=Yii::app(); - if($app instanceof CWebApplication) - { - if(($trace=$this->getExactTrace($exception))===null) - { - $fileName=$exception->getFile(); - $errorLine=$exception->getLine(); - } - else - { - $fileName=$trace['file']; - $errorLine=$trace['line']; - } - - $trace = $exception->getTrace(); - - foreach($trace as $i=>$t) - { - if(!isset($t['file'])) - $trace[$i]['file']='unknown'; - - if(!isset($t['line'])) - $trace[$i]['line']=0; - - if(!isset($t['function'])) - $trace[$i]['function']='unknown'; - - unset($trace[$i]['object']); - } - - $this->_error=$data=array( - 'code'=>($exception instanceof CHttpException)?$exception->statusCode:500, - 'type'=>get_class($exception), - 'errorCode'=>$exception->getCode(), - 'message'=>$exception->getMessage(), - 'file'=>$fileName, - 'line'=>$errorLine, - 'trace'=>$exception->getTraceAsString(), - 'traces'=>$trace, - ); - - if(!headers_sent()) - header("HTTP/1.0 {$data['code']} ".get_class($exception)); - - if($exception instanceof CHttpException || !YII_DEBUG) - $this->render('error',$data); - else - { - if($this->isAjaxRequest()) - $app->displayException($exception); - else - $this->render('exception',$data); - } - } - else - $app->displayException($exception); - } - - /** * Handles the PHP error. * @param CErrorEvent $event the PHP error event */ protected function handleError($event) { - $trace=debug_backtrace(); + $trace = debug_backtrace(); // skip the first 3 stacks as they do not tell the error position - if(count($trace)>3) - $trace=array_slice($trace,3); - $traceString=''; - foreach($trace as $i=>$t) + if (count($trace) > 3) + $trace = array_slice($trace, 3); + $traceString = ''; + foreach ($trace as $i => $t) { - if(!isset($t['file'])) - $trace[$i]['file']='unknown'; + if (!isset($t['file'])) + $trace[$i]['file'] = 'unknown'; - if(!isset($t['line'])) - $trace[$i]['line']=0; + if (!isset($t['line'])) + $trace[$i]['line'] = 0; - if(!isset($t['function'])) - $trace[$i]['function']='unknown'; + if (!isset($t['function'])) + $trace[$i]['function'] = 'unknown'; - $traceString.="#$i {$trace[$i]['file']}({$trace[$i]['line']}): "; - if(isset($t['object']) && is_object($t['object'])) - $traceString.=get_class($t['object']).'->'; - $traceString.="{$trace[$i]['function']}()\n"; + $traceString .= "#$i {$trace[$i]['file']}({$trace[$i]['line']}): "; + if (isset($t['object']) && is_object($t['object'])) + $traceString .= get_class($t['object']) . '->'; + $traceString .= "{$trace[$i]['function']}()\n"; unset($trace[$i]['object']); } - $app=Yii::app(); - if($app instanceof CWebApplication) - { - switch($event->code) + $app = Yii::app(); + if ($app instanceof CWebApplication) { + switch ($event->code) { case E_WARNING: $type = 'PHP warning'; @@ -249,51 +264,41 @@ class CErrorHandler extends CApplicationComponent default: $type = 'PHP error'; } - $this->_error=$data=array( - 'code'=>500, - 'type'=>$type, - 'message'=>$event->message, - 'file'=>$event->file, - 'line'=>$event->line, - 'trace'=>$traceString, - 'traces'=>$trace, + $this->_error = $data = array( + 'code' => 500, + 'type' => $type, + 'message' => $event->message, + 'file' => $event->file, + 'line' => $event->line, + 'trace' => $traceString, + 'traces' => $trace, ); - if(!headers_sent()) + if (!headers_sent()) header("HTTP/1.0 500 PHP Error"); - if($this->isAjaxRequest()) - $app->displayError($event->code,$event->message,$event->file,$event->line); - else if(YII_DEBUG) - $this->render('exception',$data); + if ($this->isAjaxRequest()) + $app->displayError($event->code, $event->message, $event->file, $event->line); + else if (YII_DEBUG) + $this->render('exception', $data); else - $this->render('error',$data); + $this->render('error', $data); } else - $app->displayError($event->code,$event->message,$event->file,$event->line); - } - - /** - * whether the current request is an AJAX (XMLHttpRequest) request. - * @return boolean whether the current request is an AJAX request. - */ - protected function isAjaxRequest() - { - return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'; + $app->displayError($event->code, $event->message, $event->file, $event->line); } /** * Returns the exact trace where the problem occurs. - * @param Exception $exception the uncaught exception + * @param \Exception $exception the uncaught exception * @return array the exact trace where the problem occurs */ protected function getExactTrace($exception) { - $traces=$exception->getTrace(); - - foreach($traces as $trace) - { + $traces = $exception->getTrace(); + foreach ($traces as $trace) { // property access exception - if(isset($trace['function']) && ($trace['function']==='__get' || $trace['function']==='__set')) + if (isset($trace['function']) && ($trace['function'] === '__get' || $trace['function'] === '__set')) { return $trace; + } } return null; } @@ -304,17 +309,17 @@ class CErrorHandler extends CApplicationComponent * See {@link getViewFile} for how a view file is located given its name. * @param array $data data to be passed to the view */ - protected function render($view,$data) + protected function render($view, $data) { - if($view==='error' && $this->errorAction!==null) + if ($view === 'error' && $this->errorAction !== null) Yii::app()->runController($this->errorAction); else { // additional information to be passed to view - $data['version']=$this->getVersionInfo(); - $data['time']=time(); - $data['admin']=$this->adminInfo; - include($this->getViewFile($view,$data['code'])); + $data['version'] = $this->getVersionInfo(); + $data['time'] = time(); + $data['admin'] = $this->adminInfo; + include($this->getViewFile($view, $data['code'])); } } @@ -324,21 +329,20 @@ class CErrorHandler extends CApplicationComponent * @param integer $code HTTP status code * @return string view file path */ - protected function getViewFile($view,$code) + protected function getViewFile($view, $code) { - $viewPaths=array( - Yii::app()->getTheme()===null ? null : Yii::app()->getTheme()->getSystemViewPath(), + $viewPaths = array( + Yii::app()->getTheme() === null ? null : Yii::app()->getTheme()->getSystemViewPath(), Yii::app() instanceof CWebApplication ? Yii::app()->getSystemViewPath() : null, - YII_PATH.DIRECTORY_SEPARATOR.'views', + YII_PATH . DIRECTORY_SEPARATOR . 'views', ); - foreach($viewPaths as $i=>$viewPath) + foreach ($viewPaths as $i => $viewPath) { - if($viewPath!==null) - { - $viewFile=$this->getViewFileInternal($viewPath,$view,$code,$i===2?'en_us':null); - if(is_file($viewFile)) - return $viewFile; + if ($viewPath !== null) { + $viewFile = $this->getViewFileInternal($viewPath, $view, $code, $i === 2 ? 'en_us' : null); + if (is_file($viewFile)) + return $viewFile; } } } @@ -351,17 +355,16 @@ class CErrorHandler extends CApplicationComponent * @param string $srcLanguage the language that the view file is in * @return string view file path */ - protected function getViewFileInternal($viewPath,$view,$code,$srcLanguage=null) + protected function getViewFileInternal($viewPath, $view, $code, $srcLanguage = null) { - $app=Yii::app(); - if($view==='error') - { - $viewFile=$app->findLocalizedFile($viewPath.DIRECTORY_SEPARATOR."error{$code}.php",$srcLanguage); - if(!is_file($viewFile)) - $viewFile=$app->findLocalizedFile($viewPath.DIRECTORY_SEPARATOR.'error.php',$srcLanguage); + $app = Yii::app(); + if ($view === 'error') { + $viewFile = $app->findLocalizedFile($viewPath . DIRECTORY_SEPARATOR . "error{$code}.php", $srcLanguage); + if (!is_file($viewFile)) + $viewFile = $app->findLocalizedFile($viewPath . DIRECTORY_SEPARATOR . 'error.php', $srcLanguage); } else - $viewFile=$viewPath.DIRECTORY_SEPARATOR."exception.php"; + $viewFile = $viewPath . DIRECTORY_SEPARATOR . "exception.php"; return $viewFile; } @@ -372,14 +375,14 @@ class CErrorHandler extends CApplicationComponent */ protected function getVersionInfo() { - if(YII_DEBUG) - { - $version='Yii Framework/'.Yii::getVersion(); - if(isset($_SERVER['SERVER_SOFTWARE'])) - $version=$_SERVER['SERVER_SOFTWARE'].' '.$version; + if (YII_DEBUG) { + $version = 'Yii Framework/' . \Yii::getVersion(); + if (isset($_SERVER['SERVER_SOFTWARE'])) { + $version = $_SERVER['SERVER_SOFTWARE'] . ' ' . $version; + } + } else { + $version = ''; } - else - $version=''; return $version; } @@ -391,47 +394,43 @@ class CErrorHandler extends CApplicationComponent */ protected function argumentsToString($args) { - $count=0; + $count = 0; - $isAssoc=$args!==array_values($args); + $isAssoc = $args !== array_values($args); - foreach($args as $key => $value) + foreach ($args as $key => $value) { $count++; - if($count>=5) - { - if($count>5) + if ($count >= 5) { + if ($count > 5) unset($args[$key]); else - $args[$key]='...'; + $args[$key] = '...'; continue; } - if(is_object($value)) + if (is_object($value)) $args[$key] = get_class($value); - else if(is_bool($value)) + else if (is_bool($value)) $args[$key] = $value ? 'true' : 'false'; - else if(is_string($value)) - { - if(strlen($value)>64) - $args[$key] = '"'.substr($value,0,64).'..."'; + else if (is_string($value)) { + if (strlen($value) > 64) + $args[$key] = '"' . substr($value, 0, 64) . '..."'; else - $args[$key] = '"'.$value.'"'; + $args[$key] = '"' . $value . '"'; } - else if(is_array($value)) - $args[$key] = 'array('.$this->argumentsToString($value).')'; - else if($value===null) + else if (is_array($value)) + $args[$key] = 'array(' . $this->argumentsToString($value) . ')'; + else if ($value === null) $args[$key] = 'null'; - else if(is_resource($value)) + else if (is_resource($value)) $args[$key] = 'resource'; - if(is_string($key)) - { - $args[$key] = '"'.$key.'" => '.$args[$key]; + if (is_string($key)) { + $args[$key] = '"' . $key . '" => ' . $args[$key]; } - else if($isAssoc) - { - $args[$key] = $key.' => '.$args[$key]; + else if ($isAssoc) { + $args[$key] = $key . ' => ' . $args[$key]; } } $out = implode(", ", $args); @@ -446,10 +445,9 @@ class CErrorHandler extends CApplicationComponent */ protected function isCoreCode($trace) { - if(isset($trace['file'])) - { - $systemPath=realpath(dirname(__FILE__).'/..'); - return $trace['file']==='unknown' || strpos(realpath($trace['file']),$systemPath.DIRECTORY_SEPARATOR)===0; + if (isset($trace['file'])) { + $systemPath = realpath(dirname(__FILE__) . '/..'); + return $trace['file'] === 'unknown' || strpos(realpath($trace['file']), $systemPath . DIRECTORY_SEPARATOR) === 0; } return false; } @@ -461,27 +459,49 @@ class CErrorHandler extends CApplicationComponent * @param integer $maxLines maximum number of lines to display * @return string the rendering result */ - protected function renderSourceCode($file,$errorLine,$maxLines) + protected function renderSourceCode($file, $errorLine, $maxLines) { - $errorLine--; // adjust line number to 0-based from 1-based - if($errorLine<0 || ($lines=@file($file))===false || ($lineCount=count($lines))<=$errorLine) + $errorLine--; // adjust line number to 0-based from 1-based + if ($errorLine < 0 || ($lines = @file($file)) === false || ($lineCount = count($lines)) <= $errorLine) return ''; - $halfLines=(int)($maxLines/2); - $beginLine=$errorLine-$halfLines>0 ? $errorLine-$halfLines:0; - $endLine=$errorLine+$halfLines<$lineCount?$errorLine+$halfLines:$lineCount-1; - $lineNumberWidth=strlen($endLine+1); + $halfLines = (int)($maxLines / 2); + $beginLine = $errorLine - $halfLines > 0 ? $errorLine - $halfLines : 0; + $endLine = $errorLine + $halfLines < $lineCount ? $errorLine + $halfLines : $lineCount - 1; + $lineNumberWidth = strlen($endLine + 1); - $output=''; - for($i=$beginLine;$i<=$endLine;++$i) + $output = ''; + for ($i = $beginLine; $i <= $endLine; ++$i) { - $isErrorLine = $i===$errorLine; - $code=sprintf("%0{$lineNumberWidth}d %s",$i+1,CHtml::encode(str_replace("\t",' ',$lines[$i]))); - if(!$isErrorLine) - $output.=$code; + $isErrorLine = $i === $errorLine; + $code = sprintf("%0{$lineNumberWidth}d %s", $i + 1, CHtml::encode(str_replace("\t", ' ', $lines[$i]))); + if (!$isErrorLine) + $output .= $code; else - $output.=''.$code.''; + $output .= '' . $code . ''; } - return ''.$output.'
' . $output . '