10 changed files with 1528 additions and 70 deletions
			
			
		@ -0,0 +1,156 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CDbLogRoute class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CDbLogRoute stores log messages in a database table. | 
				
			||||
 * | 
				
			||||
 * To specify the database table for storing log messages, set {@link logTableName} as | 
				
			||||
 * the name of the table and specify {@link connectionID} to be the ID of a {@link CDbConnection} | 
				
			||||
 * application component. If they are not set, a SQLite3 database named 'log-YiiVersion.db' will be created | 
				
			||||
 * and used under the application runtime directory. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CDbLogRoute.php 3069 2011-03-14 00:28:38Z qiang.xue $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0 | 
				
			||||
 */ | 
				
			||||
class CDbLogRoute extends CLogRoute | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var string the ID of CDbConnection application component. If not set, a SQLite database | 
				
			||||
	 * will be automatically created and used. The SQLite database file is | 
				
			||||
	 * <code>protected/runtime/log-YiiVersion.db</code>. | 
				
			||||
	 */ | 
				
			||||
	public $connectionID; | 
				
			||||
	/** | 
				
			||||
	 * @var string the name of the DB table that stores log content. Defaults to 'YiiLog'. | 
				
			||||
	 * If {@link autoCreateLogTable} is false and you want to create the DB table manually by yourself, | 
				
			||||
	 * you need to make sure the DB table is of the following structure: | 
				
			||||
	 * <pre> | 
				
			||||
	 *  ( | 
				
			||||
	 *		id       INTEGER NOT NULL PRIMARY KEY, | 
				
			||||
	 *		level    VARCHAR(128), | 
				
			||||
	 *		category VARCHAR(128), | 
				
			||||
	 *		logtime  INTEGER, | 
				
			||||
	 *		message  TEXT | 
				
			||||
	 *   ) | 
				
			||||
	 * </pre> | 
				
			||||
	 * Note, the 'id' column must be created as an auto-incremental column. | 
				
			||||
	 * In MySQL, this means it should be <code>id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY</code>; | 
				
			||||
	 * In PostgreSQL, it is <code>id SERIAL PRIMARY KEY</code>. | 
				
			||||
	 * @see autoCreateLogTable | 
				
			||||
	 */ | 
				
			||||
	public $logTableName = 'YiiLog'; | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether the log DB table should be automatically created if not exists. Defaults to true. | 
				
			||||
	 * @see logTableName | 
				
			||||
	 */ | 
				
			||||
	public $autoCreateLogTable = true; | 
				
			||||
	/** | 
				
			||||
	 * @var CDbConnection the DB connection instance | 
				
			||||
	 */ | 
				
			||||
	private $_db; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Initializes the route. | 
				
			||||
	 * This method is invoked after the route is created by the route manager. | 
				
			||||
	 */ | 
				
			||||
	public function init() | 
				
			||||
	{ | 
				
			||||
		parent::init(); | 
				
			||||
 | 
				
			||||
		if ($this->autoCreateLogTable) | 
				
			||||
		{ | 
				
			||||
			$db = $this->getDbConnection(); | 
				
			||||
			$sql = "DELETE FROM  {$this->logTableName} WHERE 0=1"; | 
				
			||||
			try | 
				
			||||
			{ | 
				
			||||
				$db->createCommand($sql)->execute(); | 
				
			||||
			} | 
				
			||||
			catch(Exception $e) | 
				
			||||
			{ | 
				
			||||
				$this->createLogTable($db, $this->logTableName); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Creates the DB table for storing log messages. | 
				
			||||
	 * @param CDbConnection $db the database connection | 
				
			||||
	 * @param string $tableName the name of the table to be created | 
				
			||||
	 */ | 
				
			||||
	protected function createLogTable($db, $tableName) | 
				
			||||
	{ | 
				
			||||
		$driver = $db->getDriverName(); | 
				
			||||
		if ($driver === 'mysql') | 
				
			||||
			$logID = 'id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY'; | 
				
			||||
		elseif ($driver === 'pgsql') | 
				
			||||
			$logID = 'id SERIAL PRIMARY KEY'; | 
				
			||||
		else | 
				
			||||
			$logID = 'id INTEGER NOT NULL PRIMARY KEY'; | 
				
			||||
 | 
				
			||||
		$sql = " | 
				
			||||
CREATE TABLE $tableName | 
				
			||||
( | 
				
			||||
	$logID, | 
				
			||||
	level VARCHAR(128), | 
				
			||||
	category VARCHAR(128), | 
				
			||||
	logtime INTEGER, | 
				
			||||
	message TEXT | 
				
			||||
)"; | 
				
			||||
		$db->createCommand($sql)->execute(); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return CDbConnection the DB connection instance | 
				
			||||
	 * @throws CException if {@link connectionID} does not point to a valid application component. | 
				
			||||
	 */ | 
				
			||||
	protected function getDbConnection() | 
				
			||||
	{ | 
				
			||||
		if ($this->_db !== null) | 
				
			||||
			return $this->_db; | 
				
			||||
		elseif (($id = $this->connectionID) !== null) | 
				
			||||
		{ | 
				
			||||
			if (($this->_db = Yii::app()->getComponent($id)) instanceof CDbConnection) | 
				
			||||
				return $this->_db; | 
				
			||||
			else | 
				
			||||
				throw new CException(Yii::t('yii', 'CDbLogRoute.connectionID "{id}" does not point to a valid CDbConnection application component.', | 
				
			||||
					array('{id}' => $id))); | 
				
			||||
		} | 
				
			||||
		else | 
				
			||||
		{ | 
				
			||||
			$dbFile = Yii::app()->getRuntimePath() . DIRECTORY_SEPARATOR . 'log-' . Yii::getVersion() . '.db'; | 
				
			||||
			return $this->_db = new CDbConnection('sqlite:' . $dbFile); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Stores log messages into database. | 
				
			||||
	 * @param array $logs list of log messages | 
				
			||||
	 */ | 
				
			||||
	protected function processLogs($logs) | 
				
			||||
	{ | 
				
			||||
		$sql = " | 
				
			||||
INSERT INTO  {$this->logTableName} | 
				
			||||
(level, category, logtime, message) VALUES | 
				
			||||
(:level, :category, :logtime, :message) | 
				
			||||
"; | 
				
			||||
		$command = $this->getDbConnection()->createCommand($sql); | 
				
			||||
		foreach ($logs as $log) | 
				
			||||
		{ | 
				
			||||
			$command->bindValue(':level', $log[1]); | 
				
			||||
			$command->bindValue(':category', $log[2]); | 
				
			||||
			$command->bindValue(':logtime', (int)$log[3]); | 
				
			||||
			$command->bindValue(':message', $log[0]); | 
				
			||||
			$command->execute(); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,146 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CEmailLogRoute class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CEmailLogRoute sends selected log messages to email addresses. | 
				
			||||
 * | 
				
			||||
 * The target email addresses may be specified via {@link setEmails emails} property. | 
				
			||||
 * Optionally, you may set the email {@link setSubject subject}, the | 
				
			||||
 * {@link setSentFrom sentFrom} address and any additional {@link setHeaders headers}. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CEmailLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0 | 
				
			||||
 */ | 
				
			||||
class CEmailLogRoute extends CLogRoute | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var array list of destination email addresses. | 
				
			||||
	 */ | 
				
			||||
	private $_email = array(); | 
				
			||||
	/** | 
				
			||||
	 * @var string email subject | 
				
			||||
	 */ | 
				
			||||
	private $_subject; | 
				
			||||
	/** | 
				
			||||
	 * @var string email sent from address | 
				
			||||
	 */ | 
				
			||||
	private $_from; | 
				
			||||
	/** | 
				
			||||
	 * @var array list of additional headers to use when sending an email. | 
				
			||||
	 */ | 
				
			||||
	private $_headers = array(); | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Sends log messages to specified email addresses. | 
				
			||||
	 * @param array $logs list of log messages | 
				
			||||
	 */ | 
				
			||||
	protected function processLogs($logs) | 
				
			||||
	{ | 
				
			||||
		$message = ''; | 
				
			||||
		foreach ($logs as $log) | 
				
			||||
			$message .= $this->formatLogMessage($log[0], $log[1], $log[2], $log[3]); | 
				
			||||
		$message = wordwrap($message, 70); | 
				
			||||
		$subject = $this->getSubject(); | 
				
			||||
		if ($subject === null) | 
				
			||||
			$subject = Yii::t('yii', 'Application Log'); | 
				
			||||
		foreach ($this->getEmails() as $email) | 
				
			||||
			$this->sendEmail($email, $subject, $message); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Sends an email. | 
				
			||||
	 * @param string $email single email address | 
				
			||||
	 * @param string $subject email subject | 
				
			||||
	 * @param string $message email content | 
				
			||||
	 */ | 
				
			||||
	protected function sendEmail($email, $subject, $message) | 
				
			||||
	{ | 
				
			||||
		$headers = $this->getHeaders(); | 
				
			||||
		if (($from = $this->getSentFrom()) !== null) | 
				
			||||
			$headers[] = "From:  {$from}"; | 
				
			||||
		mail($email, $subject, $message, implode("\r\n", $headers)); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return array list of destination email addresses | 
				
			||||
	 */ | 
				
			||||
	public function getEmails() | 
				
			||||
	{ | 
				
			||||
		return $this->_email; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param mixed $value list of destination email addresses. If the value is | 
				
			||||
	 * a string, it is assumed to be comma-separated email addresses. | 
				
			||||
	 */ | 
				
			||||
	public function setEmails($value) | 
				
			||||
	{ | 
				
			||||
		if (is_array($value)) | 
				
			||||
			$this->_email = $value; | 
				
			||||
		else | 
				
			||||
			$this->_email = preg_split('/[\s,]+/', $value, -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return string email subject. Defaults to CEmailLogRoute::DEFAULT_SUBJECT | 
				
			||||
	 */ | 
				
			||||
	public function getSubject() | 
				
			||||
	{ | 
				
			||||
		return $this->_subject; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param string $value email subject. | 
				
			||||
	 */ | 
				
			||||
	public function setSubject($value) | 
				
			||||
	{ | 
				
			||||
		$this->_subject = $value; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return string send from address of the email | 
				
			||||
	 */ | 
				
			||||
	public function getSentFrom() | 
				
			||||
	{ | 
				
			||||
		return $this->_from; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param string $value send from address of the email | 
				
			||||
	 */ | 
				
			||||
	public function setSentFrom($value) | 
				
			||||
	{ | 
				
			||||
		$this->_from = $value; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return array additional headers to use when sending an email. | 
				
			||||
	 * @since 1.1.4 | 
				
			||||
	 */ | 
				
			||||
	public function getHeaders() | 
				
			||||
	{ | 
				
			||||
		return $this->_headers; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param mixed $value list of additional headers to use when sending an email. | 
				
			||||
	 * If the value is a string, it is assumed to be line break separated headers. | 
				
			||||
	 * @since 1.1.4 | 
				
			||||
	 */ | 
				
			||||
	public function setHeaders($value) | 
				
			||||
	{ | 
				
			||||
		if (is_array($value)) | 
				
			||||
			$this->_headers = $value; | 
				
			||||
		else | 
				
			||||
			$this->_headers = preg_split('/\r\n|\n/', $value, -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,167 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CFileLogRoute class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CFileLogRoute records log messages in files. | 
				
			||||
 * | 
				
			||||
 * The log files are stored under {@link setLogPath logPath} and the file name | 
				
			||||
 * is specified by {@link setLogFile logFile}. If the size of the log file is | 
				
			||||
 * greater than {@link setMaxFileSize maxFileSize} (in kilo-bytes), a rotation | 
				
			||||
 * is performed, which renames the current log file by suffixing the file name | 
				
			||||
 * with '.1'. All existing log files are moved backwards one place, i.e., '.2' | 
				
			||||
 * to '.3', '.1' to '.2'. The property {@link setMaxLogFiles maxLogFiles} | 
				
			||||
 * specifies how many files to be kept. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CFileLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0 | 
				
			||||
 */ | 
				
			||||
class CFileLogRoute extends CLogRoute | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var integer maximum log file size | 
				
			||||
	 */ | 
				
			||||
	private $_maxFileSize = 1024; // in KB | 
				
			||||
	/** | 
				
			||||
	 * @var integer number of log files used for rotation | 
				
			||||
	 */ | 
				
			||||
	private $_maxLogFiles = 5; | 
				
			||||
	/** | 
				
			||||
	 * @var string directory storing log files | 
				
			||||
	 */ | 
				
			||||
	private $_logPath; | 
				
			||||
	/** | 
				
			||||
	 * @var string log file name | 
				
			||||
	 */ | 
				
			||||
	private $_logFile = 'application.log'; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Initializes the route. | 
				
			||||
	 * This method is invoked after the route is created by the route manager. | 
				
			||||
	 */ | 
				
			||||
	public function init() | 
				
			||||
	{ | 
				
			||||
		parent::init(); | 
				
			||||
		if ($this->getLogPath() === null) | 
				
			||||
			$this->setLogPath(Yii::app()->getRuntimePath()); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return string directory storing log files. Defaults to application runtime path. | 
				
			||||
	 */ | 
				
			||||
	public function getLogPath() | 
				
			||||
	{ | 
				
			||||
		return $this->_logPath; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param string $value directory for storing log files. | 
				
			||||
	 * @throws CException if the path is invalid | 
				
			||||
	 */ | 
				
			||||
	public function setLogPath($value) | 
				
			||||
	{ | 
				
			||||
		$this->_logPath = realpath($value); | 
				
			||||
		if ($this->_logPath === false || !is_dir($this->_logPath) || !is_writable($this->_logPath)) | 
				
			||||
			throw new CException(Yii::t('yii', 'CFileLogRoute.logPath "{path}" does not point to a valid directory. Make sure the directory exists and is writable by the Web server process.', | 
				
			||||
				array('{path}' => $value))); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return string log file name. Defaults to 'application.log'. | 
				
			||||
	 */ | 
				
			||||
	public function getLogFile() | 
				
			||||
	{ | 
				
			||||
		return $this->_logFile; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param string $value log file name | 
				
			||||
	 */ | 
				
			||||
	public function setLogFile($value) | 
				
			||||
	{ | 
				
			||||
		$this->_logFile = $value; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return integer maximum log file size in kilo-bytes (KB). Defaults to 1024 (1MB). | 
				
			||||
	 */ | 
				
			||||
	public function getMaxFileSize() | 
				
			||||
	{ | 
				
			||||
		return $this->_maxFileSize; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param integer $value maximum log file size in kilo-bytes (KB). | 
				
			||||
	 */ | 
				
			||||
	public function setMaxFileSize($value) | 
				
			||||
	{ | 
				
			||||
		if (($this->_maxFileSize = (int)$value) < 1) | 
				
			||||
			$this->_maxFileSize = 1; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return integer number of files used for rotation. Defaults to 5. | 
				
			||||
	 */ | 
				
			||||
	public function getMaxLogFiles() | 
				
			||||
	{ | 
				
			||||
		return $this->_maxLogFiles; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param integer $value number of files used for rotation. | 
				
			||||
	 */ | 
				
			||||
	public function setMaxLogFiles($value) | 
				
			||||
	{ | 
				
			||||
		if (($this->_maxLogFiles = (int)$value) < 1) | 
				
			||||
			$this->_maxLogFiles = 1; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Saves log messages in files. | 
				
			||||
	 * @param array $logs list of log messages | 
				
			||||
	 */ | 
				
			||||
	protected function processLogs($logs) | 
				
			||||
	{ | 
				
			||||
		$logFile = $this->getLogPath() . DIRECTORY_SEPARATOR . $this->getLogFile(); | 
				
			||||
		if (@filesize($logFile) > $this->getMaxFileSize() * 1024) | 
				
			||||
			$this->rotateFiles(); | 
				
			||||
		$fp = @fopen($logFile, 'a'); | 
				
			||||
		@flock($fp, LOCK_EX); | 
				
			||||
		foreach ($logs as $log) | 
				
			||||
			@fwrite($fp, $this->formatLogMessage($log[0], $log[1], $log[2], $log[3])); | 
				
			||||
		@flock($fp, LOCK_UN); | 
				
			||||
		@fclose($fp); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Rotates log files. | 
				
			||||
	 */ | 
				
			||||
	protected function rotateFiles() | 
				
			||||
	{ | 
				
			||||
		$file = $this->getLogPath() . DIRECTORY_SEPARATOR . $this->getLogFile(); | 
				
			||||
		$max = $this->getMaxLogFiles(); | 
				
			||||
		for ($i = $max;$i > 0;--$i) | 
				
			||||
		{ | 
				
			||||
			$rotateFile = $file . '.' . $i; | 
				
			||||
			if (is_file($rotateFile)) | 
				
			||||
			{ | 
				
			||||
				// suppress errors because it's possible multiple processes enter into this section | 
				
			||||
				if ($i === $max) | 
				
			||||
					@unlink($rotateFile); | 
				
			||||
				else | 
				
			||||
					@rename($rotateFile, $file . '.' . ($i + 1)); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		if (is_file($file)) | 
				
			||||
			@rename($file, $file . '.1'); // suppress errors because it's possible multiple processes enter into this section | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,107 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CLogFilter class file | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CLogFilter preprocesses the logged messages before they are handled by a log route. | 
				
			||||
 * | 
				
			||||
 * CLogFilter is meant to be used by a log route to preprocess the logged messages | 
				
			||||
 * before they are handled by the route. The default implementation of CLogFilter | 
				
			||||
 * prepends additional context information to the logged messages. In particular, | 
				
			||||
 * by setting {@link logVars}, predefined PHP variables such as | 
				
			||||
 * $_SERVER, $_POST, etc. can be saved as a log message, which may help identify/debug | 
				
			||||
 * issues encountered. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CLogFilter.php 3204 2011-05-05 21:36:32Z alexander.makarow $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0.6 | 
				
			||||
 */ | 
				
			||||
class CLogFilter extends CComponent | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether to prefix each log message with the current user session ID. | 
				
			||||
	 * Defaults to false. | 
				
			||||
	 */ | 
				
			||||
	public $prefixSession = false; | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether to prefix each log message with the current user | 
				
			||||
	 * {@link CWebUser::name name} and {@link CWebUser::id ID}. Defaults to false. | 
				
			||||
	 */ | 
				
			||||
	public $prefixUser = false; | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether to log the current user name and ID. Defaults to true. | 
				
			||||
	 */ | 
				
			||||
	public $logUser = true; | 
				
			||||
	/** | 
				
			||||
	 * @var array list of the PHP predefined variables that should be logged. | 
				
			||||
	 * Note that a variable must be accessible via $GLOBALS. Otherwise it won't be logged. | 
				
			||||
	 */ | 
				
			||||
	public $logVars = array('_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Filters the given log messages. | 
				
			||||
	 * This is the main method of CLogFilter. It processes the log messages | 
				
			||||
	 * by adding context information, etc. | 
				
			||||
	 * @param array $logs the log messages | 
				
			||||
	 * @return array | 
				
			||||
	 */ | 
				
			||||
	public function filter(&$logs) | 
				
			||||
	{ | 
				
			||||
		if (!empty($logs)) | 
				
			||||
		{ | 
				
			||||
			if (($message = $this->getContext()) !== '') | 
				
			||||
				array_unshift($logs, array($message, CLogger::LEVEL_INFO, 'application', YII_BEGIN_TIME)); | 
				
			||||
			$this->format($logs); | 
				
			||||
		} | 
				
			||||
		return $logs; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Formats the log messages. | 
				
			||||
	 * The default implementation will prefix each message with session ID | 
				
			||||
	 * if {@link prefixSession} is set true. It may also prefix each message | 
				
			||||
	 * with the current user's name and ID if {@link prefixUser} is true. | 
				
			||||
	 * @param array $logs the log messages | 
				
			||||
	 */ | 
				
			||||
	protected function format(&$logs) | 
				
			||||
	{ | 
				
			||||
		$prefix = ''; | 
				
			||||
		if ($this->prefixSession && ($id = session_id()) !== '') | 
				
			||||
			$prefix .= "[$id]"; | 
				
			||||
		if ($this->prefixUser && ($user = Yii::app()->getComponent('user', false)) !== null) | 
				
			||||
			$prefix .= '[' . $user->getName() . '][' . $user->getId() . ']'; | 
				
			||||
		if ($prefix !== '') | 
				
			||||
		{ | 
				
			||||
			foreach ($logs as &$log) | 
				
			||||
				$log[0] = $prefix . ' ' . $log[0]; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Generates the context information to be logged. | 
				
			||||
	 * The default implementation will dump user information, system variables, etc. | 
				
			||||
	 * @return string the context information. If an empty string, it means no context information. | 
				
			||||
	 */ | 
				
			||||
	protected function getContext() | 
				
			||||
	{ | 
				
			||||
		$context = array(); | 
				
			||||
		if ($this->logUser && ($user = Yii::app()->getComponent('user', false)) !== null) | 
				
			||||
			$context[] = 'User: ' . $user->getName() . ' (ID: ' . $user->getId() . ')'; | 
				
			||||
 | 
				
			||||
		foreach ($this->logVars as $name) | 
				
			||||
		{ | 
				
			||||
			if (!empty($GLOBALS[$name])) | 
				
			||||
				$context[] = "\$ {$name}=" . var_export($GLOBALS[$name], true); | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		return implode("\n\n", $context); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,320 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * Logger class file | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2012 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
namespace yii\logging; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Logger records logged messages in memory. | 
				
			||||
 * | 
				
			||||
 * When [[flushInterval]] is reached or when application terminates, it will | 
				
			||||
 * call [[flush]] to send logged messages to different log targets, such as | 
				
			||||
 * file, email, Web. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @since 2.0 | 
				
			||||
 */ | 
				
			||||
class Logger extends \yii\base\Component | 
				
			||||
{ | 
				
			||||
	const LEVEL_TRACE = 'trace'; | 
				
			||||
	const LEVEL_WARN = 'warn'; | 
				
			||||
	const LEVEL_ERROR = 'error'; | 
				
			||||
	const LEVEL_INFO = 'info'; | 
				
			||||
	const LEVEL_PROFILE = 'profile'; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @var integer how many messages should be logged before they are flushed from memory and sent to targets. | 
				
			||||
	 * Defaults to 1000, meaning the [[flush]] method will be invoked once every 1000 messages logged. | 
				
			||||
	 * Set this property to be 0 if you don't want to flush messages until the application terminates. | 
				
			||||
	 * This property mainly affects how much memory will be taken by the logged messages. | 
				
			||||
	 * A smaller value means less memory, but will increase the execution time due to the overhead of [[flush]]. | 
				
			||||
	 */ | 
				
			||||
	public $flushInterval = 1000; | 
				
			||||
	/** | 
				
			||||
	 * @var boolean this property will be passed as the parameter to [[flush]] when it is | 
				
			||||
	 * called due to the [[flushInterval]] is reached. Defaults to false, meaning the flushed | 
				
			||||
	 * messages are still kept in the memory by each log target. If this is true, they will | 
				
			||||
	 * be exported to the actual storage medium (e.g. DB, email) defined by each log target. | 
				
			||||
	 * @see flushInterval | 
				
			||||
	 */ | 
				
			||||
	public $autoExport = false; | 
				
			||||
	/** | 
				
			||||
	 * @var array logged messages. This property is mainly managed by [[log]] and [[flush]]. | 
				
			||||
	 */ | 
				
			||||
	public $messages = array(); | 
				
			||||
	/** | 
				
			||||
	 * @var array the profiling results (category, token => time in seconds) | 
				
			||||
	 */ | 
				
			||||
	private $_timings; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Logs an error message. | 
				
			||||
	 * An error message is typically logged when an unrecoverable error occurs | 
				
			||||
	 * during the execution of an application. | 
				
			||||
	 * @param string $message the message to be logged. | 
				
			||||
	 * @param string $category the category of the message. | 
				
			||||
	 */ | 
				
			||||
	public function error($message, $category = 'application') | 
				
			||||
	{ | 
				
			||||
		$this->log($message, self::LEVEL_ERROR, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Logs a trace message. | 
				
			||||
	 * Trace messages are logged mainly for development purpose to see | 
				
			||||
	 * the execution work flow of some code. | 
				
			||||
	 * @param string $message the message to be logged. | 
				
			||||
	 * @param string $category the category of the message. | 
				
			||||
	 */ | 
				
			||||
	public function trace($message, $category = 'application') | 
				
			||||
	{ | 
				
			||||
		$this->log($message, self::LEVEL_TRACE, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Logs a warning message. | 
				
			||||
	 * A warning message is typically logged when an error occurs while the execution | 
				
			||||
	 * can still continue. | 
				
			||||
	 * @param string $message the message to be logged. | 
				
			||||
	 * @param string $category the category of the message. | 
				
			||||
	 */ | 
				
			||||
	public function warn($message, $category = 'application') | 
				
			||||
	{ | 
				
			||||
		$this->log($message, self::LEVEL_TRACE, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Logs an informative message. | 
				
			||||
	 * An informative message is typically logged by an application to keep record of | 
				
			||||
	 * something important (e.g. an administrator logs in). | 
				
			||||
	 * @param string $message the message to be logged. | 
				
			||||
	 * @param string $category the category of the message. | 
				
			||||
	 */ | 
				
			||||
	public function info($message, $category = 'application') | 
				
			||||
	{ | 
				
			||||
		$this->log($message, self::LEVEL_TRACE, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Marks the beginning of a code block for profiling. | 
				
			||||
	 * This has to be matched with a call to [[endProfile]] with the same category name. | 
				
			||||
	 * The begin- and end- calls must also be properly nested. For example, | 
				
			||||
	 * @param string $category the category of this profile block | 
				
			||||
	 * @see endProfile | 
				
			||||
	 */ | 
				
			||||
	public function beginProfile($category) | 
				
			||||
	{ | 
				
			||||
		$this->log('begin', self::LEVEL_PROFILE, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Marks the end of a code block for profiling. | 
				
			||||
	 * This has to be matched with a previous call to [[beginProfile]] with the same category name. | 
				
			||||
	 * @param string $category the category of this profile block | 
				
			||||
	 * @see beginProfile | 
				
			||||
	 */ | 
				
			||||
	public function endProfile($category) | 
				
			||||
	{ | 
				
			||||
		$this->log('end', self::LEVEL_PROFILE, $category); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Logs a message with the given type and category. | 
				
			||||
	 * If `YII_DEBUG` is true and `YII_TRACE_LEVEL` is greater than 0, then additional | 
				
			||||
	 * call stack information about application code will be appended to the message. | 
				
			||||
	 * @param string $message the message to be logged. | 
				
			||||
	 * @param string $level the level of the message. This must be one of the following: | 
				
			||||
	 * 'trace', 'info', 'warn', 'error', 'profile'. | 
				
			||||
	 * @param string $category the category of the message. | 
				
			||||
	 */ | 
				
			||||
	public function log($message, $level, $category) | 
				
			||||
	{ | 
				
			||||
		if (YII_DEBUG && YII_TRACE_LEVEL > 0 && $level !== self::LEVEL_PROFILE) { | 
				
			||||
			$traces = debug_backtrace(); | 
				
			||||
			$count = 0; | 
				
			||||
			foreach ($traces as $trace) { | 
				
			||||
				if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII_DIR) !== 0) { | 
				
			||||
					$message .= "\nin " . $trace['file'] . ' (' . $trace['line'] . ')'; | 
				
			||||
					if (++$count >= YII_TRACE_LEVEL) { | 
				
			||||
						break; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		$this->messages[] = array($message, $level, $category, microtime(true)); | 
				
			||||
		if (count($this->messages) >= $this->flushInterval && $this->flushInterval > 0) { | 
				
			||||
			$this->flush($this->autoExport); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Retrieves log messages. | 
				
			||||
	 * | 
				
			||||
	 * Messages may be filtered by log levels and/or categories. | 
				
			||||
	 * A level filter is specified by a list of levels separated by comma or space | 
				
			||||
	 * (e.g. 'trace, error'). A category filter is similar to level filter | 
				
			||||
	 * (e.g. 'system, system.web'). A difference is that in category filter | 
				
			||||
	 * you can use pattern like 'system.*' to indicate all categories starting | 
				
			||||
	 * with 'system'. | 
				
			||||
	 * | 
				
			||||
	 * If you do not specify level filter, it will bring back logs at all levels. | 
				
			||||
	 * The same applies to category filter. | 
				
			||||
	 * | 
				
			||||
	 * Level filter and category filter are combinational, i.e., only messages | 
				
			||||
	 * satisfying both filter conditions will be returned. | 
				
			||||
	 * | 
				
			||||
	 * @param string $levels level filter | 
				
			||||
	 * @param string $categories category filter | 
				
			||||
	 * @return array list of messages. Each array elements represents one message | 
				
			||||
	 * with the following structure: | 
				
			||||
	 * array( | 
				
			||||
	 *   [0] => message (string) | 
				
			||||
	 *   [1] => level (string) | 
				
			||||
	 *   [2] => category (string) | 
				
			||||
	 *   [3] => timestamp (float, obtained by microtime(true)); | 
				
			||||
	 */ | 
				
			||||
	public function getLogs($levels = '', $categories = '') | 
				
			||||
	{ | 
				
			||||
		$this->_levels = preg_split('/[\s,]+/', strtolower($levels), -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
		$this->_categories = preg_split('/[\s,]+/', strtolower($categories), -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
		if (empty($levels) && empty($categories)) | 
				
			||||
			return $this->_logs; | 
				
			||||
		elseif (empty($levels)) | 
				
			||||
			return array_values(array_filter(array_filter($this->_logs, array($this, 'filterByCategory')))); | 
				
			||||
		elseif (empty($categories)) | 
				
			||||
			return array_values(array_filter(array_filter($this->_logs, array($this, 'filterByLevel')))); | 
				
			||||
		else | 
				
			||||
		{ | 
				
			||||
			$ret = array_values(array_filter(array_filter($this->_logs, array($this, 'filterByLevel')))); | 
				
			||||
			return array_values(array_filter(array_filter($ret, array($this, 'filterByCategory')))); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Filter function used by {@link getLogs} | 
				
			||||
	 * @param array $value element to be filtered | 
				
			||||
	 * @return array valid log, false if not. | 
				
			||||
	 */ | 
				
			||||
	private function filterByCategory($value) | 
				
			||||
	{ | 
				
			||||
		foreach ($this->_categories as $category) | 
				
			||||
		{ | 
				
			||||
			$cat = strtolower($value[2]); | 
				
			||||
			if ($cat === $category || (($c = rtrim($category, '.*')) !== $category && strpos($cat, $c) === 0)) | 
				
			||||
				return $value; | 
				
			||||
		} | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Filter function used by {@link getLogs} | 
				
			||||
	 * @param array $value element to be filtered | 
				
			||||
	 * @return array valid log, false if not. | 
				
			||||
	 */ | 
				
			||||
	private function filterByLevel($value) | 
				
			||||
	{ | 
				
			||||
		return in_array(strtolower($value[1]), $this->_levels) ? $value : false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Returns the total elapsed time since the start of the current request. | 
				
			||||
	 * This method calculates the difference between now and the timestamp | 
				
			||||
	 * defined by constant `YII_BEGIN_TIME` which is evaluated at the beginning | 
				
			||||
	 * of [[YiiBase]] class file. | 
				
			||||
	 * @return float the total elapsed time in seconds for current request. | 
				
			||||
	 */ | 
				
			||||
	public function getExecutionTime() | 
				
			||||
	{ | 
				
			||||
		return microtime(true) - YII_BEGIN_TIME; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Returns the profiling results. | 
				
			||||
	 * The results may be filtered by token and/or category. | 
				
			||||
	 * If no filter is specified, the returned results would be an array with each element | 
				
			||||
	 * being `array($token, $category, $time)`. | 
				
			||||
	 * If a filter is specified, the results would be an array of timings. | 
				
			||||
	 * @param string $token token filter. Defaults to null, meaning not filtered by token. | 
				
			||||
	 * @param string $category category filter. Defaults to null, meaning not filtered by category. | 
				
			||||
	 * @param boolean $refresh whether to refresh the internal timing calculations. If false, | 
				
			||||
	 * only the first time calling this method will the timings be calculated internally. | 
				
			||||
	 * @return array the profiling results. | 
				
			||||
	 */ | 
				
			||||
	public function getProfilingResults($token = null, $category = null, $refresh = false) | 
				
			||||
	{ | 
				
			||||
		if ($this->_timings === null || $refresh) { | 
				
			||||
			$this->calculateTimings(); | 
				
			||||
		} | 
				
			||||
		if ($token === null && $category === null) { | 
				
			||||
			return $this->_timings; | 
				
			||||
		} | 
				
			||||
		$results = array(); | 
				
			||||
		foreach ($this->_timings as $timing) { | 
				
			||||
			if (($category === null || $timing[1] === $category) && ($token === null || $timing[0] === $token)) { | 
				
			||||
				$results[] = $timing[2]; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		return $results; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	private function calculateTimings() | 
				
			||||
	{ | 
				
			||||
		$this->_timings = array(); | 
				
			||||
 | 
				
			||||
		$stack = array(); | 
				
			||||
		foreach ($this->messages as $log) { | 
				
			||||
			if ($log[1] !== self::LEVEL_PROFILE) { | 
				
			||||
				continue; | 
				
			||||
			} | 
				
			||||
			list($message, $level, $category, $timestamp) = $log; | 
				
			||||
			if (!strncasecmp($message, 'begin:', 6)) { | 
				
			||||
				$log[0] = substr($message, 6); | 
				
			||||
				$stack[] = $log; | 
				
			||||
			} | 
				
			||||
			elseif (!strncasecmp($message, 'end:', 4)) { | 
				
			||||
				$token = substr($message, 4); | 
				
			||||
				if (($last = array_pop($stack)) !== null && $last[0] === $token) { | 
				
			||||
					$delta = $log[3] - $last[3]; | 
				
			||||
					$this->_timings[] = array($message, $category, $delta); | 
				
			||||
				} | 
				
			||||
				else { | 
				
			||||
					throw new \yii\base\Exception('Found a mismatching profiling block: ' . $token); | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		$now = microtime(true); | 
				
			||||
		while (($last = array_pop($stack)) !== null) { | 
				
			||||
			$delta = $now - $last[3]; | 
				
			||||
			$this->_timings[] = array($last[0], $last[2], $delta); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Removes all recorded messages from the memory. | 
				
			||||
	 * This method will raise an {@link onFlush} event. | 
				
			||||
	 * The attached event handlers can process the log messages before they are removed. | 
				
			||||
	 * @param boolean $export whether to notify log targets to export the filtered messages they have received. | 
				
			||||
	 */ | 
				
			||||
	public function flush($export = false) | 
				
			||||
	{ | 
				
			||||
		$this->onFlush(new \yii\base\Event($this, array('export' => $export))); | 
				
			||||
		$this->messages = array(); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Raises an `onFlush` event. | 
				
			||||
	 * @param \yii\base\Event $event the event parameter | 
				
			||||
	 */ | 
				
			||||
	public function onFlush($event) | 
				
			||||
	{ | 
				
			||||
		$this->raiseEvent('onFlush', $event); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,201 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CProfileLogRoute class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CProfileLogRoute displays the profiling results in Web page. | 
				
			||||
 * | 
				
			||||
 * The profiling is done by calling {@link YiiBase::beginProfile()} and {@link YiiBase::endProfile()}, | 
				
			||||
 * which marks the begin and end of a code block. | 
				
			||||
 * | 
				
			||||
 * CProfileLogRoute supports two types of report by setting the {@link setReport report} property: | 
				
			||||
 * <ul> | 
				
			||||
 * <li>summary: list the execution time of every marked code block</li> | 
				
			||||
 * <li>callstack: list the mark code blocks in a hierarchical view reflecting their calling sequence.</li> | 
				
			||||
 * </ul> | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CProfileLogRoute.php 3204 2011-05-05 21:36:32Z alexander.makarow $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0 | 
				
			||||
 */ | 
				
			||||
class CProfileLogRoute extends CWebLogRoute | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether to aggregate results according to profiling tokens. | 
				
			||||
	 * If false, the results will be aggregated by categories. | 
				
			||||
	 * Defaults to true. Note that this property only affects the summary report | 
				
			||||
	 * that is enabled when {@link report} is 'summary'. | 
				
			||||
	 * @since 1.0.6 | 
				
			||||
	 */ | 
				
			||||
	public $groupByToken = true; | 
				
			||||
	/** | 
				
			||||
	 * @var string type of profiling report to display | 
				
			||||
	 */ | 
				
			||||
	private $_report = 'summary'; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Initializes the route. | 
				
			||||
	 * This method is invoked after the route is created by the route manager. | 
				
			||||
	 */ | 
				
			||||
	public function init() | 
				
			||||
	{ | 
				
			||||
		$this->levels = CLogger::LEVEL_PROFILE; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @return string the type of the profiling report to display. Defaults to 'summary'. | 
				
			||||
	 */ | 
				
			||||
	public function getReport() | 
				
			||||
	{ | 
				
			||||
		return $this->_report; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @param string $value the type of the profiling report to display. Valid values include 'summary' and 'callstack'. | 
				
			||||
	 */ | 
				
			||||
	public function setReport($value) | 
				
			||||
	{ | 
				
			||||
		if ($value === 'summary' || $value === 'callstack') | 
				
			||||
			$this->_report = $value; | 
				
			||||
		else | 
				
			||||
			throw new CException(Yii::t('yii', 'CProfileLogRoute.report "{report}" is invalid. Valid values include "summary" and "callstack".', | 
				
			||||
				array('{report}' => $value))); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Displays the log messages. | 
				
			||||
	 * @param array $logs list of log messages | 
				
			||||
	 */ | 
				
			||||
	public function processLogs($logs) | 
				
			||||
	{ | 
				
			||||
		$app = Yii::app(); | 
				
			||||
		if (!($app instanceof CWebApplication) || $app->getRequest()->getIsAjaxRequest()) | 
				
			||||
			return; | 
				
			||||
 | 
				
			||||
		if ($this->getReport() === 'summary') | 
				
			||||
			$this->displaySummary($logs); | 
				
			||||
		else | 
				
			||||
			$this->displayCallstack($logs); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Displays the callstack of the profiling procedures for display. | 
				
			||||
	 * @param array $logs list of logs | 
				
			||||
	 */ | 
				
			||||
	protected function displayCallstack($logs) | 
				
			||||
	{ | 
				
			||||
		$stack = array(); | 
				
			||||
		$results = array(); | 
				
			||||
		$n = 0; | 
				
			||||
		foreach ($logs as $log) | 
				
			||||
		{ | 
				
			||||
			if ($log[1] !== CLogger::LEVEL_PROFILE) | 
				
			||||
				continue; | 
				
			||||
			$message = $log[0]; | 
				
			||||
			if (!strncasecmp($message, 'begin:', 6)) | 
				
			||||
			{ | 
				
			||||
				$log[0] = substr($message, 6); | 
				
			||||
				$log[4] = $n; | 
				
			||||
				$stack[] = $log; | 
				
			||||
				$n++; | 
				
			||||
			} | 
				
			||||
			elseif (!strncasecmp($message, 'end:', 4)) | 
				
			||||
			{ | 
				
			||||
				$token = substr($message, 4); | 
				
			||||
				if (($last = array_pop($stack)) !== null && $last[0] === $token) | 
				
			||||
				{ | 
				
			||||
					$delta = $log[3] - $last[3]; | 
				
			||||
					$results[$last[4]] = array($token, $delta, count($stack)); | 
				
			||||
				} | 
				
			||||
				else | 
				
			||||
					throw new CException(Yii::t('yii', 'CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.', | 
				
			||||
						array('{token}' => $token))); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
		// remaining entries should be closed here | 
				
			||||
		$now = microtime(true); | 
				
			||||
		while (($last = array_pop($stack)) !== null) | 
				
			||||
			$results[$last[4]] = array($last[0], $now - $last[3], count($stack)); | 
				
			||||
		ksort($results); | 
				
			||||
		$this->render('profile-callstack', $results); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Displays the summary report of the profiling result. | 
				
			||||
	 * @param array $logs list of logs | 
				
			||||
	 */ | 
				
			||||
	protected function displaySummary($logs) | 
				
			||||
	{ | 
				
			||||
		$stack = array(); | 
				
			||||
		foreach ($logs as $log) | 
				
			||||
		{ | 
				
			||||
			if ($log[1] !== CLogger::LEVEL_PROFILE) | 
				
			||||
				continue; | 
				
			||||
			$message = $log[0]; | 
				
			||||
			if (!strncasecmp($message, 'begin:', 6)) | 
				
			||||
			{ | 
				
			||||
				$log[0] = substr($message, 6); | 
				
			||||
				$stack[] = $log; | 
				
			||||
			} | 
				
			||||
			elseif (!strncasecmp($message, 'end:', 4)) | 
				
			||||
			{ | 
				
			||||
				$token = substr($message, 4); | 
				
			||||
				if (($last = array_pop($stack)) !== null && $last[0] === $token) | 
				
			||||
				{ | 
				
			||||
					$delta = $log[3] - $last[3]; | 
				
			||||
					if (!$this->groupByToken) | 
				
			||||
						$token = $log[2]; | 
				
			||||
					if (isset($results[$token])) | 
				
			||||
						$results[$token] = $this->aggregateResult($results[$token], $delta); | 
				
			||||
					else | 
				
			||||
						$results[$token] = array($token, 1, $delta, $delta, $delta); | 
				
			||||
				} | 
				
			||||
				else | 
				
			||||
					throw new CException(Yii::t('yii', 'CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.', | 
				
			||||
						array('{token}' => $token))); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		$now = microtime(true); | 
				
			||||
		while (($last = array_pop($stack)) !== null) | 
				
			||||
		{ | 
				
			||||
			$delta = $now - $last[3]; | 
				
			||||
			$token = $this->groupByToken ? $last[0] : $last[2]; | 
				
			||||
			if (isset($results[$token])) | 
				
			||||
				$results[$token] = $this->aggregateResult($results[$token], $delta); | 
				
			||||
			else | 
				
			||||
				$results[$token] = array($token, 1, $delta, $delta, $delta); | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		$entries = array_values($results); | 
				
			||||
		$func = create_function('$a,$b', 'return $a[4]<$b[4]?1:0;'); | 
				
			||||
		usort($entries, $func); | 
				
			||||
 | 
				
			||||
		$this->render('profile-summary', $entries); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Aggregates the report result. | 
				
			||||
	 * @param array $result log result for this code block | 
				
			||||
	 * @param float $delta time spent for this code block | 
				
			||||
	 * @return array | 
				
			||||
	 */ | 
				
			||||
	protected function aggregateResult($result, $delta) | 
				
			||||
	{ | 
				
			||||
		list($token, $calls, $min, $max, $total) = $result; | 
				
			||||
		if ($delta < $min) | 
				
			||||
			$min = $delta; | 
				
			||||
		elseif ($delta > $max) | 
				
			||||
			$max = $delta; | 
				
			||||
		$calls++; | 
				
			||||
		$total += $delta; | 
				
			||||
		return array($token, $calls, $min, $max, $total); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,136 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * Router class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2012 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
namespace yii\logging; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Router manages [[Target|log targets]] that record log messages in different media. | 
				
			||||
 * | 
				
			||||
 * For example, a [[FileTarget|file log target]] records log messages | 
				
			||||
 * in files; an [[EmailTarget|email log target]] sends log messages | 
				
			||||
 * to specific email addresses. Each log target may specify filters on | 
				
			||||
 * message levels and categories to record specific messages only. | 
				
			||||
 * | 
				
			||||
 * Router and the targets it manages may be configured in application configuration, | 
				
			||||
 * like the following: | 
				
			||||
 * | 
				
			||||
 * ~~~ | 
				
			||||
 * array( | 
				
			||||
 *     // preload log component when application starts | 
				
			||||
 *     'preload' => array('log'), | 
				
			||||
 *     'components' => array( | 
				
			||||
 *         'log' => array( | 
				
			||||
 *             'class' => '\yii\logging\Router', | 
				
			||||
 *             'targets' => array( | 
				
			||||
 *                 'file' => array( | 
				
			||||
 *                     'class' => '\yii\logging\FileTarget', | 
				
			||||
 *                     'levels' => 'trace, info', | 
				
			||||
 *                     'categories' => 'yii\*', | 
				
			||||
 *                 ), | 
				
			||||
 *                 'email' => array( | 
				
			||||
 *                     'class' => '\yii\logging\EmailTarget', | 
				
			||||
 *                     'levels' => 'error, warning', | 
				
			||||
 *                     'emails' => array('admin@example.com'), | 
				
			||||
 *                 ), | 
				
			||||
 *             ), | 
				
			||||
 *         ), | 
				
			||||
 *     ), | 
				
			||||
 * ) | 
				
			||||
 * ~~~ | 
				
			||||
 * | 
				
			||||
 * Each log target can have a name and can be referenced via the [[targets]] property | 
				
			||||
 * as follows: | 
				
			||||
 * | 
				
			||||
 * ~~~ | 
				
			||||
 * \Yii::app()->log->targets['file']->enabled = false; | 
				
			||||
 * ~~~ | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @since 2.0 | 
				
			||||
 */ | 
				
			||||
class Router extends \yii\base\ApplicationComponent | 
				
			||||
{ | 
				
			||||
	private $_targets; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Constructor. | 
				
			||||
	 */ | 
				
			||||
	public function __construct() | 
				
			||||
	{ | 
				
			||||
		$this->_targets = new \yii\base\Dictionary; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Initializes this application component. | 
				
			||||
	 * This method is invoked when the Router component is created by the application. | 
				
			||||
	 * The method attaches the [[processLogs]] method to both the [[Logger::onFlush]] event | 
				
			||||
	 * and the [[\yii\base\Application::onEndRequest]] event. | 
				
			||||
	 */ | 
				
			||||
	public function init() | 
				
			||||
	{ | 
				
			||||
		parent::init(); | 
				
			||||
		\Yii::getLogger()->attachEventHandler('onFlush', array($this, 'processMessages')); | 
				
			||||
		if (($app = \Yii::app()) !== null) { | 
				
			||||
			$app->attachEventHandler('onEndRequest', array($this, 'processMessages')); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Returns the log targets managed by this log router. | 
				
			||||
	 * The keys of the dictionary are the names of the log targets. | 
				
			||||
	 * You can use the name to access a specific log target. For example, | 
				
			||||
	 * | 
				
			||||
	 * ~~~ | 
				
			||||
	 * $target = $router->targets['file']; | 
				
			||||
	 * ~~~ | 
				
			||||
	 * @return \yii\base\Dictionary the targets managed by this log router. | 
				
			||||
	 */ | 
				
			||||
	public function getTargets() | 
				
			||||
	{ | 
				
			||||
		return $this->_targets; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Sets the log targets. | 
				
			||||
	 * @param array $config list of log target configurations. Each array element | 
				
			||||
	 * represents the configuration for creating a single log target. It will be | 
				
			||||
	 * passed to [[\Yii::createComponent]] to create the target instance. | 
				
			||||
	 */ | 
				
			||||
	public function setTargets($config) | 
				
			||||
	{ | 
				
			||||
		foreach ($config as $name => $target) { | 
				
			||||
			if ($target instanceof Target) { | 
				
			||||
				$this->_targets[$name] = $target; | 
				
			||||
			} | 
				
			||||
			else { | 
				
			||||
				$this->_targets[$name] = \Yii::createComponent($target); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Retrieves and processes log messages from the system logger. | 
				
			||||
	 * This method mainly serves the event handler to [[Logger::onFlush]] | 
				
			||||
	 * and [[\yii\base\Application::onEndRequest]] events. | 
				
			||||
	 * It will retrieve the available log messages from the [[\Yii::getLogger|system logger]] | 
				
			||||
	 * and invoke the registered [[targets|log targets]] to do the actual processing. | 
				
			||||
	 * @param \yii\base\Event $event event parameter | 
				
			||||
	 */ | 
				
			||||
	public function processMessages($event) | 
				
			||||
	{ | 
				
			||||
		$logger = Yii::getLogger(); | 
				
			||||
		$export = !isset($event->params['export']) || $event->params['export']; | 
				
			||||
		foreach ($this->_targets as $target) { | 
				
			||||
			if ($target->enabled) { | 
				
			||||
				$target->processMessages($logger, $export); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,171 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * Target class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2012 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
namespace yii\logging; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Target is the base class for all log target classes. | 
				
			||||
 * | 
				
			||||
 * A log target object retrieves log messages from a logger and sends it | 
				
			||||
 * somewhere, such as files, emails. | 
				
			||||
 * The messages being retrieved may be filtered first before being sent | 
				
			||||
 * to the destination. The filters include log level filter and log category filter. | 
				
			||||
 * | 
				
			||||
 * To specify level filter, set {@link levels} property, | 
				
			||||
 * which takes a string of comma-separated desired level names (e.g. 'Error, Debug'). | 
				
			||||
 * To specify category filter, set {@link categories} property, | 
				
			||||
 * which takes a string of comma-separated desired category names (e.g. 'System.Web, System.IO'). | 
				
			||||
 * | 
				
			||||
 * Level filter and category filter are combinational, i.e., only messages | 
				
			||||
 * satisfying both filter conditions will they be returned. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @since 2.0 | 
				
			||||
 */ | 
				
			||||
abstract class Target extends \yii\base\Component implements \yii\base\Initable | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether to enable this log target. Defaults to true. | 
				
			||||
	 */ | 
				
			||||
	public $enabled = true; | 
				
			||||
	/** | 
				
			||||
	 * @var string list of levels separated by comma or space. Defaults to empty, meaning all levels. | 
				
			||||
	 */ | 
				
			||||
	public $levels; | 
				
			||||
	/** | 
				
			||||
	 * @var string list of categories separated by comma or space. Defaults to empty, meaning all categories. | 
				
			||||
	 */ | 
				
			||||
	public $categories; | 
				
			||||
	/** | 
				
			||||
	 * @var string list of categories that should be excluded. | 
				
			||||
	 */ | 
				
			||||
	public $excludeCategories; | 
				
			||||
	/** | 
				
			||||
	 * @var mixed the additional filter (eg {@link CLogFilter}) that can be applied to the log messages. | 
				
			||||
	 * The value of this property will be passed to {@link Yii::createComponent} to create | 
				
			||||
	 * a log filter object. As a result, this can be either a string representing the | 
				
			||||
	 * filter class name or an array representing the filter configuration. | 
				
			||||
	 * In general, the log filter class should be {@link CLogFilter} or a child class of it. | 
				
			||||
	 * Defaults to null, meaning no filter will be used. | 
				
			||||
	 */ | 
				
			||||
	public $filter; | 
				
			||||
	/** | 
				
			||||
	 * @var array the messages that are collected so far by this log target. | 
				
			||||
	 */ | 
				
			||||
	public $messages; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Pre-initializes this component. | 
				
			||||
	 * This method is required by the [[Initable]] interface. It is invoked by | 
				
			||||
	 * [[\Yii::createComponent]] after its creates the new component instance but | 
				
			||||
	 * BEFORE the component properties are initialized. | 
				
			||||
	 * | 
				
			||||
	 * You may override this method to do work such as setting property default values. | 
				
			||||
	 */ | 
				
			||||
	public function preinit() | 
				
			||||
	{ | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Initializes this component. | 
				
			||||
	 * This method is invoked after the component is created and its property values are | 
				
			||||
	 * initialized. | 
				
			||||
	 */ | 
				
			||||
	public function init() | 
				
			||||
	{ | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Formats a log message given different fields. | 
				
			||||
	 * @param string $message message content | 
				
			||||
	 * @param integer $level message level | 
				
			||||
	 * @param string $category message category | 
				
			||||
	 * @param integer $time timestamp | 
				
			||||
	 * @return string formatted message | 
				
			||||
	 */ | 
				
			||||
	protected function formatMessage($message, $level, $category, $time) | 
				
			||||
	{ | 
				
			||||
		return @date('Y/m/d H:i:s', $time) . " [$level] [$category] $message\n"; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Retrieves filtered log messages from logger for further processing. | 
				
			||||
	 * @param CLogger $logger logger instance | 
				
			||||
	 * @param boolean $processLogs whether to process the messages after they are collected from the logger | 
				
			||||
	 */ | 
				
			||||
	public function processMessages($logger, $export) | 
				
			||||
	{ | 
				
			||||
		$messages = $logger->getLogs($this->levels, $this->categories); | 
				
			||||
		$this->messages = empty($this->messages) ? $messages : array_merge($this->messages, $messages); | 
				
			||||
		if ($processLogs && !empty($this->messages)) | 
				
			||||
		{ | 
				
			||||
			if ($this->filter !== null) | 
				
			||||
				Yii::createComponent($this->filter)->filter($this->messages); | 
				
			||||
			$this->processLogs($this->messages); | 
				
			||||
			$this->messages = array(); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	protected function filterMessages($levels = '', $categories = '') | 
				
			||||
	{ | 
				
			||||
		$this->_levels = preg_split('/[\s,]+/', strtolower($levels), -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
		$this->_categories = preg_split('/[\s,]+/', strtolower($categories), -1, PREG_SPLIT_NO_EMPTY); | 
				
			||||
		if (empty($levels) && empty($categories)) | 
				
			||||
			return $this->_logs; | 
				
			||||
		elseif (empty($levels)) | 
				
			||||
			return array_values(array_filter(array_filter($this->_logs, array($this, 'filterByCategory')))); | 
				
			||||
		elseif (empty($categories)) | 
				
			||||
			return array_values(array_filter(array_filter($this->_logs, array($this, 'filterByLevel')))); | 
				
			||||
		else | 
				
			||||
		{ | 
				
			||||
			$ret = array_values(array_filter(array_filter($this->_logs, array($this, 'filterByLevel')))); | 
				
			||||
			return array_values(array_filter(array_filter($ret, array($this, 'filterByCategory')))); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Filter function used by {@link getLogs} | 
				
			||||
	 * @param array $value element to be filtered | 
				
			||||
	 * @return array valid log, false if not. | 
				
			||||
	 */ | 
				
			||||
	protected function filterByCategory($value) | 
				
			||||
	{ | 
				
			||||
		foreach ($this->_categories as $category) | 
				
			||||
		{ | 
				
			||||
			$cat = strtolower($value[2]); | 
				
			||||
			if ($cat === $category || (($c = rtrim($category, '.*')) !== $category && strpos($cat, $c) === 0)) | 
				
			||||
				return $value; | 
				
			||||
		} | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Filter function used by {@link getLogs} | 
				
			||||
	 * @param array $value element to be filtered | 
				
			||||
	 * @return array valid log, false if not. | 
				
			||||
	 */ | 
				
			||||
	protected function filterByLevel($value) | 
				
			||||
	{ | 
				
			||||
		return in_array(strtolower($value[1]), $this->_levels) ? $value : false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Processes log messages and sends them to specific destination. | 
				
			||||
	 * Derived child classes must implement this method. | 
				
			||||
	 * @param array $messages list of messages.  Each array elements represents one message | 
				
			||||
	 * with the following structure: | 
				
			||||
	 * array( | 
				
			||||
	 *   [0] => message (string) | 
				
			||||
	 *   [1] => level (string) | 
				
			||||
	 *   [2] => category (string) | 
				
			||||
	 *   [3] => timestamp (float, obtained by microtime(true)); | 
				
			||||
	 */ | 
				
			||||
	abstract protected function processLogs($messages); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,67 @@
					 | 
				
			||||
<?php | 
				
			||||
/** | 
				
			||||
 * CWebLogRoute class file. | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @link http://www.yiiframework.com/ | 
				
			||||
 * @copyright Copyright © 2008-2011 Yii Software LLC | 
				
			||||
 * @license http://www.yiiframework.com/license/ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * CWebLogRoute shows the log content in Web page. | 
				
			||||
 * | 
				
			||||
 * The log content can appear either at the end of the current Web page | 
				
			||||
 * or in FireBug console window (if {@link showInFireBug} is set true). | 
				
			||||
 * | 
				
			||||
 * @author Qiang Xue <qiang.xue@gmail.com> | 
				
			||||
 * @version $Id: CWebLogRoute.php 3001 2011-02-24 16:42:44Z alexander.makarow $ | 
				
			||||
 * @package system.logging | 
				
			||||
 * @since 1.0 | 
				
			||||
 */ | 
				
			||||
class CWebLogRoute extends CLogRoute | 
				
			||||
{ | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether the log should be displayed in FireBug instead of browser window. Defaults to false. | 
				
			||||
	 */ | 
				
			||||
	public $showInFireBug = false; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * @var boolean whether the log should be ignored in FireBug for ajax calls. Defaults to true. | 
				
			||||
	 * This option should be used carefully, because an ajax call returns all output as a result data. | 
				
			||||
	 * For example if the ajax call expects a json type result any output from the logger will cause ajax call to fail. | 
				
			||||
	 */ | 
				
			||||
	public $ignoreAjaxInFireBug = true; | 
				
			||||
	 | 
				
			||||
	/** | 
				
			||||
	 * Displays the log messages. | 
				
			||||
	 * @param array $logs list of log messages | 
				
			||||
	 */ | 
				
			||||
	public function processLogs($logs) | 
				
			||||
	{ | 
				
			||||
		$this->render('log', $logs); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * Renders the view. | 
				
			||||
	 * @param string $view the view name (file name without extension). The file is assumed to be located under framework/data/views. | 
				
			||||
	 * @param array $data data to be passed to the view | 
				
			||||
	 */ | 
				
			||||
	protected function render($view, $data) | 
				
			||||
	{ | 
				
			||||
		$app = Yii::app(); | 
				
			||||
		$isAjax = $app->getRequest()->getIsAjaxRequest(); | 
				
			||||
 | 
				
			||||
		if ($this->showInFireBug) | 
				
			||||
		{ | 
				
			||||
			if ($isAjax && $this->ignoreAjaxInFireBug) | 
				
			||||
				return; | 
				
			||||
			$view .= '-firebug'; | 
				
			||||
		} | 
				
			||||
		elseif (!($app instanceof CWebApplication) || $isAjax) | 
				
			||||
			return; | 
				
			||||
 | 
				
			||||
		$viewFile = YII_PATH . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $view . '.php'; | 
				
			||||
		include($app->findLocalizedFile($viewFile, 'en')); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue