"Fossies" - the Fresh Open Source Software Archive

Member "yii-1.1.24.a5ab20/framework/base/CApplication.php" (7 Jun 2021, 33171 Bytes) of package /linux/www/yii-1.1.24.a5ab20.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "CApplication.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.1.23.445827_vs_1.1.24.a5ab20.

    1 <?php
    2 /**
    3  * CApplication class file.
    4  *
    5  * @author Qiang Xue <qiang.xue@gmail.com>
    6  * @link http://www.yiiframework.com/
    7  * @copyright 2008-2013 Yii Software LLC
    8  * @license http://www.yiiframework.com/license/
    9  */
   10 
   11 /**
   12  * CApplication is the base class for all application classes.
   13  *
   14  * An application serves as the global context that the user request
   15  * is being processed. It manages a set of application components that
   16  * provide specific functionalities to the whole application.
   17  *
   18  * The core application components provided by CApplication are the following:
   19  * <ul>
   20  * <li>{@link getErrorHandler errorHandler}: handles PHP errors and
   21  *   uncaught exceptions. This application component is dynamically loaded when needed.</li>
   22  * <li>{@link getSecurityManager securityManager}: provides security-related
   23  *   services, such as hashing, encryption. This application component is dynamically
   24  *   loaded when needed.</li>
   25  * <li>{@link getStatePersister statePersister}: provides global state
   26  *   persistence method. This application component is dynamically loaded when needed.</li>
   27  * <li>{@link getCache cache}: provides caching feature. This application component is
   28  *   disabled by default.</li>
   29  * <li>{@link getMessages messages}: provides the message source for translating
   30  *   application messages. This application component is dynamically loaded when needed.</li>
   31  * <li>{@link getCoreMessages coreMessages}: provides the message source for translating
   32  *   Yii framework messages. This application component is dynamically loaded when needed.</li>
   33  * <li>{@link getUrlManager urlManager}: provides URL construction as well as parsing functionality.
   34  *   This application component is dynamically loaded when needed.</li>
   35  * <li>{@link getRequest request}: represents the current HTTP request by encapsulating
   36  *   the $_SERVER variable and managing cookies sent from and sent to the user.
   37  *   This application component is dynamically loaded when needed.</li>
   38  * <li>{@link getFormat format}: provides a set of commonly used data formatting methods.
   39  *   This application component is dynamically loaded when needed.</li>
   40  * </ul>
   41  *
   42  * CApplication will undergo the following lifecycles when processing a user request:
   43  * <ol>
   44  * <li>load application configuration;</li>
   45  * <li>set up error handling;</li>
   46  * <li>load static application components;</li>
   47  * <li>{@link onBeginRequest}: preprocess the user request;</li>
   48  * <li>{@link processRequest}: process the user request;</li>
   49  * <li>{@link onEndRequest}: postprocess the user request;</li>
   50  * </ol>
   51  *
   52  * Starting from lifecycle 3, if a PHP error or an uncaught exception occurs,
   53  * the application will switch to its error handling logic and jump to step 6 afterwards.
   54  *
   55  * @property string $id The unique identifier for the application.
   56  * @property string $basePath The root directory of the application. Defaults to 'protected'.
   57  * @property string $runtimePath The directory that stores runtime files. Defaults to 'protected/runtime'.
   58  * @property string $extensionPath The directory that contains all extensions. Defaults to the 'extensions' directory under 'protected'.
   59  * @property string $language The language that the user is using and the application should be targeted to.
   60  * Defaults to the {@link sourceLanguage source language}.
   61  * @property string $timeZone The time zone used by this application.
   62  * @property CLocale $locale The locale instance.
   63  * @property string $localeDataPath The directory that contains the locale data. It defaults to 'framework/i18n/data'.
   64  * @property CNumberFormatter $numberFormatter The locale-dependent number formatter.
   65  * The current {@link getLocale application locale} will be used.
   66  * @property CDateFormatter $dateFormatter The locale-dependent date formatter.
   67  * The current {@link getLocale application locale} will be used.
   68  * @property CDbConnection $db The database connection.
   69  * @property CErrorHandler $errorHandler The error handler application component.
   70  * @property CSecurityManager $securityManager The security manager application component.
   71  * @property CStatePersister $statePersister The state persister application component.
   72  * @property CCache $cache The cache application component. Null if the component is not enabled.
   73  * @property CPhpMessageSource $coreMessages The core message translations.
   74  * @property CMessageSource $messages The application message translations.
   75  * @property CHttpRequest $request The request component.
   76  * @property CFormatter $format The formatter component.
   77  * @property CUrlManager $urlManager The URL manager component.
   78  * @property CController $controller The currently active controller. Null is returned in this base class.
   79  * @property string $baseUrl The relative URL for the application.
   80  * @property string $homeUrl The homepage URL.
   81  *
   82  * @author Qiang Xue <qiang.xue@gmail.com>
   83  * @package system.base
   84  * @since 1.0
   85  */
   86 abstract class CApplication extends CModule
   87 {
   88     /**
   89      * @var string the application name. Defaults to 'My Application'.
   90      */
   91     public $name='My Application';
   92     /**
   93      * @var string the charset currently used for the application. Defaults to 'UTF-8'.
   94      */
   95     public $charset='UTF-8';
   96     /**
   97      * @var string the language that the application is written in. This mainly refers to
   98      * the language that the messages and view files are in. Defaults to 'en_us' (US English).
   99      */
  100     public $sourceLanguage='en_us';
  101     /**
  102      * @var string the class used to get locale data. Defaults to 'CLocale'.
  103      */
  104     public $localeClass='CLocale';
  105 
  106     private $_id;
  107     private $_basePath;
  108     private $_runtimePath;
  109     private $_extensionPath;
  110     private $_globalState;
  111     private $_stateChanged;
  112     private $_ended=false;
  113     private $_language;
  114     private $_homeUrl;
  115 
  116     /**
  117      * Processes the request.
  118      * This is the place where the actual request processing work is done.
  119      * Derived classes should override this method.
  120      */
  121     abstract public function processRequest();
  122 
  123     /**
  124      * Constructor.
  125      * @param mixed $config application configuration.
  126      * If a string, it is treated as the path of the file that contains the configuration;
  127      * If an array, it is the actual configuration information.
  128      * Please make sure you specify the {@link getBasePath basePath} property in the configuration,
  129      * which should point to the directory containing all application logic, template and data.
  130      * If not, the directory will be defaulted to 'protected'.
  131      */
  132     public function __construct($config=null)
  133     {
  134         Yii::setApplication($this);
  135 
  136         // set basePath as early as possible to avoid trouble
  137         if(is_string($config))
  138             $config=require($config);
  139         if(isset($config['basePath']))
  140         {
  141             $this->setBasePath($config['basePath']);
  142             unset($config['basePath']);
  143         }
  144         else
  145             $this->setBasePath('protected');
  146         Yii::setPathOfAlias('application',$this->getBasePath());
  147         Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME']));
  148         if(isset($config['extensionPath']))
  149         {
  150             $this->setExtensionPath($config['extensionPath']);
  151             unset($config['extensionPath']);
  152         }
  153         else
  154             Yii::setPathOfAlias('ext',$this->getBasePath().DIRECTORY_SEPARATOR.'extensions');
  155         if(isset($config['aliases']))
  156         {
  157             $this->setAliases($config['aliases']);
  158             unset($config['aliases']);
  159         }
  160 
  161         $this->preinit();
  162 
  163         $this->initSystemHandlers();
  164         $this->registerCoreComponents();
  165 
  166         $this->configure($config);
  167         $this->attachBehaviors($this->behaviors);
  168         $this->preloadComponents();
  169 
  170         $this->init();
  171     }
  172 
  173 
  174     /**
  175      * Runs the application.
  176      * This method loads static application components. Derived classes usually overrides this
  177      * method to do more application-specific tasks.
  178      * Remember to call the parent implementation so that static application components are loaded.
  179      */
  180     public function run()
  181     {
  182         if($this->hasEventHandler('onBeginRequest'))
  183             $this->onBeginRequest(new CEvent($this));
  184         register_shutdown_function(array($this,'end'),0,false);
  185         $this->processRequest();
  186         if($this->hasEventHandler('onEndRequest'))
  187             $this->onEndRequest(new CEvent($this));
  188     }
  189 
  190     /**
  191      * Terminates the application.
  192      * This method replaces PHP's exit() function by calling
  193      * {@link onEndRequest} before exiting.
  194      * @param integer $status exit status (value 0 means normal exit while other values mean abnormal exit).
  195      * @param boolean $exit whether to exit the current request. This parameter has been available since version 1.1.5.
  196      * It defaults to true, meaning the PHP's exit() function will be called at the end of this method.
  197      */
  198     public function end($status=0,$exit=true)
  199     {
  200         if($this->hasEventHandler('onEndRequest'))
  201             $this->onEndRequest(new CEvent($this));
  202         if($exit)
  203             exit($status);
  204     }
  205 
  206     /**
  207      * Raised right BEFORE the application processes the request.
  208      * @param CEvent $event the event parameter
  209      */
  210     public function onBeginRequest($event)
  211     {
  212         $this->raiseEvent('onBeginRequest',$event);
  213     }
  214 
  215     /**
  216      * Raised right AFTER the application processes the request.
  217      * @param CEvent $event the event parameter
  218      */
  219     public function onEndRequest($event)
  220     {
  221         if(!$this->_ended)
  222         {
  223             $this->_ended=true;
  224             $this->raiseEvent('onEndRequest',$event);
  225         }
  226     }
  227 
  228     /**
  229      * Returns the unique identifier for the application.
  230      * @return string the unique identifier for the application.
  231      */
  232     public function getId()
  233     {
  234         if($this->_id!==null)
  235             return $this->_id;
  236         else
  237             return $this->_id=sprintf('%x',crc32($this->getBasePath().$this->name));
  238     }
  239 
  240     /**
  241      * Sets the unique identifier for the application.
  242      * @param string $id the unique identifier for the application.
  243      */
  244     public function setId($id)
  245     {
  246         $this->_id=$id;
  247     }
  248 
  249     /**
  250      * Returns the root path of the application.
  251      * @return string the root directory of the application. Defaults to 'protected'.
  252      */
  253     public function getBasePath()
  254     {
  255         return $this->_basePath;
  256     }
  257 
  258     /**
  259      * Sets the root directory of the application.
  260      * This method can only be invoked at the begin of the constructor.
  261      * @param string $path the root directory of the application.
  262      * @throws CException if the directory does not exist.
  263      */
  264     public function setBasePath($path)
  265     {
  266         if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath))
  267             throw new CException(Yii::t('yii','Application base path "{path}" is not a valid directory.',
  268                 array('{path}'=>$path)));
  269     }
  270 
  271     /**
  272      * Returns the directory that stores runtime files.
  273      * @return string the directory that stores runtime files. Defaults to 'protected/runtime'.
  274      */
  275     public function getRuntimePath()
  276     {
  277         if($this->_runtimePath!==null)
  278             return $this->_runtimePath;
  279         else
  280         {
  281             $this->setRuntimePath($this->getBasePath().DIRECTORY_SEPARATOR.'runtime');
  282             return $this->_runtimePath;
  283         }
  284     }
  285 
  286     /**
  287      * Sets the directory that stores runtime files.
  288      * @param string $path the directory that stores runtime files.
  289      * @throws CException if the directory does not exist or is not writable
  290      */
  291     public function setRuntimePath($path)
  292     {
  293         if(($runtimePath=realpath($path))===false || !is_dir($runtimePath) || !is_writable($runtimePath))
  294             throw new CException(Yii::t('yii','Application runtime path "{path}" is not valid. Please make sure it is a directory writable by the Web server process.',
  295                 array('{path}'=>$path)));
  296         $this->_runtimePath=$runtimePath;
  297     }
  298 
  299     /**
  300      * Returns the root directory that holds all third-party extensions.
  301      * @return string the directory that contains all extensions. Defaults to the 'extensions' directory under 'protected'.
  302      */
  303     public function getExtensionPath()
  304     {
  305         return Yii::getPathOfAlias('ext');
  306     }
  307 
  308     /**
  309      * Sets the root directory that holds all third-party extensions.
  310      * @param string $path the directory that contains all third-party extensions.
  311      * @throws CException if the directory does not exist
  312      */
  313     public function setExtensionPath($path)
  314     {
  315         if(($extensionPath=realpath($path))===false || !is_dir($extensionPath))
  316             throw new CException(Yii::t('yii','Extension path "{path}" does not exist.',
  317                 array('{path}'=>$path)));
  318         Yii::setPathOfAlias('ext',$extensionPath);
  319     }
  320 
  321     /**
  322      * Returns the language that the user is using and the application should be targeted to.
  323      * @return string the language that the user is using and the application should be targeted to.
  324      * Defaults to the {@link sourceLanguage source language}.
  325      */
  326     public function getLanguage()
  327     {
  328         return $this->_language===null ? $this->sourceLanguage : $this->_language;
  329     }
  330 
  331     /**
  332      * Specifies which language the application is targeted to.
  333      *
  334      * This is the language that the application displays to end users.
  335      * If set null, it uses the {@link sourceLanguage source language}.
  336      *
  337      * Unless your application needs to support multiple languages, you should always
  338      * set this language to null to maximize the application's performance.
  339      * @param string $language the user language (e.g. 'en_US', 'zh_CN').
  340      * If it is null, the {@link sourceLanguage} will be used.
  341      */
  342     public function setLanguage($language)
  343     {
  344         $this->_language=$language;
  345     }
  346 
  347     /**
  348      * Returns the time zone used by this application.
  349      * This is a simple wrapper of PHP function date_default_timezone_get().
  350      * @return string the time zone used by this application.
  351      * @see http://php.net/manual/en/function.date-default-timezone-get.php
  352      */
  353     public function getTimeZone()
  354     {
  355         return date_default_timezone_get();
  356     }
  357 
  358     /**
  359      * Sets the time zone used by this application.
  360      * This is a simple wrapper of PHP function date_default_timezone_set().
  361      * @param string $value the time zone used by this application.
  362      * @see http://php.net/manual/en/function.date-default-timezone-set.php
  363      */
  364     public function setTimeZone($value)
  365     {
  366         date_default_timezone_set($value);
  367     }
  368 
  369     /**
  370      * Returns the localized version of a specified file.
  371      *
  372      * The searching is based on the specified language code. In particular,
  373      * a file with the same name will be looked for under the subdirectory
  374      * named as the locale ID. For example, given the file "path/to/view.php"
  375      * and locale ID "zh_cn", the localized file will be looked for as
  376      * "path/to/zh_cn/view.php". If the file is not found, the original file
  377      * will be returned.
  378      *
  379      * For consistency, it is recommended that the locale ID is given
  380      * in lower case and in the format of LanguageID_RegionID (e.g. "en_us").
  381      *
  382      * @param string $srcFile the original file
  383      * @param string $srcLanguage the language that the original file is in. If null, the application {@link sourceLanguage source language} is used.
  384      * @param string $language the desired language that the file should be localized to. If null, the {@link getLanguage application language} will be used.
  385      * @return string the matching localized file. The original file is returned if no localized version is found
  386      * or if source language is the same as the desired language.
  387      */
  388     public function findLocalizedFile($srcFile,$srcLanguage=null,$language=null)
  389     {
  390         if($srcLanguage===null)
  391             $srcLanguage=$this->sourceLanguage;
  392         if($language===null)
  393             $language=$this->getLanguage();
  394         if($language===$srcLanguage)
  395             return $srcFile;
  396         $desiredFile=dirname($srcFile).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.basename($srcFile);
  397         return is_file($desiredFile) ? $desiredFile : $srcFile;
  398     }
  399 
  400     /**
  401      * Returns the locale instance.
  402      * @param string $localeID the locale ID (e.g. en_US). If null, the {@link getLanguage application language ID} will be used.
  403      * @return CLocale an instance of CLocale
  404      */
  405     public function getLocale($localeID=null)
  406     {
  407         return call_user_func_array(array($this->localeClass, 'getInstance'),array($localeID===null?$this->getLanguage():$localeID));
  408     }
  409 
  410     /**
  411      * Returns the directory that contains the locale data.
  412      * @return string the directory that contains the locale data. It defaults to 'framework/i18n/data'.
  413      * @since 1.1.0
  414      */
  415     public function getLocaleDataPath()
  416     {
  417         $vars=get_class_vars($this->localeClass);
  418         if(empty($vars['dataPath']))
  419             return Yii::getPathOfAlias('system.i18n.data');
  420         return $vars['dataPath'];
  421     }
  422 
  423     /**
  424      * Sets the directory that contains the locale data.
  425      * @param string $value the directory that contains the locale data.
  426      * @since 1.1.0
  427      */
  428     public function setLocaleDataPath($value)
  429     {
  430         $property=new ReflectionProperty($this->localeClass,'dataPath');
  431         $property->setValue($value);
  432     }
  433 
  434     /**
  435      * @return CNumberFormatter the locale-dependent number formatter.
  436      * The current {@link getLocale application locale} will be used.
  437      */
  438     public function getNumberFormatter()
  439     {
  440         return $this->getLocale()->getNumberFormatter();
  441     }
  442 
  443     /**
  444      * Returns the locale-dependent date formatter.
  445      * @return CDateFormatter the locale-dependent date formatter.
  446      * The current {@link getLocale application locale} will be used.
  447      */
  448     public function getDateFormatter()
  449     {
  450         return $this->getLocale()->getDateFormatter();
  451     }
  452 
  453     /**
  454      * Returns the database connection component.
  455      * @return CDbConnection the database connection
  456      */
  457     public function getDb()
  458     {
  459         return $this->getComponent('db');
  460     }
  461 
  462     /**
  463      * Returns the error handler component.
  464      * @return CErrorHandler the error handler application component.
  465      */
  466     public function getErrorHandler()
  467     {
  468         return $this->getComponent('errorHandler');
  469     }
  470 
  471     /**
  472      * Returns the security manager component.
  473      * @return CSecurityManager the security manager application component.
  474      */
  475     public function getSecurityManager()
  476     {
  477         return $this->getComponent('securityManager');
  478     }
  479 
  480     /**
  481      * Returns the state persister component.
  482      * @return CStatePersister the state persister application component.
  483      */
  484     public function getStatePersister()
  485     {
  486         return $this->getComponent('statePersister');
  487     }
  488 
  489     /**
  490      * Returns the cache component.
  491      * @return CCache the cache application component. Null if the component is not enabled.
  492      */
  493     public function getCache()
  494     {
  495         return $this->getComponent('cache');
  496     }
  497 
  498     /**
  499      * Returns the core message translations component.
  500      * @return CPhpMessageSource the core message translations
  501      */
  502     public function getCoreMessages()
  503     {
  504         return $this->getComponent('coreMessages');
  505     }
  506 
  507     /**
  508      * Returns the application message translations component.
  509      * @return CMessageSource the application message translations
  510      */
  511     public function getMessages()
  512     {
  513         return $this->getComponent('messages');
  514     }
  515 
  516     /**
  517      * Returns the request component.
  518      * @return CHttpRequest the request component
  519      */
  520     public function getRequest()
  521     {
  522         return $this->getComponent('request');
  523     }
  524 
  525     /**
  526      * Returns the URL manager component.
  527      * @return CUrlManager the URL manager component
  528      */
  529     public function getUrlManager()
  530     {
  531         return $this->getComponent('urlManager');
  532     }
  533 
  534     /**
  535      * Returns the formatter component.
  536      * @return CFormatter the formatter component
  537      */
  538     public function getFormat()
  539     {
  540         return $this->getComponent('format');
  541     }
  542 
  543     /**
  544      * @return CController the currently active controller. Null is returned in this base class.
  545      * @since 1.1.8
  546      */
  547     public function getController()
  548     {
  549         return null;
  550     }
  551 
  552     /**
  553      * Creates a relative URL based on the given controller and action information.
  554      * @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
  555      * @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
  556      * @param string $ampersand the token separating name-value pairs in the URL.
  557      * @return string the constructed URL
  558      */
  559     public function createUrl($route,$params=array(),$ampersand='&')
  560     {
  561         return $this->getUrlManager()->createUrl($route,$params,$ampersand);
  562     }
  563 
  564     /**
  565      * Creates an absolute URL based on the given controller and action information.
  566      * @param string $route the URL route. This should be in the format of 'ControllerID/ActionID'.
  567      * @param array $params additional GET parameters (name=>value). Both the name and value will be URL-encoded.
  568      * @param string $schema schema to use (e.g. http, https). If empty, the schema used for the current request will be used.
  569      * @param string $ampersand the token separating name-value pairs in the URL.
  570      * @return string the constructed URL
  571      */
  572     public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
  573     {
  574         $url=$this->createUrl($route,$params,$ampersand);
  575         if(strpos($url,'http')===0 || strpos($url,'//')===0)
  576             return $url;
  577         else
  578             return $this->getRequest()->getHostInfo($schema).$url;
  579     }
  580 
  581     /**
  582      * Returns the relative URL for the application.
  583      * This is a shortcut method to {@link CHttpRequest::getBaseUrl()}.
  584      * @param boolean $absolute whether to return an absolute URL. Defaults to false, meaning returning a relative one.
  585      * @return string the relative URL for the application
  586      * @see CHttpRequest::getBaseUrl()
  587      */
  588     public function getBaseUrl($absolute=false)
  589     {
  590         return $this->getRequest()->getBaseUrl($absolute);
  591     }
  592 
  593     /**
  594      * @return string the homepage URL
  595      */
  596     public function getHomeUrl()
  597     {
  598         if($this->_homeUrl===null)
  599         {
  600             if($this->getUrlManager()->showScriptName)
  601                 return $this->getRequest()->getScriptUrl();
  602             else
  603                 return $this->getRequest()->getBaseUrl().'/';
  604         }
  605         else
  606             return $this->_homeUrl;
  607     }
  608 
  609     /**
  610      * @param string $value the homepage URL
  611      */
  612     public function setHomeUrl($value)
  613     {
  614         $this->_homeUrl=$value;
  615     }
  616 
  617     /**
  618      * Returns a global value.
  619      *
  620      * A global value is one that is persistent across users sessions and requests.
  621      * @param string $key the name of the value to be returned
  622      * @param mixed $defaultValue the default value. If the named global value is not found, this will be returned instead.
  623      * @return mixed the named global value
  624      * @see setGlobalState
  625      */
  626     public function getGlobalState($key,$defaultValue=null)
  627     {
  628         if($this->_globalState===null)
  629             $this->loadGlobalState();
  630         if(isset($this->_globalState[$key]))
  631             return $this->_globalState[$key];
  632         else
  633             return $defaultValue;
  634     }
  635 
  636     /**
  637      * Sets a global value.
  638      *
  639      * A global value is one that is persistent across users sessions and requests.
  640      * Make sure that the value is serializable and unserializable.
  641      * @param string $key the name of the value to be saved
  642      * @param mixed $value the global value to be saved. It must be serializable.
  643      * @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.
  644      * @see getGlobalState
  645      */
  646     public function setGlobalState($key,$value,$defaultValue=null)
  647     {
  648         if($this->_globalState===null)
  649             $this->loadGlobalState();
  650 
  651         $changed=$this->_stateChanged;
  652         if($value===$defaultValue)
  653         {
  654             if(isset($this->_globalState[$key]))
  655             {
  656                 unset($this->_globalState[$key]);
  657                 $this->_stateChanged=true;
  658             }
  659         }
  660         elseif(!isset($this->_globalState[$key]) || $this->_globalState[$key]!==$value)
  661         {
  662             $this->_globalState[$key]=$value;
  663             $this->_stateChanged=true;
  664         }
  665 
  666         if($this->_stateChanged!==$changed)
  667             $this->attachEventHandler('onEndRequest',array($this,'saveGlobalState'));
  668     }
  669 
  670     /**
  671      * Clears a global value.
  672      *
  673      * The value cleared will no longer be available in this request and the following requests.
  674      * @param string $key the name of the value to be cleared
  675      */
  676     public function clearGlobalState($key)
  677     {
  678         $this->setGlobalState($key,true,true);
  679     }
  680 
  681     /**
  682      * Loads the global state data from persistent storage.
  683      * @see getStatePersister
  684      * @throws CException if the state persister is not available
  685      */
  686     public function loadGlobalState()
  687     {
  688         $persister=$this->getStatePersister();
  689         if(($this->_globalState=$persister->load())===null)
  690             $this->_globalState=array();
  691         $this->_stateChanged=false;
  692         $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
  693     }
  694 
  695     /**
  696      * Saves the global state data into persistent storage.
  697      * @see getStatePersister
  698      * @throws CException if the state persister is not available
  699      */
  700     public function saveGlobalState()
  701     {
  702         if($this->_stateChanged)
  703         {
  704             $this->_stateChanged=false;
  705             $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
  706             $this->getStatePersister()->save($this->_globalState);
  707         }
  708     }
  709 
  710     /**
  711      * Handles uncaught PHP exceptions.
  712      *
  713      * This method is implemented as a PHP exception handler. It requires
  714      * that constant YII_ENABLE_EXCEPTION_HANDLER be defined true.
  715      *
  716      * This method will first raise an {@link onException} event.
  717      * If the exception is not handled by any event handler, it will call
  718      * {@link getErrorHandler errorHandler} to process the exception.
  719      *
  720      * The application will be terminated by this method.
  721      *
  722      * @param Exception $exception exception that is not caught
  723      */
  724     public function handleException($exception)
  725     {
  726         // disable error capturing to avoid recursive errors
  727         restore_error_handler();
  728         restore_exception_handler();
  729 
  730         $category='exception.'.get_class($exception);
  731         if($exception instanceof CHttpException)
  732             $category.='.'.$exception->statusCode;
  733         // php <5.2 doesn't support string conversion auto-magically
  734         $message=$exception->__toString();
  735         if(isset($_SERVER['REQUEST_URI']))
  736             $message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI'];
  737         if(isset($_SERVER['HTTP_REFERER']))
  738             $message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER'];
  739         $message.="\n---";
  740         Yii::log($message,CLogger::LEVEL_ERROR,$category);
  741 
  742         try
  743         {
  744             $event=new CExceptionEvent($this,$exception);
  745             $this->onException($event);
  746             if(!$event->handled)
  747             {
  748                 // try an error handler
  749                 if(($handler=$this->getErrorHandler())!==null)
  750                     $handler->handle($event);
  751                 else
  752                     $this->displayException($exception);
  753             }
  754         }
  755         catch(Exception $e)
  756         {
  757             $this->displayException($e);
  758         }
  759 
  760         try
  761         {
  762             $this->end(1);
  763         }
  764         catch(Exception $e)
  765         {
  766             // use the most primitive way to log error
  767             $msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
  768             $msg .= $e->getTraceAsString()."\n";
  769             $msg .= "Previous exception:\n";
  770             $msg .= get_class($exception).': '.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().")\n";
  771             $msg .= $exception->getTraceAsString()."\n";
  772             $msg .= '$_SERVER='.var_export($_SERVER,true);
  773             error_log($msg);
  774             exit(1);
  775         }
  776     }
  777 
  778     /**
  779      * Handles PHP execution errors such as warnings, notices.
  780      *
  781      * This method is implemented as a PHP error handler. It requires
  782      * that constant YII_ENABLE_ERROR_HANDLER be defined true.
  783      *
  784      * This method will first raise an {@link onError} event.
  785      * If the error is not handled by any event handler, it will call
  786      * {@link getErrorHandler errorHandler} to process the error.
  787      *
  788      * The application will be terminated by this method.
  789      *
  790      * @param integer $code the level of the error raised
  791      * @param string $message the error message
  792      * @param string $file the filename that the error was raised in
  793      * @param integer $line the line number the error was raised at
  794      */
  795     public function handleError($code,$message,$file,$line)
  796     {
  797         if($code & error_reporting())
  798         {
  799             // disable error capturing to avoid recursive errors
  800             restore_error_handler();
  801             restore_exception_handler();
  802 
  803             $log="$message ($file:$line)\nStack trace:\n";
  804             $trace=debug_backtrace();
  805             array_shift($trace);
  806             foreach($trace as $i=>$t)
  807             {
  808                 if(!isset($t['file']))
  809                     $t['file']='unknown';
  810                 if(!isset($t['line']))
  811                     $t['line']=0;
  812                 if(!isset($t['function']))
  813                     $t['function']='unknown';
  814                 $log.="#$i {$t['file']}({$t['line']}): ";
  815                 if(isset($t['object']) && is_object($t['object']))
  816                     $log.=get_class($t['object']).'->';
  817                 $log.="{$t['function']}()\n";
  818             }
  819             if(isset($_SERVER['REQUEST_URI']))
  820                 $log.='REQUEST_URI='.$_SERVER['REQUEST_URI'];
  821             Yii::log($log,CLogger::LEVEL_ERROR,'php');
  822 
  823             try
  824             {
  825                 Yii::import('CErrorEvent',true);
  826                 $event=new CErrorEvent($this,$code,$message,$file,$line);
  827                 $this->onError($event);
  828                 if(!$event->handled)
  829                 {
  830                     // try an error handler
  831                     if(($handler=$this->getErrorHandler())!==null)
  832                         $handler->handle($event);
  833                     else
  834                         $this->displayError($code,$message,$file,$line);
  835                 }
  836             }
  837             catch(Exception $e)
  838             {
  839                 $this->displayException($e);
  840             }
  841 
  842             try
  843             {
  844                 $this->end(1);
  845             }
  846             catch(Exception $e)
  847             {
  848                 // use the most primitive way to log error
  849                 $msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
  850                 $msg .= $e->getTraceAsString()."\n";
  851                 $msg .= "Previous error:\n";
  852                 $msg .= $log."\n";
  853                 $msg .= '$_SERVER='.var_export($_SERVER,true);
  854                 error_log($msg);
  855                 exit(1);
  856             }
  857         }
  858     }
  859 
  860     /**
  861      * Raised when an uncaught PHP exception occurs.
  862      *
  863      * An event handler can set the {@link CExceptionEvent::handled handled}
  864      * property of the event parameter to be true to indicate no further error
  865      * handling is needed. Otherwise, the {@link getErrorHandler errorHandler}
  866      * application component will continue processing the error.
  867      *
  868      * @param CExceptionEvent $event event parameter
  869      */
  870     public function onException($event)
  871     {
  872         $this->raiseEvent('onException',$event);
  873     }
  874 
  875     /**
  876      * Raised when a PHP execution error occurs.
  877      *
  878      * An event handler can set the {@link CErrorEvent::handled handled}
  879      * property of the event parameter to be true to indicate no further error
  880      * handling is needed. Otherwise, the {@link getErrorHandler errorHandler}
  881      * application component will continue processing the error.
  882      *
  883      * @param CErrorEvent $event event parameter
  884      */
  885     public function onError($event)
  886     {
  887         $this->raiseEvent('onError',$event);
  888     }
  889 
  890     /**
  891      * Displays the captured PHP error.
  892      * This method displays the error in HTML when there is
  893      * no active error handler.
  894      * @param integer $code error code
  895      * @param string $message error message
  896      * @param string $file error file
  897      * @param string $line error line
  898      */
  899     public function displayError($code,$message,$file,$line)
  900     {
  901         if(YII_DEBUG)
  902         {
  903             echo "<h1>PHP Error [$code]</h1>\n";
  904             echo "<p>$message ($file:$line)</p>\n";
  905             echo '<pre>';
  906 
  907             $trace=debug_backtrace();
  908             // skip the first 2 stacks as they are always irrelevant
  909             if(count($trace)>2)
  910                 $trace=array_slice($trace,2);
  911             foreach($trace as $i=>$t)
  912             {
  913                 if(!isset($t['file']))
  914                     $t['file']='unknown';
  915                 if(!isset($t['line']))
  916                     $t['line']=0;
  917                 if(!isset($t['function']))
  918                     $t['function']='unknown';
  919                 echo "#$i {$t['file']}({$t['line']}): ";
  920                 if(isset($t['object']) && is_object($t['object']))
  921                     echo get_class($t['object']).'->';
  922                 echo "{$t['function']}()\n";
  923             }
  924 
  925             echo '</pre>';
  926         }
  927         else
  928         {
  929             echo "<h1>PHP Error [$code]</h1>\n";
  930             echo "<p>$message</p>\n";
  931         }
  932     }
  933 
  934     /**
  935      * Displays the uncaught PHP exception.
  936      * This method displays the exception in HTML when there is
  937      * no active error handler.
  938      * @param Exception $exception the uncaught exception
  939      */
  940     public function displayException($exception)
  941     {
  942         if(YII_DEBUG)
  943         {
  944             echo '<h1>'.get_class($exception)."</h1>\n";
  945             echo '<p>'.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().')</p>';
  946             echo '<pre>'.$exception->getTraceAsString().'</pre>';
  947         }
  948         else
  949         {
  950             echo '<h1>'.get_class($exception)."</h1>\n";
  951             echo '<p>'.$exception->getMessage().'</p>';
  952         }
  953     }
  954 
  955     /**
  956      * Initializes the error handlers.
  957      */
  958     protected function initSystemHandlers()
  959     {
  960         if(YII_ENABLE_EXCEPTION_HANDLER)
  961             set_exception_handler(array($this,'handleException'));
  962         if(YII_ENABLE_ERROR_HANDLER)
  963             set_error_handler(array($this,'handleError'),error_reporting());
  964     }
  965 
  966     /**
  967      * Registers the core application components.
  968      * @see setComponents
  969      */
  970     protected function registerCoreComponents()
  971     {
  972         $components=array(
  973             'coreMessages'=>array(
  974                 'class'=>'CPhpMessageSource',
  975                 'language'=>'en_us',
  976                 'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages',
  977             ),
  978             'db'=>array(
  979                 'class'=>'CDbConnection',
  980             ),
  981             'messages'=>array(
  982                 'class'=>'CPhpMessageSource',
  983             ),
  984             'errorHandler'=>array(
  985                 'class'=>'CErrorHandler',
  986             ),
  987             'securityManager'=>array(
  988                 'class'=>'CSecurityManager',
  989             ),
  990             'statePersister'=>array(
  991                 'class'=>'CStatePersister',
  992             ),
  993             'urlManager'=>array(
  994                 'class'=>'CUrlManager',
  995             ),
  996             'request'=>array(
  997                 'class'=>'CHttpRequest',
  998             ),
  999             'format'=>array(
 1000                 'class'=>'CFormatter',
 1001             ),
 1002         );
 1003 
 1004         $this->setComponents($components);
 1005     }
 1006 }