diff options
Diffstat (limited to 'framework/yiilite.php')
| -rw-r--r-- | framework/yiilite.php | 9680 |
1 files changed, 9680 insertions, 0 deletions
diff --git a/framework/yiilite.php b/framework/yiilite.php new file mode 100644 index 0000000..8ddfb20 --- /dev/null +++ b/framework/yiilite.php @@ -0,0 +1,9680 @@ +<?php +/** + * Yii bootstrap file. + * + * This file is automatically generated using 'build lite' command. + * It is the result of merging commonly used Yii class files with + * comments and trace statements removed away. + * + * By using this file instead of yii.php, an Yii application may + * improve performance due to the reduction of PHP parsing time. + * The performance improvement is especially obvious when PHP APC extension + * is enabled. + * + * DO NOT modify this file manually. + * + * @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/ + * @version $Id: yiilite.php 3564 2012-02-13 01:29:03Z qiang.xue $ + * @since 1.0 + */ + + +defined('YII_BEGIN_TIME') or define('YII_BEGIN_TIME',microtime(true)); +defined('YII_DEBUG') or define('YII_DEBUG',false); +defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',0); +defined('YII_ENABLE_EXCEPTION_HANDLER') or define('YII_ENABLE_EXCEPTION_HANDLER',true); +defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER',true); +defined('YII_PATH') or define('YII_PATH',dirname(__FILE__)); +defined('YII_ZII_PATH') or define('YII_ZII_PATH',YII_PATH.DIRECTORY_SEPARATOR.'zii'); +class YiiBase +{ + public static $classMap=array(); + public static $enableIncludePath=true; + private static $_aliases=array('system'=>YII_PATH,'zii'=>YII_ZII_PATH); // alias => path + private static $_imports=array(); // alias => class name or directory + private static $_includePaths; // list of include paths + private static $_app; + private static $_logger; + public static function getVersion() + { + return '1.1.10'; + } + public static function createWebApplication($config=null) + { + return self::createApplication('CWebApplication',$config); + } + public static function createConsoleApplication($config=null) + { + return self::createApplication('CConsoleApplication',$config); + } + public static function createApplication($class,$config=null) + { + return new $class($config); + } + public static function app() + { + return self::$_app; + } + public static function setApplication($app) + { + if(self::$_app===null || $app===null) + self::$_app=$app; + else + throw new CException(Yii::t('yii','Yii application can only be created once.')); + } + public static function getFrameworkPath() + { + return YII_PATH; + } + public static function createComponent($config) + { + if(is_string($config)) + { + $type=$config; + $config=array(); + } + else if(isset($config['class'])) + { + $type=$config['class']; + unset($config['class']); + } + else + throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.')); + if(!class_exists($type,false)) + $type=Yii::import($type,true); + if(($n=func_num_args())>1) + { + $args=func_get_args(); + if($n===2) + $object=new $type($args[1]); + else if($n===3) + $object=new $type($args[1],$args[2]); + else if($n===4) + $object=new $type($args[1],$args[2],$args[3]); + else + { + unset($args[0]); + $class=new ReflectionClass($type); + // Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+ + // $object=$class->newInstanceArgs($args); + $object=call_user_func_array(array($class,'newInstance'),$args); + } + } + else + $object=new $type; + foreach($config as $key=>$value) + $object->$key=$value; + return $object; + } + public static function import($alias,$forceInclude=false) + { + if(isset(self::$_imports[$alias])) // previously imported + return self::$_imports[$alias]; + if(class_exists($alias,false) || interface_exists($alias,false)) + return self::$_imports[$alias]=$alias; + if(($pos=strrpos($alias,'\\'))!==false) // a class name in PHP 5.3 namespace format + { + $namespace=str_replace('\\','.',ltrim(substr($alias,0,$pos),'\\')); + if(($path=self::getPathOfAlias($namespace))!==false) + { + $classFile=$path.DIRECTORY_SEPARATOR.substr($alias,$pos+1).'.php'; + if($forceInclude) + { + if(is_file($classFile)) + require($classFile); + else + throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file.',array('{alias}'=>$alias))); + self::$_imports[$alias]=$alias; + } + else + self::$classMap[$alias]=$classFile; + return $alias; + } + else + throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory.', + array('{alias}'=>$namespace))); + } + if(($pos=strrpos($alias,'.'))===false) // a simple class name + { + if($forceInclude && self::autoload($alias)) + self::$_imports[$alias]=$alias; + return $alias; + } + $className=(string)substr($alias,$pos+1); + $isClass=$className!=='*'; + if($isClass && (class_exists($className,false) || interface_exists($className,false))) + return self::$_imports[$alias]=$className; + if(($path=self::getPathOfAlias($alias))!==false) + { + if($isClass) + { + if($forceInclude) + { + if(is_file($path.'.php')) + require($path.'.php'); + else + throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file.',array('{alias}'=>$alias))); + self::$_imports[$alias]=$className; + } + else + self::$classMap[$className]=$path.'.php'; + return $className; + } + else // a directory + { + if(self::$_includePaths===null) + { + self::$_includePaths=array_unique(explode(PATH_SEPARATOR,get_include_path())); + if(($pos=array_search('.',self::$_includePaths,true))!==false) + unset(self::$_includePaths[$pos]); + } + array_unshift(self::$_includePaths,$path); + if(self::$enableIncludePath && set_include_path('.'.PATH_SEPARATOR.implode(PATH_SEPARATOR,self::$_includePaths))===false) + self::$enableIncludePath=false; + return self::$_imports[$alias]=$path; + } + } + else + throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.', + array('{alias}'=>$alias))); + } + public static function getPathOfAlias($alias) + { + if(isset(self::$_aliases[$alias])) + return self::$_aliases[$alias]; + else if(($pos=strpos($alias,'.'))!==false) + { + $rootAlias=substr($alias,0,$pos); + if(isset(self::$_aliases[$rootAlias])) + return self::$_aliases[$alias]=rtrim(self::$_aliases[$rootAlias].DIRECTORY_SEPARATOR.str_replace('.',DIRECTORY_SEPARATOR,substr($alias,$pos+1)),'*'.DIRECTORY_SEPARATOR); + else if(self::$_app instanceof CWebApplication) + { + if(self::$_app->findModule($rootAlias)!==null) + return self::getPathOfAlias($alias); + } + } + return false; + } + public static function setPathOfAlias($alias,$path) + { + if(empty($path)) + unset(self::$_aliases[$alias]); + else + self::$_aliases[$alias]=rtrim($path,'\\/'); + } + public static function autoload($className) + { + // use include so that the error PHP file may appear + if(isset(self::$classMap[$className])) + include(self::$classMap[$className]); + else if(isset(self::$_coreClasses[$className])) + include(YII_PATH.self::$_coreClasses[$className]); + else + { + // include class file relying on include_path + if(strpos($className,'\\')===false) // class without namespace + { + if(self::$enableIncludePath===false) + { + foreach(self::$_includePaths as $path) + { + $classFile=$path.DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($classFile)) + { + include($classFile); + break; + } + } + } + else + include($className.'.php'); + } + else // class name with namespace in PHP 5.3 + { + $namespace=str_replace('\\','.',ltrim($className,'\\')); + if(($path=self::getPathOfAlias($namespace))!==false) + include($path.'.php'); + else + return false; + } + return class_exists($className,false) || interface_exists($className,false); + } + return true; + } + public static function trace($msg,$category='application') + { + if(YII_DEBUG) + self::log($msg,CLogger::LEVEL_TRACE,$category); + } + public static function log($msg,$level=CLogger::LEVEL_INFO,$category='application') + { + if(self::$_logger===null) + self::$_logger=new CLogger; + if(YII_DEBUG && YII_TRACE_LEVEL>0 && $level!==CLogger::LEVEL_PROFILE) + { + $traces=debug_backtrace(); + $count=0; + foreach($traces as $trace) + { + if(isset($trace['file'],$trace['line']) && strpos($trace['file'],YII_PATH)!==0) + { + $msg.="\nin ".$trace['file'].' ('.$trace['line'].')'; + if(++$count>=YII_TRACE_LEVEL) + break; + } + } + } + self::$_logger->log($msg,$level,$category); + } + public static function beginProfile($token,$category='application') + { + self::log('begin:'.$token,CLogger::LEVEL_PROFILE,$category); + } + public static function endProfile($token,$category='application') + { + self::log('end:'.$token,CLogger::LEVEL_PROFILE,$category); + } + public static function getLogger() + { + if(self::$_logger!==null) + return self::$_logger; + else + return self::$_logger=new CLogger; + } + public static function setLogger($logger) + { + self::$_logger=$logger; + } + public static function powered() + { + return Yii::t('yii','Powered by {yii}.', array('{yii}'=>'<a href="http://www.yiiframework.com/" rel="external">Yii Framework</a>')); + } + public static function t($category,$message,$params=array(),$source=null,$language=null) + { + if(self::$_app!==null) + { + if($source===null) + $source=($category==='yii'||$category==='zii')?'coreMessages':'messages'; + if(($source=self::$_app->getComponent($source))!==null) + $message=$source->translate($category,$message,$language); + } + if($params===array()) + return $message; + if(!is_array($params)) + $params=array($params); + if(isset($params[0])) // number choice + { + if(strpos($message,'|')!==false) + { + if(strpos($message,'#')===false) + { + $chunks=explode('|',$message); + $expressions=self::$_app->getLocale($language)->getPluralRules(); + if($n=min(count($chunks),count($expressions))) + { + for($i=0;$i<$n;$i++) + $chunks[$i]=$expressions[$i].'#'.$chunks[$i]; + $message=implode('|',$chunks); + } + } + $message=CChoiceFormat::format($message,$params[0]); + } + if(!isset($params['{n}'])) + $params['{n}']=$params[0]; + unset($params[0]); + } + return $params!==array() ? strtr($message,$params) : $message; + } + public static function registerAutoloader($callback, $append=false) + { + if($append) + { + self::$enableIncludePath=false; + spl_autoload_register($callback); + } + else + { + spl_autoload_unregister(array('YiiBase','autoload')); + spl_autoload_register($callback); + spl_autoload_register(array('YiiBase','autoload')); + } + } + private static $_coreClasses=array( + 'CApplication' => '/base/CApplication.php', + 'CApplicationComponent' => '/base/CApplicationComponent.php', + 'CBehavior' => '/base/CBehavior.php', + 'CComponent' => '/base/CComponent.php', + 'CErrorEvent' => '/base/CErrorEvent.php', + 'CErrorHandler' => '/base/CErrorHandler.php', + 'CException' => '/base/CException.php', + 'CExceptionEvent' => '/base/CExceptionEvent.php', + 'CHttpException' => '/base/CHttpException.php', + 'CModel' => '/base/CModel.php', + 'CModelBehavior' => '/base/CModelBehavior.php', + 'CModelEvent' => '/base/CModelEvent.php', + 'CModule' => '/base/CModule.php', + 'CSecurityManager' => '/base/CSecurityManager.php', + 'CStatePersister' => '/base/CStatePersister.php', + 'CApcCache' => '/caching/CApcCache.php', + 'CCache' => '/caching/CCache.php', + 'CDbCache' => '/caching/CDbCache.php', + 'CDummyCache' => '/caching/CDummyCache.php', + 'CEAcceleratorCache' => '/caching/CEAcceleratorCache.php', + 'CFileCache' => '/caching/CFileCache.php', + 'CMemCache' => '/caching/CMemCache.php', + 'CWinCache' => '/caching/CWinCache.php', + 'CXCache' => '/caching/CXCache.php', + 'CZendDataCache' => '/caching/CZendDataCache.php', + 'CCacheDependency' => '/caching/dependencies/CCacheDependency.php', + 'CChainedCacheDependency' => '/caching/dependencies/CChainedCacheDependency.php', + 'CDbCacheDependency' => '/caching/dependencies/CDbCacheDependency.php', + 'CDirectoryCacheDependency' => '/caching/dependencies/CDirectoryCacheDependency.php', + 'CExpressionDependency' => '/caching/dependencies/CExpressionDependency.php', + 'CFileCacheDependency' => '/caching/dependencies/CFileCacheDependency.php', + 'CGlobalStateCacheDependency' => '/caching/dependencies/CGlobalStateCacheDependency.php', + 'CAttributeCollection' => '/collections/CAttributeCollection.php', + 'CConfiguration' => '/collections/CConfiguration.php', + 'CList' => '/collections/CList.php', + 'CListIterator' => '/collections/CListIterator.php', + 'CMap' => '/collections/CMap.php', + 'CMapIterator' => '/collections/CMapIterator.php', + 'CQueue' => '/collections/CQueue.php', + 'CQueueIterator' => '/collections/CQueueIterator.php', + 'CStack' => '/collections/CStack.php', + 'CStackIterator' => '/collections/CStackIterator.php', + 'CTypedList' => '/collections/CTypedList.php', + 'CTypedMap' => '/collections/CTypedMap.php', + 'CConsoleApplication' => '/console/CConsoleApplication.php', + 'CConsoleCommand' => '/console/CConsoleCommand.php', + 'CConsoleCommandRunner' => '/console/CConsoleCommandRunner.php', + 'CHelpCommand' => '/console/CHelpCommand.php', + 'CDbCommand' => '/db/CDbCommand.php', + 'CDbConnection' => '/db/CDbConnection.php', + 'CDbDataReader' => '/db/CDbDataReader.php', + 'CDbException' => '/db/CDbException.php', + 'CDbMigration' => '/db/CDbMigration.php', + 'CDbTransaction' => '/db/CDbTransaction.php', + 'CActiveFinder' => '/db/ar/CActiveFinder.php', + 'CActiveRecord' => '/db/ar/CActiveRecord.php', + 'CActiveRecordBehavior' => '/db/ar/CActiveRecordBehavior.php', + 'CDbColumnSchema' => '/db/schema/CDbColumnSchema.php', + 'CDbCommandBuilder' => '/db/schema/CDbCommandBuilder.php', + 'CDbCriteria' => '/db/schema/CDbCriteria.php', + 'CDbExpression' => '/db/schema/CDbExpression.php', + 'CDbSchema' => '/db/schema/CDbSchema.php', + 'CDbTableSchema' => '/db/schema/CDbTableSchema.php', + 'CMssqlColumnSchema' => '/db/schema/mssql/CMssqlColumnSchema.php', + 'CMssqlCommandBuilder' => '/db/schema/mssql/CMssqlCommandBuilder.php', + 'CMssqlPdoAdapter' => '/db/schema/mssql/CMssqlPdoAdapter.php', + 'CMssqlSchema' => '/db/schema/mssql/CMssqlSchema.php', + 'CMssqlTableSchema' => '/db/schema/mssql/CMssqlTableSchema.php', + 'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php', + 'CMysqlSchema' => '/db/schema/mysql/CMysqlSchema.php', + 'CMysqlTableSchema' => '/db/schema/mysql/CMysqlTableSchema.php', + 'COciColumnSchema' => '/db/schema/oci/COciColumnSchema.php', + 'COciCommandBuilder' => '/db/schema/oci/COciCommandBuilder.php', + 'COciSchema' => '/db/schema/oci/COciSchema.php', + 'COciTableSchema' => '/db/schema/oci/COciTableSchema.php', + 'CPgsqlColumnSchema' => '/db/schema/pgsql/CPgsqlColumnSchema.php', + 'CPgsqlSchema' => '/db/schema/pgsql/CPgsqlSchema.php', + 'CPgsqlTableSchema' => '/db/schema/pgsql/CPgsqlTableSchema.php', + 'CSqliteColumnSchema' => '/db/schema/sqlite/CSqliteColumnSchema.php', + 'CSqliteCommandBuilder' => '/db/schema/sqlite/CSqliteCommandBuilder.php', + 'CSqliteSchema' => '/db/schema/sqlite/CSqliteSchema.php', + 'CChoiceFormat' => '/i18n/CChoiceFormat.php', + 'CDateFormatter' => '/i18n/CDateFormatter.php', + 'CDbMessageSource' => '/i18n/CDbMessageSource.php', + 'CGettextMessageSource' => '/i18n/CGettextMessageSource.php', + 'CLocale' => '/i18n/CLocale.php', + 'CMessageSource' => '/i18n/CMessageSource.php', + 'CNumberFormatter' => '/i18n/CNumberFormatter.php', + 'CPhpMessageSource' => '/i18n/CPhpMessageSource.php', + 'CGettextFile' => '/i18n/gettext/CGettextFile.php', + 'CGettextMoFile' => '/i18n/gettext/CGettextMoFile.php', + 'CGettextPoFile' => '/i18n/gettext/CGettextPoFile.php', + 'CDbLogRoute' => '/logging/CDbLogRoute.php', + 'CEmailLogRoute' => '/logging/CEmailLogRoute.php', + 'CFileLogRoute' => '/logging/CFileLogRoute.php', + 'CLogFilter' => '/logging/CLogFilter.php', + 'CLogRoute' => '/logging/CLogRoute.php', + 'CLogRouter' => '/logging/CLogRouter.php', + 'CLogger' => '/logging/CLogger.php', + 'CProfileLogRoute' => '/logging/CProfileLogRoute.php', + 'CWebLogRoute' => '/logging/CWebLogRoute.php', + 'CDateTimeParser' => '/utils/CDateTimeParser.php', + 'CFileHelper' => '/utils/CFileHelper.php', + 'CFormatter' => '/utils/CFormatter.php', + 'CMarkdownParser' => '/utils/CMarkdownParser.php', + 'CPropertyValue' => '/utils/CPropertyValue.php', + 'CTimestamp' => '/utils/CTimestamp.php', + 'CVarDumper' => '/utils/CVarDumper.php', + 'CBooleanValidator' => '/validators/CBooleanValidator.php', + 'CCaptchaValidator' => '/validators/CCaptchaValidator.php', + 'CCompareValidator' => '/validators/CCompareValidator.php', + 'CDateValidator' => '/validators/CDateValidator.php', + 'CDefaultValueValidator' => '/validators/CDefaultValueValidator.php', + 'CEmailValidator' => '/validators/CEmailValidator.php', + 'CExistValidator' => '/validators/CExistValidator.php', + 'CFileValidator' => '/validators/CFileValidator.php', + 'CFilterValidator' => '/validators/CFilterValidator.php', + 'CInlineValidator' => '/validators/CInlineValidator.php', + 'CNumberValidator' => '/validators/CNumberValidator.php', + 'CRangeValidator' => '/validators/CRangeValidator.php', + 'CRegularExpressionValidator' => '/validators/CRegularExpressionValidator.php', + 'CRequiredValidator' => '/validators/CRequiredValidator.php', + 'CSafeValidator' => '/validators/CSafeValidator.php', + 'CStringValidator' => '/validators/CStringValidator.php', + 'CTypeValidator' => '/validators/CTypeValidator.php', + 'CUniqueValidator' => '/validators/CUniqueValidator.php', + 'CUnsafeValidator' => '/validators/CUnsafeValidator.php', + 'CUrlValidator' => '/validators/CUrlValidator.php', + 'CValidator' => '/validators/CValidator.php', + 'CActiveDataProvider' => '/web/CActiveDataProvider.php', + 'CArrayDataProvider' => '/web/CArrayDataProvider.php', + 'CAssetManager' => '/web/CAssetManager.php', + 'CBaseController' => '/web/CBaseController.php', + 'CCacheHttpSession' => '/web/CCacheHttpSession.php', + 'CClientScript' => '/web/CClientScript.php', + 'CController' => '/web/CController.php', + 'CDataProvider' => '/web/CDataProvider.php', + 'CDbHttpSession' => '/web/CDbHttpSession.php', + 'CExtController' => '/web/CExtController.php', + 'CFormModel' => '/web/CFormModel.php', + 'CHttpCookie' => '/web/CHttpCookie.php', + 'CHttpRequest' => '/web/CHttpRequest.php', + 'CHttpSession' => '/web/CHttpSession.php', + 'CHttpSessionIterator' => '/web/CHttpSessionIterator.php', + 'COutputEvent' => '/web/COutputEvent.php', + 'CPagination' => '/web/CPagination.php', + 'CSort' => '/web/CSort.php', + 'CSqlDataProvider' => '/web/CSqlDataProvider.php', + 'CTheme' => '/web/CTheme.php', + 'CThemeManager' => '/web/CThemeManager.php', + 'CUploadedFile' => '/web/CUploadedFile.php', + 'CUrlManager' => '/web/CUrlManager.php', + 'CWebApplication' => '/web/CWebApplication.php', + 'CWebModule' => '/web/CWebModule.php', + 'CWidgetFactory' => '/web/CWidgetFactory.php', + 'CAction' => '/web/actions/CAction.php', + 'CInlineAction' => '/web/actions/CInlineAction.php', + 'CViewAction' => '/web/actions/CViewAction.php', + 'CAccessControlFilter' => '/web/auth/CAccessControlFilter.php', + 'CAuthAssignment' => '/web/auth/CAuthAssignment.php', + 'CAuthItem' => '/web/auth/CAuthItem.php', + 'CAuthManager' => '/web/auth/CAuthManager.php', + 'CBaseUserIdentity' => '/web/auth/CBaseUserIdentity.php', + 'CDbAuthManager' => '/web/auth/CDbAuthManager.php', + 'CPhpAuthManager' => '/web/auth/CPhpAuthManager.php', + 'CUserIdentity' => '/web/auth/CUserIdentity.php', + 'CWebUser' => '/web/auth/CWebUser.php', + 'CFilter' => '/web/filters/CFilter.php', + 'CFilterChain' => '/web/filters/CFilterChain.php', + 'CInlineFilter' => '/web/filters/CInlineFilter.php', + 'CForm' => '/web/form/CForm.php', + 'CFormButtonElement' => '/web/form/CFormButtonElement.php', + 'CFormElement' => '/web/form/CFormElement.php', + 'CFormElementCollection' => '/web/form/CFormElementCollection.php', + 'CFormInputElement' => '/web/form/CFormInputElement.php', + 'CFormStringElement' => '/web/form/CFormStringElement.php', + 'CGoogleApi' => '/web/helpers/CGoogleApi.php', + 'CHtml' => '/web/helpers/CHtml.php', + 'CJSON' => '/web/helpers/CJSON.php', + 'CJavaScript' => '/web/helpers/CJavaScript.php', + 'CPradoViewRenderer' => '/web/renderers/CPradoViewRenderer.php', + 'CViewRenderer' => '/web/renderers/CViewRenderer.php', + 'CWebService' => '/web/services/CWebService.php', + 'CWebServiceAction' => '/web/services/CWebServiceAction.php', + 'CWsdlGenerator' => '/web/services/CWsdlGenerator.php', + 'CActiveForm' => '/web/widgets/CActiveForm.php', + 'CAutoComplete' => '/web/widgets/CAutoComplete.php', + 'CClipWidget' => '/web/widgets/CClipWidget.php', + 'CContentDecorator' => '/web/widgets/CContentDecorator.php', + 'CFilterWidget' => '/web/widgets/CFilterWidget.php', + 'CFlexWidget' => '/web/widgets/CFlexWidget.php', + 'CHtmlPurifier' => '/web/widgets/CHtmlPurifier.php', + 'CInputWidget' => '/web/widgets/CInputWidget.php', + 'CMarkdown' => '/web/widgets/CMarkdown.php', + 'CMaskedTextField' => '/web/widgets/CMaskedTextField.php', + 'CMultiFileUpload' => '/web/widgets/CMultiFileUpload.php', + 'COutputCache' => '/web/widgets/COutputCache.php', + 'COutputProcessor' => '/web/widgets/COutputProcessor.php', + 'CStarRating' => '/web/widgets/CStarRating.php', + 'CTabView' => '/web/widgets/CTabView.php', + 'CTextHighlighter' => '/web/widgets/CTextHighlighter.php', + 'CTreeView' => '/web/widgets/CTreeView.php', + 'CWidget' => '/web/widgets/CWidget.php', + 'CCaptcha' => '/web/widgets/captcha/CCaptcha.php', + 'CCaptchaAction' => '/web/widgets/captcha/CCaptchaAction.php', + 'CBasePager' => '/web/widgets/pagers/CBasePager.php', + 'CLinkPager' => '/web/widgets/pagers/CLinkPager.php', + 'CListPager' => '/web/widgets/pagers/CListPager.php', + ); +} +spl_autoload_register(array('YiiBase','autoload')); +class Yii extends YiiBase +{ +} +class CComponent +{ + private $_e; + private $_m; + public function __get($name) + { + $getter='get'.$name; + if(method_exists($this,$getter)) + return $this->$getter(); + else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) + { + // duplicating getEventHandlers() here for performance + $name=strtolower($name); + if(!isset($this->_e[$name])) + $this->_e[$name]=new CList; + return $this->_e[$name]; + } + else if(isset($this->_m[$name])) + return $this->_m[$name]; + else if(is_array($this->_m)) + { + foreach($this->_m as $object) + { + if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name))) + return $object->$name; + } + } + throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.', + array('{class}'=>get_class($this), '{property}'=>$name))); + } + public function __set($name,$value) + { + $setter='set'.$name; + if(method_exists($this,$setter)) + return $this->$setter($value); + else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) + { + // duplicating getEventHandlers() here for performance + $name=strtolower($name); + if(!isset($this->_e[$name])) + $this->_e[$name]=new CList; + return $this->_e[$name]->add($value); + } + else if(is_array($this->_m)) + { + foreach($this->_m as $object) + { + if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name))) + return $object->$name=$value; + } + } + if(method_exists($this,'get'.$name)) + throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.', + array('{class}'=>get_class($this), '{property}'=>$name))); + else + throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.', + array('{class}'=>get_class($this), '{property}'=>$name))); + } + public function __isset($name) + { + $getter='get'.$name; + if(method_exists($this,$getter)) + return $this->$getter()!==null; + else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) + { + $name=strtolower($name); + return isset($this->_e[$name]) && $this->_e[$name]->getCount(); + } + else if(is_array($this->_m)) + { + if(isset($this->_m[$name])) + return true; + foreach($this->_m as $object) + { + if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name))) + return $object->$name!==null; + } + } + return false; + } + public function __unset($name) + { + $setter='set'.$name; + if(method_exists($this,$setter)) + $this->$setter(null); + else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) + unset($this->_e[strtolower($name)]); + else if(is_array($this->_m)) + { + if(isset($this->_m[$name])) + $this->detachBehavior($name); + else + { + foreach($this->_m as $object) + { + if($object->getEnabled()) + { + if(property_exists($object,$name)) + return $object->$name=null; + else if($object->canSetProperty($name)) + return $object->$setter(null); + } + } + } + } + else if(method_exists($this,'get'.$name)) + throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.', + array('{class}'=>get_class($this), '{property}'=>$name))); + } + public function __call($name,$parameters) + { + if($this->_m!==null) + { + foreach($this->_m as $object) + { + if($object->getEnabled() && method_exists($object,$name)) + return call_user_func_array(array($object,$name),$parameters); + } + } + if(class_exists('Closure', false) && $this->canGetProperty($name) && $this->$name instanceof Closure) + return call_user_func_array($this->$name, $parameters); + throw new CException(Yii::t('yii','{class} and its behaviors do not have a method or closure named "{name}".', + array('{class}'=>get_class($this), '{name}'=>$name))); + } + public function asa($behavior) + { + return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null; + } + public function attachBehaviors($behaviors) + { + foreach($behaviors as $name=>$behavior) + $this->attachBehavior($name,$behavior); + } + public function detachBehaviors() + { + if($this->_m!==null) + { + foreach($this->_m as $name=>$behavior) + $this->detachBehavior($name); + $this->_m=null; + } + } + public function attachBehavior($name,$behavior) + { + if(!($behavior instanceof IBehavior)) + $behavior=Yii::createComponent($behavior); + $behavior->setEnabled(true); + $behavior->attach($this); + return $this->_m[$name]=$behavior; + } + public function detachBehavior($name) + { + if(isset($this->_m[$name])) + { + $this->_m[$name]->detach($this); + $behavior=$this->_m[$name]; + unset($this->_m[$name]); + return $behavior; + } + } + public function enableBehaviors() + { + if($this->_m!==null) + { + foreach($this->_m as $behavior) + $behavior->setEnabled(true); + } + } + public function disableBehaviors() + { + if($this->_m!==null) + { + foreach($this->_m as $behavior) + $behavior->setEnabled(false); + } + } + public function enableBehavior($name) + { + if(isset($this->_m[$name])) + $this->_m[$name]->setEnabled(true); + } + public function disableBehavior($name) + { + if(isset($this->_m[$name])) + $this->_m[$name]->setEnabled(false); + } + public function hasProperty($name) + { + return method_exists($this,'get'.$name) || method_exists($this,'set'.$name); + } + public function canGetProperty($name) + { + return method_exists($this,'get'.$name); + } + public function canSetProperty($name) + { + return method_exists($this,'set'.$name); + } + public function hasEvent($name) + { + return !strncasecmp($name,'on',2) && method_exists($this,$name); + } + public function hasEventHandler($name) + { + $name=strtolower($name); + return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0; + } + public function getEventHandlers($name) + { + if($this->hasEvent($name)) + { + $name=strtolower($name); + if(!isset($this->_e[$name])) + $this->_e[$name]=new CList; + return $this->_e[$name]; + } + else + throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', + array('{class}'=>get_class($this), '{event}'=>$name))); + } + public function attachEventHandler($name,$handler) + { + $this->getEventHandlers($name)->add($handler); + } + public function detachEventHandler($name,$handler) + { + if($this->hasEventHandler($name)) + return $this->getEventHandlers($name)->remove($handler)!==false; + else + return false; + } + public function raiseEvent($name,$event) + { + $name=strtolower($name); + if(isset($this->_e[$name])) + { + foreach($this->_e[$name] as $handler) + { + if(is_string($handler)) + call_user_func($handler,$event); + else if(is_callable($handler,true)) + { + if(is_array($handler)) + { + // an array: 0 - object, 1 - method name + list($object,$method)=$handler; + if(is_string($object)) // static method call + call_user_func($handler,$event); + else if(method_exists($object,$method)) + $object->$method($event); + else + throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', + array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1]))); + } + else // PHP 5.3: anonymous function + call_user_func($handler,$event); + } + else + throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', + array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler)))); + // stop further handling if param.handled is set true + if(($event instanceof CEvent) && $event->handled) + return; + } + } + else if(YII_DEBUG && !$this->hasEvent($name)) + throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', + array('{class}'=>get_class($this), '{event}'=>$name))); + } + public function evaluateExpression($_expression_,$_data_=array()) + { + if(is_string($_expression_)) + { + extract($_data_); + return eval('return '.$_expression_.';'); + } + else + { + $_data_[]=$this; + return call_user_func_array($_expression_, $_data_); + } + } +} +class CEvent extends CComponent +{ + public $sender; + public $handled=false; + public $params; + public function __construct($sender=null,$params=null) + { + $this->sender=$sender; + $this->params=$params; + } +} +class CEnumerable +{ +} +abstract class CModule extends CComponent +{ + public $preload=array(); + public $behaviors=array(); + private $_id; + private $_parentModule; + private $_basePath; + private $_modulePath; + private $_params; + private $_modules=array(); + private $_moduleConfig=array(); + private $_components=array(); + private $_componentConfig=array(); + public function __construct($id,$parent,$config=null) + { + $this->_id=$id; + $this->_parentModule=$parent; + // set basePath at early as possible to avoid trouble + if(is_string($config)) + $config=require($config); + if(isset($config['basePath'])) + { + $this->setBasePath($config['basePath']); + unset($config['basePath']); + } + Yii::setPathOfAlias($id,$this->getBasePath()); + $this->preinit(); + $this->configure($config); + $this->attachBehaviors($this->behaviors); + $this->preloadComponents(); + $this->init(); + } + public function __get($name) + { + if($this->hasComponent($name)) + return $this->getComponent($name); + else + return parent::__get($name); + } + public function __isset($name) + { + if($this->hasComponent($name)) + return $this->getComponent($name)!==null; + else + return parent::__isset($name); + } + public function getId() + { + return $this->_id; + } + public function setId($id) + { + $this->_id=$id; + } + public function getBasePath() + { + if($this->_basePath===null) + { + $class=new ReflectionClass(get_class($this)); + $this->_basePath=dirname($class->getFileName()); + } + return $this->_basePath; + } + public function setBasePath($path) + { + if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath)) + throw new CException(Yii::t('yii','Base path "{path}" is not a valid directory.', + array('{path}'=>$path))); + } + public function getParams() + { + if($this->_params!==null) + return $this->_params; + else + { + $this->_params=new CAttributeCollection; + $this->_params->caseSensitive=true; + return $this->_params; + } + } + public function setParams($value) + { + $params=$this->getParams(); + foreach($value as $k=>$v) + $params->add($k,$v); + } + public function getModulePath() + { + if($this->_modulePath!==null) + return $this->_modulePath; + else + return $this->_modulePath=$this->getBasePath().DIRECTORY_SEPARATOR.'modules'; + } + public function setModulePath($value) + { + if(($this->_modulePath=realpath($value))===false || !is_dir($this->_modulePath)) + throw new CException(Yii::t('yii','The module path "{path}" is not a valid directory.', + array('{path}'=>$value))); + } + public function setImport($aliases) + { + foreach($aliases as $alias) + Yii::import($alias); + } + public function setAliases($mappings) + { + foreach($mappings as $name=>$alias) + { + if(($path=Yii::getPathOfAlias($alias))!==false) + Yii::setPathOfAlias($name,$path); + else + Yii::setPathOfAlias($name,$alias); + } + } + public function getParentModule() + { + return $this->_parentModule; + } + public function getModule($id) + { + if(isset($this->_modules[$id]) || array_key_exists($id,$this->_modules)) + return $this->_modules[$id]; + else if(isset($this->_moduleConfig[$id])) + { + $config=$this->_moduleConfig[$id]; + if(!isset($config['enabled']) || $config['enabled']) + { + $class=$config['class']; + unset($config['class'], $config['enabled']); + if($this===Yii::app()) + $module=Yii::createComponent($class,$id,null,$config); + else + $module=Yii::createComponent($class,$this->getId().'/'.$id,$this,$config); + return $this->_modules[$id]=$module; + } + } + } + public function hasModule($id) + { + return isset($this->_moduleConfig[$id]) || isset($this->_modules[$id]); + } + public function getModules() + { + return $this->_moduleConfig; + } + public function setModules($modules) + { + foreach($modules as $id=>$module) + { + if(is_int($id)) + { + $id=$module; + $module=array(); + } + if(!isset($module['class'])) + { + Yii::setPathOfAlias($id,$this->getModulePath().DIRECTORY_SEPARATOR.$id); + $module['class']=$id.'.'.ucfirst($id).'Module'; + } + if(isset($this->_moduleConfig[$id])) + $this->_moduleConfig[$id]=CMap::mergeArray($this->_moduleConfig[$id],$module); + else + $this->_moduleConfig[$id]=$module; + } + } + public function hasComponent($id) + { + return isset($this->_components[$id]) || isset($this->_componentConfig[$id]); + } + public function getComponent($id,$createIfNull=true) + { + if(isset($this->_components[$id])) + return $this->_components[$id]; + else if(isset($this->_componentConfig[$id]) && $createIfNull) + { + $config=$this->_componentConfig[$id]; + if(!isset($config['enabled']) || $config['enabled']) + { + unset($config['enabled']); + $component=Yii::createComponent($config); + $component->init(); + return $this->_components[$id]=$component; + } + } + } + public function setComponent($id,$component) + { + if($component===null) + unset($this->_components[$id]); + else + { + $this->_components[$id]=$component; + if(!$component->getIsInitialized()) + $component->init(); + } + } + public function getComponents($loadedOnly=true) + { + if($loadedOnly) + return $this->_components; + else + return array_merge($this->_componentConfig, $this->_components); + } + public function setComponents($components,$merge=true) + { + foreach($components as $id=>$component) + { + if($component instanceof IApplicationComponent) + $this->setComponent($id,$component); + else if(isset($this->_componentConfig[$id]) && $merge) + $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component); + else + $this->_componentConfig[$id]=$component; + } + } + public function configure($config) + { + if(is_array($config)) + { + foreach($config as $key=>$value) + $this->$key=$value; + } + } + protected function preloadComponents() + { + foreach($this->preload as $id) + $this->getComponent($id); + } + protected function preinit() + { + } + protected function init() + { + } +} +abstract class CApplication extends CModule +{ + public $name='My Application'; + public $charset='UTF-8'; + public $sourceLanguage='en_us'; + private $_id; + private $_basePath; + private $_runtimePath; + private $_extensionPath; + private $_globalState; + private $_stateChanged; + private $_ended=false; + private $_language; + private $_homeUrl; + abstract public function processRequest(); + public function __construct($config=null) + { + Yii::setApplication($this); + // set basePath at early as possible to avoid trouble + if(is_string($config)) + $config=require($config); + if(isset($config['basePath'])) + { + $this->setBasePath($config['basePath']); + unset($config['basePath']); + } + else + $this->setBasePath('protected'); + Yii::setPathOfAlias('application',$this->getBasePath()); + Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME'])); + Yii::setPathOfAlias('ext',$this->getBasePath().DIRECTORY_SEPARATOR.'extensions'); + $this->preinit(); + $this->initSystemHandlers(); + $this->registerCoreComponents(); + $this->configure($config); + $this->attachBehaviors($this->behaviors); + $this->preloadComponents(); + $this->init(); + } + public function run() + { + if($this->hasEventHandler('onBeginRequest')) + $this->onBeginRequest(new CEvent($this)); + $this->processRequest(); + if($this->hasEventHandler('onEndRequest')) + $this->onEndRequest(new CEvent($this)); + } + public function end($status=0, $exit=true) + { + if($this->hasEventHandler('onEndRequest')) + $this->onEndRequest(new CEvent($this)); + if($exit) + exit($status); + } + public function onBeginRequest($event) + { + $this->raiseEvent('onBeginRequest',$event); + } + public function onEndRequest($event) + { + if(!$this->_ended) + { + $this->_ended=true; + $this->raiseEvent('onEndRequest',$event); + } + } + public function getId() + { + if($this->_id!==null) + return $this->_id; + else + return $this->_id=sprintf('%x',crc32($this->getBasePath().$this->name)); + } + public function setId($id) + { + $this->_id=$id; + } + public function getBasePath() + { + return $this->_basePath; + } + public function setBasePath($path) + { + if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath)) + throw new CException(Yii::t('yii','Application base path "{path}" is not a valid directory.', + array('{path}'=>$path))); + } + public function getRuntimePath() + { + if($this->_runtimePath!==null) + return $this->_runtimePath; + else + { + $this->setRuntimePath($this->getBasePath().DIRECTORY_SEPARATOR.'runtime'); + return $this->_runtimePath; + } + } + public function setRuntimePath($path) + { + if(($runtimePath=realpath($path))===false || !is_dir($runtimePath) || !is_writable($runtimePath)) + 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.', + array('{path}'=>$path))); + $this->_runtimePath=$runtimePath; + } + public function getExtensionPath() + { + return Yii::getPathOfAlias('ext'); + } + public function setExtensionPath($path) + { + if(($extensionPath=realpath($path))===false || !is_dir($extensionPath)) + throw new CException(Yii::t('yii','Extension path "{path}" does not exist.', + array('{path}'=>$path))); + Yii::setPathOfAlias('ext',$extensionPath); + } + public function getLanguage() + { + return $this->_language===null ? $this->sourceLanguage : $this->_language; + } + public function setLanguage($language) + { + $this->_language=$language; + } + public function getTimeZone() + { + return date_default_timezone_get(); + } + public function setTimeZone($value) + { + date_default_timezone_set($value); + } + public function findLocalizedFile($srcFile,$srcLanguage=null,$language=null) + { + if($srcLanguage===null) + $srcLanguage=$this->sourceLanguage; + if($language===null) + $language=$this->getLanguage(); + if($language===$srcLanguage) + return $srcFile; + $desiredFile=dirname($srcFile).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.basename($srcFile); + return is_file($desiredFile) ? $desiredFile : $srcFile; + } + public function getLocale($localeID=null) + { + return CLocale::getInstance($localeID===null?$this->getLanguage():$localeID); + } + public function getLocaleDataPath() + { + return CLocale::$dataPath===null ? Yii::getPathOfAlias('system.i18n.data') : CLocale::$dataPath; + } + public function setLocaleDataPath($value) + { + CLocale::$dataPath=$value; + } + public function getNumberFormatter() + { + return $this->getLocale()->getNumberFormatter(); + } + public function getDateFormatter() + { + return $this->getLocale()->getDateFormatter(); + } + public function getDb() + { + return $this->getComponent('db'); + } + public function getErrorHandler() + { + return $this->getComponent('errorHandler'); + } + public function getSecurityManager() + { + return $this->getComponent('securityManager'); + } + public function getStatePersister() + { + return $this->getComponent('statePersister'); + } + public function getCache() + { + return $this->getComponent('cache'); + } + public function getCoreMessages() + { + return $this->getComponent('coreMessages'); + } + public function getMessages() + { + return $this->getComponent('messages'); + } + public function getRequest() + { + return $this->getComponent('request'); + } + public function getUrlManager() + { + return $this->getComponent('urlManager'); + } + public function getController() + { + return null; + } + public function createUrl($route,$params=array(),$ampersand='&') + { + return $this->getUrlManager()->createUrl($route,$params,$ampersand); + } + public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&') + { + $url=$this->createUrl($route,$params,$ampersand); + if(strpos($url,'http')===0) + return $url; + else + return $this->getRequest()->getHostInfo($schema).$url; + } + public function getBaseUrl($absolute=false) + { + return $this->getRequest()->getBaseUrl($absolute); + } + public function getHomeUrl() + { + if($this->_homeUrl===null) + { + if($this->getUrlManager()->showScriptName) + return $this->getRequest()->getScriptUrl(); + else + return $this->getRequest()->getBaseUrl().'/'; + } + else + return $this->_homeUrl; + } + public function setHomeUrl($value) + { + $this->_homeUrl=$value; + } + public function getGlobalState($key,$defaultValue=null) + { + if($this->_globalState===null) + $this->loadGlobalState(); + if(isset($this->_globalState[$key])) + return $this->_globalState[$key]; + else + return $defaultValue; + } + public function setGlobalState($key,$value,$defaultValue=null) + { + if($this->_globalState===null) + $this->loadGlobalState(); + $changed=$this->_stateChanged; + if($value===$defaultValue) + { + if(isset($this->_globalState[$key])) + { + unset($this->_globalState[$key]); + $this->_stateChanged=true; + } + } + else if(!isset($this->_globalState[$key]) || $this->_globalState[$key]!==$value) + { + $this->_globalState[$key]=$value; + $this->_stateChanged=true; + } + if($this->_stateChanged!==$changed) + $this->attachEventHandler('onEndRequest',array($this,'saveGlobalState')); + } + public function clearGlobalState($key) + { + $this->setGlobalState($key,true,true); + } + public function loadGlobalState() + { + $persister=$this->getStatePersister(); + if(($this->_globalState=$persister->load())===null) + $this->_globalState=array(); + $this->_stateChanged=false; + $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState')); + } + public function saveGlobalState() + { + if($this->_stateChanged) + { + $this->_stateChanged=false; + $this->detachEventHandler('onEndRequest',array($this,'saveGlobalState')); + $this->getStatePersister()->save($this->_globalState); + } + } + public function handleException($exception) + { + // disable error capturing to avoid recursive errors + restore_error_handler(); + restore_exception_handler(); + $category='exception.'.get_class($exception); + if($exception instanceof CHttpException) + $category.='.'.$exception->statusCode; + // php <5.2 doesn't support string conversion auto-magically + $message=$exception->__toString(); + if(isset($_SERVER['REQUEST_URI'])) + $message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI']; + if(isset($_SERVER['HTTP_REFERER'])) + $message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER']; + $message.="\n---"; + Yii::log($message,CLogger::LEVEL_ERROR,$category); + try + { + $event=new CExceptionEvent($this,$exception); + $this->onException($event); + if(!$event->handled) + { + // try an error handler + if(($handler=$this->getErrorHandler())!==null) + $handler->handle($event); + else + $this->displayException($exception); + } + } + catch(Exception $e) + { + $this->displayException($e); + } + try + { + $this->end(1); + } + catch(Exception $e) + { + // use the most primitive way to log error + $msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n"; + $msg .= $e->getTraceAsString()."\n"; + $msg .= "Previous exception:\n"; + $msg .= get_class($exception).': '.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().")\n"; + $msg .= $exception->getTraceAsString()."\n"; + $msg .= '$_SERVER='.var_export($_SERVER,true); + error_log($msg); + exit(1); + } + } + public function handleError($code,$message,$file,$line) + { + if($code & error_reporting()) + { + // disable error capturing to avoid recursive errors + restore_error_handler(); + restore_exception_handler(); + $log="$message ($file:$line)\nStack trace:\n"; + $trace=debug_backtrace(); + // skip the first 3 stacks as they do not tell the error position + if(count($trace)>3) + $trace=array_slice($trace,3); + foreach($trace as $i=>$t) + { + if(!isset($t['file'])) + $t['file']='unknown'; + if(!isset($t['line'])) + $t['line']=0; + if(!isset($t['function'])) + $t['function']='unknown'; + $log.="#$i {$t['file']}({$t['line']}): "; + if(isset($t['object']) && is_object($t['object'])) + $log.=get_class($t['object']).'->'; + $log.="{$t['function']}()\n"; + } + if(isset($_SERVER['REQUEST_URI'])) + $log.='REQUEST_URI='.$_SERVER['REQUEST_URI']; + Yii::log($log,CLogger::LEVEL_ERROR,'php'); + try + { + Yii::import('CErrorEvent',true); + $event=new CErrorEvent($this,$code,$message,$file,$line); + $this->onError($event); + if(!$event->handled) + { + // try an error handler + if(($handler=$this->getErrorHandler())!==null) + $handler->handle($event); + else + $this->displayError($code,$message,$file,$line); + } + } + catch(Exception $e) + { + $this->displayException($e); + } + try + { + $this->end(1); + } + catch(Exception $e) + { + // use the most primitive way to log error + $msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n"; + $msg .= $e->getTraceAsString()."\n"; + $msg .= "Previous error:\n"; + $msg .= $log."\n"; + $msg .= '$_SERVER='.var_export($_SERVER,true); + error_log($msg); + exit(1); + } + } + } + public function onException($event) + { + $this->raiseEvent('onException',$event); + } + public function onError($event) + { + $this->raiseEvent('onError',$event); + } + public function displayError($code,$message,$file,$line) + { + if(YII_DEBUG) + { + echo "<h1>PHP Error [$code]</h1>\n"; + echo "<p>$message ($file:$line)</p>\n"; + echo '<pre>'; + $trace=debug_backtrace(); + // skip the first 3 stacks as they do not tell the error position + if(count($trace)>3) + $trace=array_slice($trace,3); + foreach($trace as $i=>$t) + { + if(!isset($t['file'])) + $t['file']='unknown'; + if(!isset($t['line'])) + $t['line']=0; + if(!isset($t['function'])) + $t['function']='unknown'; + echo "#$i {$t['file']}({$t['line']}): "; + if(isset($t['object']) && is_object($t['object'])) + echo get_class($t['object']).'->'; + echo "{$t['function']}()\n"; + } + echo '</pre>'; + } + else + { + echo "<h1>PHP Error [$code]</h1>\n"; + echo "<p>$message</p>\n"; + } + } + public function displayException($exception) + { + if(YII_DEBUG) + { + echo '<h1>'.get_class($exception)."</h1>\n"; + echo '<p>'.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().')</p>'; + echo '<pre>'.$exception->getTraceAsString().'</pre>'; + } + else + { + echo '<h1>'.get_class($exception)."</h1>\n"; + echo '<p>'.$exception->getMessage().'</p>'; + } + } + protected function initSystemHandlers() + { + if(YII_ENABLE_EXCEPTION_HANDLER) + set_exception_handler(array($this,'handleException')); + if(YII_ENABLE_ERROR_HANDLER) + set_error_handler(array($this,'handleError'),error_reporting()); + } + protected function registerCoreComponents() + { + $components=array( + 'coreMessages'=>array( + 'class'=>'CPhpMessageSource', + 'language'=>'en_us', + 'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages', + ), + 'db'=>array( + 'class'=>'CDbConnection', + ), + 'messages'=>array( + 'class'=>'CPhpMessageSource', + ), + 'errorHandler'=>array( + 'class'=>'CErrorHandler', + ), + 'securityManager'=>array( + 'class'=>'CSecurityManager', + ), + 'statePersister'=>array( + 'class'=>'CStatePersister', + ), + 'urlManager'=>array( + 'class'=>'CUrlManager', + ), + 'request'=>array( + 'class'=>'CHttpRequest', + ), + 'format'=>array( + 'class'=>'CFormatter', + ), + ); + $this->setComponents($components); + } +} +class CWebApplication extends CApplication +{ + public $defaultController='site'; + public $layout='main'; + public $controllerMap=array(); + public $catchAllRequest; + private $_controllerPath; + private $_viewPath; + private $_systemViewPath; + private $_layoutPath; + private $_controller; + private $_theme; + public function processRequest() + { + if(is_array($this->catchAllRequest) && isset($this->catchAllRequest[0])) + { + $route=$this->catchAllRequest[0]; + foreach(array_splice($this->catchAllRequest,1) as $name=>$value) + $_GET[$name]=$value; + } + else + $route=$this->getUrlManager()->parseUrl($this->getRequest()); + $this->runController($route); + } + protected function registerCoreComponents() + { + parent::registerCoreComponents(); + $components=array( + 'session'=>array( + 'class'=>'CHttpSession', + ), + 'assetManager'=>array( + 'class'=>'CAssetManager', + ), + 'user'=>array( + 'class'=>'CWebUser', + ), + 'themeManager'=>array( + 'class'=>'CThemeManager', + ), + 'authManager'=>array( + 'class'=>'CPhpAuthManager', + ), + 'clientScript'=>array( + 'class'=>'CClientScript', + ), + 'widgetFactory'=>array( + 'class'=>'CWidgetFactory', + ), + ); + $this->setComponents($components); + } + public function getAuthManager() + { + return $this->getComponent('authManager'); + } + public function getAssetManager() + { + return $this->getComponent('assetManager'); + } + public function getSession() + { + return $this->getComponent('session'); + } + public function getUser() + { + return $this->getComponent('user'); + } + public function getViewRenderer() + { + return $this->getComponent('viewRenderer'); + } + public function getClientScript() + { + return $this->getComponent('clientScript'); + } + public function getWidgetFactory() + { + return $this->getComponent('widgetFactory'); + } + public function getThemeManager() + { + return $this->getComponent('themeManager'); + } + public function getTheme() + { + if(is_string($this->_theme)) + $this->_theme=$this->getThemeManager()->getTheme($this->_theme); + return $this->_theme; + } + public function setTheme($value) + { + $this->_theme=$value; + } + public function runController($route) + { + if(($ca=$this->createController($route))!==null) + { + list($controller,$actionID)=$ca; + $oldController=$this->_controller; + $this->_controller=$controller; + $controller->init(); + $controller->run($actionID); + $this->_controller=$oldController; + } + else + throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".', + array('{route}'=>$route===''?$this->defaultController:$route))); + } + public function createController($route,$owner=null) + { + if($owner===null) + $owner=$this; + if(($route=trim($route,'/'))==='') + $route=$owner->defaultController; + $caseSensitive=$this->getUrlManager()->caseSensitive; + $route.='/'; + while(($pos=strpos($route,'/'))!==false) + { + $id=substr($route,0,$pos); + if(!preg_match('/^\w+$/',$id)) + return null; + if(!$caseSensitive) + $id=strtolower($id); + $route=(string)substr($route,$pos+1); + if(!isset($basePath)) // first segment + { + if(isset($owner->controllerMap[$id])) + { + return array( + Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner), + $this->parseActionParams($route), + ); + } + if(($module=$owner->getModule($id))!==null) + return $this->createController($route,$module); + $basePath=$owner->getControllerPath(); + $controllerID=''; + } + else + $controllerID.='/'; + $className=ucfirst($id).'Controller'; + $classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($classFile)) + { + if(!class_exists($className,false)) + require($classFile); + if(class_exists($className,false) && is_subclass_of($className,'CController')) + { + $id[0]=strtolower($id[0]); + return array( + new $className($controllerID.$id,$owner===$this?null:$owner), + $this->parseActionParams($route), + ); + } + return null; + } + $controllerID.=$id; + $basePath.=DIRECTORY_SEPARATOR.$id; + } + } + protected function parseActionParams($pathInfo) + { + if(($pos=strpos($pathInfo,'/'))!==false) + { + $manager=$this->getUrlManager(); + $manager->parsePathInfo((string)substr($pathInfo,$pos+1)); + $actionID=substr($pathInfo,0,$pos); + return $manager->caseSensitive ? $actionID : strtolower($actionID); + } + else + return $pathInfo; + } + public function getController() + { + return $this->_controller; + } + public function setController($value) + { + $this->_controller=$value; + } + public function getControllerPath() + { + if($this->_controllerPath!==null) + return $this->_controllerPath; + else + return $this->_controllerPath=$this->getBasePath().DIRECTORY_SEPARATOR.'controllers'; + } + public function setControllerPath($value) + { + if(($this->_controllerPath=realpath($value))===false || !is_dir($this->_controllerPath)) + throw new CException(Yii::t('yii','The controller path "{path}" is not a valid directory.', + array('{path}'=>$value))); + } + public function getViewPath() + { + if($this->_viewPath!==null) + return $this->_viewPath; + else + return $this->_viewPath=$this->getBasePath().DIRECTORY_SEPARATOR.'views'; + } + public function setViewPath($path) + { + if(($this->_viewPath=realpath($path))===false || !is_dir($this->_viewPath)) + throw new CException(Yii::t('yii','The view path "{path}" is not a valid directory.', + array('{path}'=>$path))); + } + public function getSystemViewPath() + { + if($this->_systemViewPath!==null) + return $this->_systemViewPath; + else + return $this->_systemViewPath=$this->getViewPath().DIRECTORY_SEPARATOR.'system'; + } + public function setSystemViewPath($path) + { + if(($this->_systemViewPath=realpath($path))===false || !is_dir($this->_systemViewPath)) + throw new CException(Yii::t('yii','The system view path "{path}" is not a valid directory.', + array('{path}'=>$path))); + } + public function getLayoutPath() + { + if($this->_layoutPath!==null) + return $this->_layoutPath; + else + return $this->_layoutPath=$this->getViewPath().DIRECTORY_SEPARATOR.'layouts'; + } + public function setLayoutPath($path) + { + if(($this->_layoutPath=realpath($path))===false || !is_dir($this->_layoutPath)) + throw new CException(Yii::t('yii','The layout path "{path}" is not a valid directory.', + array('{path}'=>$path))); + } + public function beforeControllerAction($controller,$action) + { + return true; + } + public function afterControllerAction($controller,$action) + { + } + public function findModule($id) + { + if(($controller=$this->getController())!==null && ($module=$controller->getModule())!==null) + { + do + { + if(($m=$module->getModule($id))!==null) + return $m; + } while(($module=$module->getParentModule())!==null); + } + if(($m=$this->getModule($id))!==null) + return $m; + } + protected function init() + { + parent::init(); + // preload 'request' so that it has chance to respond to onBeginRequest event. + $this->getRequest(); + } +} +class CMap extends CComponent implements IteratorAggregate,ArrayAccess,Countable +{ + private $_d=array(); + private $_r=false; + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + public function getReadOnly() + { + return $this->_r; + } + protected function setReadOnly($value) + { + $this->_r=$value; + } + public function getIterator() + { + return new CMapIterator($this->_d); + } + public function count() + { + return $this->getCount(); + } + public function getCount() + { + return count($this->_d); + } + public function getKeys() + { + return array_keys($this->_d); + } + public function itemAt($key) + { + if(isset($this->_d[$key])) + return $this->_d[$key]; + else + return null; + } + public function add($key,$value) + { + if(!$this->_r) + { + if($key===null) + $this->_d[]=$value; + else + $this->_d[$key]=$value; + } + else + throw new CException(Yii::t('yii','The map is read only.')); + } + public function remove($key) + { + if(!$this->_r) + { + if(isset($this->_d[$key])) + { + $value=$this->_d[$key]; + unset($this->_d[$key]); + return $value; + } + else + { + // it is possible the value is null, which is not detected by isset + unset($this->_d[$key]); + return null; + } + } + else + throw new CException(Yii::t('yii','The map is read only.')); + } + public function clear() + { + foreach(array_keys($this->_d) as $key) + $this->remove($key); + } + public function contains($key) + { + return isset($this->_d[$key]) || array_key_exists($key,$this->_d); + } + public function toArray() + { + return $this->_d; + } + public function copyFrom($data) + { + if(is_array($data) || $data instanceof Traversable) + { + if($this->getCount()>0) + $this->clear(); + if($data instanceof CMap) + $data=$data->_d; + foreach($data as $key=>$value) + $this->add($key,$value); + } + else if($data!==null) + throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.')); + } + public function mergeWith($data,$recursive=true) + { + if(is_array($data) || $data instanceof Traversable) + { + if($data instanceof CMap) + $data=$data->_d; + if($recursive) + { + if($data instanceof Traversable) + { + $d=array(); + foreach($data as $key=>$value) + $d[$key]=$value; + $this->_d=self::mergeArray($this->_d,$d); + } + else + $this->_d=self::mergeArray($this->_d,$data); + } + else + { + foreach($data as $key=>$value) + $this->add($key,$value); + } + } + else if($data!==null) + throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.')); + } + public static function mergeArray($a,$b) + { + $args=func_get_args(); + $res=array_shift($args); + while(!empty($args)) + { + $next=array_shift($args); + foreach($next as $k => $v) + { + if(is_integer($k)) + isset($res[$k]) ? $res[]=$v : $res[$k]=$v; + else if(is_array($v) && isset($res[$k]) && is_array($res[$k])) + $res[$k]=self::mergeArray($res[$k],$v); + else + $res[$k]=$v; + } + } + return $res; + } + public function offsetExists($offset) + { + return $this->contains($offset); + } + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + public function offsetSet($offset,$item) + { + $this->add($offset,$item); + } + public function offsetUnset($offset) + { + $this->remove($offset); + } +} +class CLogger extends CComponent +{ + const LEVEL_TRACE='trace'; + const LEVEL_WARNING='warning'; + const LEVEL_ERROR='error'; + const LEVEL_INFO='info'; + const LEVEL_PROFILE='profile'; + public $autoFlush=10000; + public $autoDump=false; + private $_logs=array(); + private $_logCount=0; + private $_levels; + private $_categories; + private $_timings; + private $_processing = false; + public function log($message,$level='info',$category='application') + { + $this->_logs[]=array($message,$level,$category,microtime(true)); + $this->_logCount++; + if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush && !$this->_processing) + { + $this->_processing=true; + $this->flush($this->autoDump); + $this->_processing=false; + } + } + 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; + else if(empty($levels)) + return array_values(array_filter(array_filter($this->_logs,array($this,'filterByCategory')))); + else if(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')))); + } + } + 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; + } + private function filterByLevel($value) + { + return in_array(strtolower($value[1]),$this->_levels)?$value:false; + } + public function getExecutionTime() + { + return microtime(true)-YII_BEGIN_TIME; + } + public function getMemoryUsage() + { + if(function_exists('memory_get_usage')) + return memory_get_usage(); + else + { + $output=array(); + if(strncmp(PHP_OS,'WIN',3)===0) + { + exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST',$output); + return isset($output[5])?preg_replace('/[\D]/','',$output[5])*1024 : 0; + } + else + { + $pid=getmypid(); + exec("ps -eo%mem,rss,pid | grep $pid", $output); + $output=explode(" ",$output[0]); + return isset($output[1]) ? $output[1]*1024 : 0; + } + } + } + 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->_logs as $log) + { + if($log[1]!==CLogger::LEVEL_PROFILE) + continue; + list($message,$level,$category,$timestamp)=$log; + if(!strncasecmp($message,'begin:',6)) + { + $log[0]=substr($message,6); + $stack[]=$log; + } + else if(!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 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]; + $this->_timings[]=array($last[0],$last[2],$delta); + } + } + public function flush($dumpLogs=false) + { + $this->onFlush(new CEvent($this, array('dumpLogs'=>$dumpLogs))); + $this->_logs=array(); + $this->_logCount=0; + } + public function onFlush($event) + { + $this->raiseEvent('onFlush', $event); + } +} +abstract class CApplicationComponent extends CComponent implements IApplicationComponent +{ + public $behaviors=array(); + private $_initialized=false; + public function init() + { + $this->attachBehaviors($this->behaviors); + $this->_initialized=true; + } + public function getIsInitialized() + { + return $this->_initialized; + } +} +class CHttpRequest extends CApplicationComponent +{ + public $enableCookieValidation=false; + public $enableCsrfValidation=false; + public $csrfTokenName='YII_CSRF_TOKEN'; + public $csrfCookie; + private $_requestUri; + private $_pathInfo; + private $_scriptFile; + private $_scriptUrl; + private $_hostInfo; + private $_baseUrl; + private $_cookies; + private $_preferredLanguage; + private $_csrfToken; + private $_deleteParams; + private $_putParams; + public function init() + { + parent::init(); + $this->normalizeRequest(); + } + protected function normalizeRequest() + { + // normalize request + if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) + { + if(isset($_GET)) + $_GET=$this->stripSlashes($_GET); + if(isset($_POST)) + $_POST=$this->stripSlashes($_POST); + if(isset($_REQUEST)) + $_REQUEST=$this->stripSlashes($_REQUEST); + if(isset($_COOKIE)) + $_COOKIE=$this->stripSlashes($_COOKIE); + } + if($this->enableCsrfValidation) + Yii::app()->attachEventHandler('onBeginRequest',array($this,'validateCsrfToken')); + } + public function stripSlashes(&$data) + { + return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data); + } + public function getParam($name,$defaultValue=null) + { + return isset($_GET[$name]) ? $_GET[$name] : (isset($_POST[$name]) ? $_POST[$name] : $defaultValue); + } + public function getQuery($name,$defaultValue=null) + { + return isset($_GET[$name]) ? $_GET[$name] : $defaultValue; + } + public function getPost($name,$defaultValue=null) + { + return isset($_POST[$name]) ? $_POST[$name] : $defaultValue; + } + public function getDelete($name,$defaultValue=null) + { + if($this->_deleteParams===null) + $this->_deleteParams=$this->getIsDeleteRequest() ? $this->getRestParams() : array(); + return isset($this->_deleteParams[$name]) ? $this->_deleteParams[$name] : $defaultValue; + } + public function getPut($name,$defaultValue=null) + { + if($this->_putParams===null) + $this->_putParams=$this->getIsPutRequest() ? $this->getRestParams() : array(); + return isset($this->_putParams[$name]) ? $this->_putParams[$name] : $defaultValue; + } + protected function getRestParams() + { + $result=array(); + if(function_exists('mb_parse_str')) + mb_parse_str(file_get_contents('php://input'), $result); + else + parse_str(file_get_contents('php://input'), $result); + return $result; + } + public function getUrl() + { + return $this->getRequestUri(); + } + public function getHostInfo($schema='') + { + if($this->_hostInfo===null) + { + if($secure=$this->getIsSecureConnection()) + $http='https'; + else + $http='http'; + if(isset($_SERVER['HTTP_HOST'])) + $this->_hostInfo=$http.'://'.$_SERVER['HTTP_HOST']; + else + { + $this->_hostInfo=$http.'://'.$_SERVER['SERVER_NAME']; + $port=$secure ? $this->getSecurePort() : $this->getPort(); + if(($port!==80 && !$secure) || ($port!==443 && $secure)) + $this->_hostInfo.=':'.$port; + } + } + if($schema!=='') + { + $secure=$this->getIsSecureConnection(); + if($secure && $schema==='https' || !$secure && $schema==='http') + return $this->_hostInfo; + $port=$schema==='https' ? $this->getSecurePort() : $this->getPort(); + if($port!==80 && $schema==='http' || $port!==443 && $schema==='https') + $port=':'.$port; + else + $port=''; + $pos=strpos($this->_hostInfo,':'); + return $schema.substr($this->_hostInfo,$pos,strcspn($this->_hostInfo,':',$pos+1)+1).$port; + } + else + return $this->_hostInfo; + } + public function setHostInfo($value) + { + $this->_hostInfo=rtrim($value,'/'); + } + public function getBaseUrl($absolute=false) + { + if($this->_baseUrl===null) + $this->_baseUrl=rtrim(dirname($this->getScriptUrl()),'\\/'); + return $absolute ? $this->getHostInfo() . $this->_baseUrl : $this->_baseUrl; + } + public function setBaseUrl($value) + { + $this->_baseUrl=$value; + } + public function getScriptUrl() + { + if($this->_scriptUrl===null) + { + $scriptName=basename($_SERVER['SCRIPT_FILENAME']); + if(basename($_SERVER['SCRIPT_NAME'])===$scriptName) + $this->_scriptUrl=$_SERVER['SCRIPT_NAME']; + else if(basename($_SERVER['PHP_SELF'])===$scriptName) + $this->_scriptUrl=$_SERVER['PHP_SELF']; + else if(isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME'])===$scriptName) + $this->_scriptUrl=$_SERVER['ORIG_SCRIPT_NAME']; + else if(($pos=strpos($_SERVER['PHP_SELF'],'/'.$scriptName))!==false) + $this->_scriptUrl=substr($_SERVER['SCRIPT_NAME'],0,$pos).'/'.$scriptName; + else if(isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===0) + $this->_scriptUrl=str_replace('\\','/',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME'])); + else + throw new CException(Yii::t('yii','CHttpRequest is unable to determine the entry script URL.')); + } + return $this->_scriptUrl; + } + public function setScriptUrl($value) + { + $this->_scriptUrl='/'.trim($value,'/'); + } + public function getPathInfo() + { + if($this->_pathInfo===null) + { + $pathInfo=$this->getRequestUri(); + if(($pos=strpos($pathInfo,'?'))!==false) + $pathInfo=substr($pathInfo,0,$pos); + $pathInfo=$this->decodePathInfo($pathInfo); + $scriptUrl=$this->getScriptUrl(); + $baseUrl=$this->getBaseUrl(); + if(strpos($pathInfo,$scriptUrl)===0) + $pathInfo=substr($pathInfo,strlen($scriptUrl)); + else if($baseUrl==='' || strpos($pathInfo,$baseUrl)===0) + $pathInfo=substr($pathInfo,strlen($baseUrl)); + else if(strpos($_SERVER['PHP_SELF'],$scriptUrl)===0) + $pathInfo=substr($_SERVER['PHP_SELF'],strlen($scriptUrl)); + else + throw new CException(Yii::t('yii','CHttpRequest is unable to determine the path info of the request.')); + $this->_pathInfo=trim($pathInfo,'/'); + } + return $this->_pathInfo; + } + protected function decodePathInfo($pathInfo) + { + $pathInfo = urldecode($pathInfo); + // is it UTF-8? + // http://w3.org/International/questions/qa-forms-utf-8.html + if(preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*$%xs', $pathInfo)) + { + return $pathInfo; + } + else + { + return utf8_encode($pathInfo); + } + } + public function getRequestUri() + { + if($this->_requestUri===null) + { + if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS + $this->_requestUri=$_SERVER['HTTP_X_REWRITE_URL']; + else if(isset($_SERVER['REQUEST_URI'])) + { + $this->_requestUri=$_SERVER['REQUEST_URI']; + if(!empty($_SERVER['HTTP_HOST'])) + { + if(strpos($this->_requestUri,$_SERVER['HTTP_HOST'])!==false) + $this->_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',$this->_requestUri); + } + else + $this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',$this->_requestUri); + } + else if(isset($_SERVER['ORIG_PATH_INFO'])) // IIS 5.0 CGI + { + $this->_requestUri=$_SERVER['ORIG_PATH_INFO']; + if(!empty($_SERVER['QUERY_STRING'])) + $this->_requestUri.='?'.$_SERVER['QUERY_STRING']; + } + else + throw new CException(Yii::t('yii','CHttpRequest is unable to determine the request URI.')); + } + return $this->_requestUri; + } + public function getQueryString() + { + return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:''; + } + public function getIsSecureConnection() + { + return isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'],'on'); + } + public function getRequestType() + { + return strtoupper(isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'GET'); + } + public function getIsPostRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'POST'); + } + public function getIsDeleteRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'DELETE'); + } + public function getIsPutRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'PUT'); + } + public function getIsAjaxRequest() + { + return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'; + } + public function getServerName() + { + return $_SERVER['SERVER_NAME']; + } + public function getServerPort() + { + return $_SERVER['SERVER_PORT']; + } + public function getUrlReferrer() + { + return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null; + } + public function getUserAgent() + { + return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null; + } + public function getUserHostAddress() + { + return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'127.0.0.1'; + } + public function getUserHost() + { + return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null; + } + public function getScriptFile() + { + if($this->_scriptFile!==null) + return $this->_scriptFile; + else + return $this->_scriptFile=realpath($_SERVER['SCRIPT_FILENAME']); + } + public function getBrowser($userAgent=null) + { + return get_browser($userAgent,true); + } + public function getAcceptTypes() + { + return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null; + } + private $_port; + public function getPort() + { + if($this->_port===null) + $this->_port=!$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 80; + return $this->_port; + } + public function setPort($value) + { + $this->_port=(int)$value; + $this->_hostInfo=null; + } + private $_securePort; + public function getSecurePort() + { + if($this->_securePort===null) + $this->_securePort=$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 443; + return $this->_securePort; + } + public function setSecurePort($value) + { + $this->_securePort=(int)$value; + $this->_hostInfo=null; + } + public function getCookies() + { + if($this->_cookies!==null) + return $this->_cookies; + else + return $this->_cookies=new CCookieCollection($this); + } + public function redirect($url,$terminate=true,$statusCode=302) + { + if(strpos($url,'/')===0) + $url=$this->getHostInfo().$url; + header('Location: '.$url, true, $statusCode); + if($terminate) + Yii::app()->end(); + } + public function getPreferredLanguage() + { + if($this->_preferredLanguage===null) + { + if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && ($n=preg_match_all('/([\w\-_]+)\s*(;\s*q\s*=\s*(\d*\.\d*))?/',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches))>0) + { + $languages=array(); + for($i=0;$i<$n;++$i) + $languages[$matches[1][$i]]=empty($matches[3][$i]) ? 1.0 : floatval($matches[3][$i]); + arsort($languages); + foreach($languages as $language=>$pref) + return $this->_preferredLanguage=CLocale::getCanonicalID($language); + } + return $this->_preferredLanguage=false; + } + return $this->_preferredLanguage; + } + public function sendFile($fileName,$content,$mimeType=null,$terminate=true) + { + if($mimeType===null) + { + if(($mimeType=CFileHelper::getMimeTypeByExtension($fileName))===null) + $mimeType='text/plain'; + } + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header("Content-type: $mimeType"); + if(ob_get_length()===false) + header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($content,'8bit') : strlen($content))); + header("Content-Disposition: attachment; filename=\"$fileName\""); + header('Content-Transfer-Encoding: binary'); + if($terminate) + { + // clean up the application first because the file downloading could take long time + // which may cause timeout of some resources (such as DB connection) + Yii::app()->end(0,false); + echo $content; + exit(0); + } + else + echo $content; + } + public function xSendFile($filePath, $options=array()) + { + if(!isset($options['forceDownload']) || $options['forceDownload']) + $disposition='attachment'; + else + $disposition='inline'; + if(!isset($options['saveName'])) + $options['saveName']=basename($filePath); + if(!isset($options['mimeType'])) + { + if(($options['mimeType']=CFileHelper::getMimeTypeByExtension($filePath))===null) + $options['mimeType']='text/plain'; + } + if(!isset($options['xHeader'])) + $options['xHeader']='X-Sendfile'; + if($options['mimeType'] !== null) + header('Content-type: '.$options['mimeType']); + header('Content-Disposition: '.$disposition.'; filename="'.$options['saveName'].'"'); + if(isset($options['addHeaders'])) + { + foreach($options['addHeaders'] as $header=>$value) + header($header.': '.$value); + } + header(trim($options['xHeader']).': '.$filePath); + if(!isset($options['terminate']) || $options['terminate']) + Yii::app()->end(); + } + public function getCsrfToken() + { + if($this->_csrfToken===null) + { + $cookie=$this->getCookies()->itemAt($this->csrfTokenName); + if(!$cookie || ($this->_csrfToken=$cookie->value)==null) + { + $cookie=$this->createCsrfCookie(); + $this->_csrfToken=$cookie->value; + $this->getCookies()->add($cookie->name,$cookie); + } + } + return $this->_csrfToken; + } + protected function createCsrfCookie() + { + $cookie=new CHttpCookie($this->csrfTokenName,sha1(uniqid(mt_rand(),true))); + if(is_array($this->csrfCookie)) + { + foreach($this->csrfCookie as $name=>$value) + $cookie->$name=$value; + } + return $cookie; + } + public function validateCsrfToken($event) + { + if($this->getIsPostRequest()) + { + // only validate POST requests + $cookies=$this->getCookies(); + if($cookies->contains($this->csrfTokenName) && isset($_POST[$this->csrfTokenName])) + { + $tokenFromCookie=$cookies->itemAt($this->csrfTokenName)->value; + $tokenFromPost=$_POST[$this->csrfTokenName]; + $valid=$tokenFromCookie===$tokenFromPost; + } + else + $valid=false; + if(!$valid) + throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.')); + } + } +} +class CCookieCollection extends CMap +{ + private $_request; + private $_initialized=false; + public function __construct(CHttpRequest $request) + { + $this->_request=$request; + $this->copyfrom($this->getCookies()); + $this->_initialized=true; + } + public function getRequest() + { + return $this->_request; + } + protected function getCookies() + { + $cookies=array(); + if($this->_request->enableCookieValidation) + { + $sm=Yii::app()->getSecurityManager(); + foreach($_COOKIE as $name=>$value) + { + if(is_string($value) && ($value=$sm->validateData($value))!==false) + $cookies[$name]=new CHttpCookie($name,@unserialize($value)); + } + } + else + { + foreach($_COOKIE as $name=>$value) + $cookies[$name]=new CHttpCookie($name,$value); + } + return $cookies; + } + public function add($name,$cookie) + { + if($cookie instanceof CHttpCookie) + { + $this->remove($name); + parent::add($name,$cookie); + if($this->_initialized) + $this->addCookie($cookie); + } + else + throw new CException(Yii::t('yii','CHttpCookieCollection can only hold CHttpCookie objects.')); + } + public function remove($name) + { + if(($cookie=parent::remove($name))!==null) + { + if($this->_initialized) + $this->removeCookie($cookie); + } + return $cookie; + } + protected function addCookie($cookie) + { + $value=$cookie->value; + if($this->_request->enableCookieValidation) + $value=Yii::app()->getSecurityManager()->hashData(serialize($value)); + if(version_compare(PHP_VERSION,'5.2.0','>=')) + setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); + else + setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure); + } + protected function removeCookie($cookie) + { + if(version_compare(PHP_VERSION,'5.2.0','>=')) + setcookie($cookie->name,null,0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); + else + setcookie($cookie->name,null,0,$cookie->path,$cookie->domain,$cookie->secure); + } +} +class CUrlManager extends CApplicationComponent +{ + const CACHE_KEY='Yii.CUrlManager.rules'; + const GET_FORMAT='get'; + const PATH_FORMAT='path'; + public $rules=array(); + public $urlSuffix=''; + public $showScriptName=true; + public $appendParams=true; + public $routeVar='r'; + public $caseSensitive=true; + public $matchValue=false; + public $cacheID='cache'; + public $useStrictParsing=false; + public $urlRuleClass='CUrlRule'; + private $_urlFormat=self::GET_FORMAT; + private $_rules=array(); + private $_baseUrl; + public function init() + { + parent::init(); + $this->processRules(); + } + protected function processRules() + { + if(empty($this->rules) || $this->getUrlFormat()===self::GET_FORMAT) + return; + if($this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null) + { + $hash=md5(serialize($this->rules)); + if(($data=$cache->get(self::CACHE_KEY))!==false && isset($data[1]) && $data[1]===$hash) + { + $this->_rules=$data[0]; + return; + } + } + foreach($this->rules as $pattern=>$route) + $this->_rules[]=$this->createUrlRule($route,$pattern); + if(isset($cache)) + $cache->set(self::CACHE_KEY,array($this->_rules,$hash)); + } + public function addRules($rules, $append=true) + { + if ($append) + { + foreach($rules as $pattern=>$route) + $this->_rules[]=$this->createUrlRule($route,$pattern); + } + else + { + foreach($rules as $pattern=>$route) + array_unshift($this->_rules, $this->createUrlRule($route,$pattern)); + } + } + protected function createUrlRule($route,$pattern) + { + if(is_array($route) && isset($route['class'])) + return $route; + else + return new $this->urlRuleClass($route,$pattern); + } + public function createUrl($route,$params=array(),$ampersand='&') + { + unset($params[$this->routeVar]); + foreach($params as $i=>$param) + if($param===null) + $params[$i]=''; + if(isset($params['#'])) + { + $anchor='#'.$params['#']; + unset($params['#']); + } + else + $anchor=''; + $route=trim($route,'/'); + foreach($this->_rules as $i=>$rule) + { + if(is_array($rule)) + $this->_rules[$i]=$rule=Yii::createComponent($rule); + if(($url=$rule->createUrl($this,$route,$params,$ampersand))!==false) + { + if($rule->hasHostInfo) + return $url==='' ? '/'.$anchor : $url.$anchor; + else + return $this->getBaseUrl().'/'.$url.$anchor; + } + } + return $this->createUrlDefault($route,$params,$ampersand).$anchor; + } + protected function createUrlDefault($route,$params,$ampersand) + { + if($this->getUrlFormat()===self::PATH_FORMAT) + { + $url=rtrim($this->getBaseUrl().'/'.$route,'/'); + if($this->appendParams) + { + $url=rtrim($url.'/'.$this->createPathInfo($params,'/','/'),'/'); + return $route==='' ? $url : $url.$this->urlSuffix; + } + else + { + if($route!=='') + $url.=$this->urlSuffix; + $query=$this->createPathInfo($params,'=',$ampersand); + return $query==='' ? $url : $url.'?'.$query; + } + } + else + { + $url=$this->getBaseUrl(); + if(!$this->showScriptName) + $url.='/'; + if($route!=='') + { + $url.='?'.$this->routeVar.'='.$route; + if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') + $url.=$ampersand.$query; + } + else if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') + $url.='?'.$query; + return $url; + } + } + public function parseUrl($request) + { + if($this->getUrlFormat()===self::PATH_FORMAT) + { + $rawPathInfo=$request->getPathInfo(); + $pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix); + foreach($this->_rules as $i=>$rule) + { + if(is_array($rule)) + $this->_rules[$i]=$rule=Yii::createComponent($rule); + if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false) + return isset($_GET[$this->routeVar]) ? $_GET[$this->routeVar] : $r; + } + if($this->useStrictParsing) + throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".', + array('{route}'=>$pathInfo))); + else + return $pathInfo; + } + else if(isset($_GET[$this->routeVar])) + return $_GET[$this->routeVar]; + else if(isset($_POST[$this->routeVar])) + return $_POST[$this->routeVar]; + else + return ''; + } + public function parsePathInfo($pathInfo) + { + if($pathInfo==='') + return; + $segs=explode('/',$pathInfo.'/'); + $n=count($segs); + for($i=0;$i<$n-1;$i+=2) + { + $key=$segs[$i]; + if($key==='') continue; + $value=$segs[$i+1]; + if(($pos=strpos($key,'['))!==false && ($m=preg_match_all('/\[(.*?)\]/',$key,$matches))>0) + { + $name=substr($key,0,$pos); + for($j=$m-1;$j>=0;--$j) + { + if($matches[1][$j]==='') + $value=array($value); + else + $value=array($matches[1][$j]=>$value); + } + if(isset($_GET[$name]) && is_array($_GET[$name])) + $value=CMap::mergeArray($_GET[$name],$value); + $_REQUEST[$name]=$_GET[$name]=$value; + } + else + $_REQUEST[$key]=$_GET[$key]=$value; + } + } + public function createPathInfo($params,$equal,$ampersand, $key=null) + { + $pairs = array(); + foreach($params as $k => $v) + { + if ($key!==null) + $k = $key.'['.$k.']'; + if (is_array($v)) + $pairs[]=$this->createPathInfo($v,$equal,$ampersand, $k); + else + $pairs[]=urlencode($k).$equal.urlencode($v); + } + return implode($ampersand,$pairs); + } + public function removeUrlSuffix($pathInfo,$urlSuffix) + { + if($urlSuffix!=='' && substr($pathInfo,-strlen($urlSuffix))===$urlSuffix) + return substr($pathInfo,0,-strlen($urlSuffix)); + else + return $pathInfo; + } + public function getBaseUrl() + { + if($this->_baseUrl!==null) + return $this->_baseUrl; + else + { + if($this->showScriptName) + $this->_baseUrl=Yii::app()->getRequest()->getScriptUrl(); + else + $this->_baseUrl=Yii::app()->getRequest()->getBaseUrl(); + return $this->_baseUrl; + } + } + public function setBaseUrl($value) + { + $this->_baseUrl=$value; + } + public function getUrlFormat() + { + return $this->_urlFormat; + } + public function setUrlFormat($value) + { + if($value===self::PATH_FORMAT || $value===self::GET_FORMAT) + $this->_urlFormat=$value; + else + throw new CException(Yii::t('yii','CUrlManager.UrlFormat must be either "path" or "get".')); + } +} +abstract class CBaseUrlRule extends CComponent +{ + public $hasHostInfo=false; + abstract public function createUrl($manager,$route,$params,$ampersand); + abstract public function parseUrl($manager,$request,$pathInfo,$rawPathInfo); +} +class CUrlRule extends CBaseUrlRule +{ + public $urlSuffix; + public $caseSensitive; + public $defaultParams=array(); + public $matchValue; + public $verb; + public $parsingOnly=false; + public $route; + public $references=array(); + public $routePattern; + public $pattern; + public $template; + public $params=array(); + public $append; + public $hasHostInfo; + public function __construct($route,$pattern) + { + if(is_array($route)) + { + foreach(array('urlSuffix', 'caseSensitive', 'defaultParams', 'matchValue', 'verb', 'parsingOnly') as $name) + { + if(isset($route[$name])) + $this->$name=$route[$name]; + } + if(isset($route['pattern'])) + $pattern=$route['pattern']; + $route=$route[0]; + } + $this->route=trim($route,'/'); + $tr2['/']=$tr['/']='\\/'; + if(strpos($route,'<')!==false && preg_match_all('/<(\w+)>/',$route,$matches2)) + { + foreach($matches2[1] as $name) + $this->references[$name]="<$name>"; + } + $this->hasHostInfo=!strncasecmp($pattern,'http://',7) || !strncasecmp($pattern,'https://',8); + if($this->verb!==null) + $this->verb=preg_split('/[\s,]+/',strtoupper($this->verb),-1,PREG_SPLIT_NO_EMPTY); + if(preg_match_all('/<(\w+):?(.*?)?>/',$pattern,$matches)) + { + $tokens=array_combine($matches[1],$matches[2]); + foreach($tokens as $name=>$value) + { + if($value==='') + $value='[^\/]+'; + $tr["<$name>"]="(?P<$name>$value)"; + if(isset($this->references[$name])) + $tr2["<$name>"]=$tr["<$name>"]; + else + $this->params[$name]=$value; + } + } + $p=rtrim($pattern,'*'); + $this->append=$p!==$pattern; + $p=trim($p,'/'); + $this->template=preg_replace('/<(\w+):?.*?>/','<$1>',$p); + $this->pattern='/^'.strtr($this->template,$tr).'\/'; + if($this->append) + $this->pattern.='/u'; + else + $this->pattern.='$/u'; + if($this->references!==array()) + $this->routePattern='/^'.strtr($this->route,$tr2).'$/u'; + if(YII_DEBUG && @preg_match($this->pattern,'test')===false) + throw new CException(Yii::t('yii','The URL pattern "{pattern}" for route "{route}" is not a valid regular expression.', + array('{route}'=>$route,'{pattern}'=>$pattern))); + } + public function createUrl($manager,$route,$params,$ampersand) + { + if($this->parsingOnly) + return false; + if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive) + $case=''; + else + $case='i'; + $tr=array(); + if($route!==$this->route) + { + if($this->routePattern!==null && preg_match($this->routePattern.$case,$route,$matches)) + { + foreach($this->references as $key=>$name) + $tr[$name]=$matches[$key]; + } + else + return false; + } + foreach($this->defaultParams as $key=>$value) + { + if(isset($params[$key])) + { + if($params[$key]==$value) + unset($params[$key]); + else + return false; + } + } + foreach($this->params as $key=>$value) + if(!isset($params[$key])) + return false; + if($manager->matchValue && $this->matchValue===null || $this->matchValue) + { + foreach($this->params as $key=>$value) + { + if(!preg_match('/'.$value.'/'.$case,$params[$key])) + return false; + } + } + foreach($this->params as $key=>$value) + { + $tr["<$key>"]=urlencode($params[$key]); + unset($params[$key]); + } + $suffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix; + $url=strtr($this->template,$tr); + if($this->hasHostInfo) + { + $hostInfo=Yii::app()->getRequest()->getHostInfo(); + if(stripos($url,$hostInfo)===0) + $url=substr($url,strlen($hostInfo)); + } + if(empty($params)) + return $url!=='' ? $url.$suffix : $url; + if($this->append) + $url.='/'.$manager->createPathInfo($params,'/','/').$suffix; + else + { + if($url!=='') + $url.=$suffix; + $url.='?'.$manager->createPathInfo($params,'=',$ampersand); + } + return $url; + } + public function parseUrl($manager,$request,$pathInfo,$rawPathInfo) + { + if($this->verb!==null && !in_array($request->getRequestType(), $this->verb, true)) + return false; + if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive) + $case=''; + else + $case='i'; + if($this->urlSuffix!==null) + $pathInfo=$manager->removeUrlSuffix($rawPathInfo,$this->urlSuffix); + // URL suffix required, but not found in the requested URL + if($manager->useStrictParsing && $pathInfo===$rawPathInfo) + { + $urlSuffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix; + if($urlSuffix!='' && $urlSuffix!=='/') + return false; + } + if($this->hasHostInfo) + $pathInfo=strtolower($request->getHostInfo()).rtrim('/'.$pathInfo,'/'); + $pathInfo.='/'; + if(preg_match($this->pattern.$case,$pathInfo,$matches)) + { + foreach($this->defaultParams as $name=>$value) + { + if(!isset($_GET[$name])) + $_REQUEST[$name]=$_GET[$name]=$value; + } + $tr=array(); + foreach($matches as $key=>$value) + { + if(isset($this->references[$key])) + $tr[$this->references[$key]]=$value; + else if(isset($this->params[$key])) + $_REQUEST[$key]=$_GET[$key]=$value; + } + if($pathInfo!==$matches[0]) // there're additional GET params + $manager->parsePathInfo(ltrim(substr($pathInfo,strlen($matches[0])),'/')); + if($this->routePattern!==null) + return strtr($this->route,$tr); + else + return $this->route; + } + else + return false; + } +} +abstract class CBaseController extends CComponent +{ + private $_widgetStack=array(); + abstract public function getViewFile($viewName); + public function renderFile($viewFile,$data=null,$return=false) + { + $widgetCount=count($this->_widgetStack); + if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile)) + $content=$renderer->renderFile($this,$viewFile,$data,$return); + else + $content=$this->renderInternal($viewFile,$data,$return); + if(count($this->_widgetStack)===$widgetCount) + return $content; + else + { + $widget=end($this->_widgetStack); + throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.', + array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget)))); + } + } + public function renderInternal($_viewFile_,$_data_=null,$_return_=false) + { + // we use special variable names here to avoid conflict when extracting data + if(is_array($_data_)) + extract($_data_,EXTR_PREFIX_SAME,'data'); + else + $data=$_data_; + if($_return_) + { + ob_start(); + ob_implicit_flush(false); + require($_viewFile_); + return ob_get_clean(); + } + else + require($_viewFile_); + } + public function createWidget($className,$properties=array()) + { + $widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties); + $widget->init(); + return $widget; + } + public function widget($className,$properties=array(),$captureOutput=false) + { + if($captureOutput) + { + ob_start(); + ob_implicit_flush(false); + $widget=$this->createWidget($className,$properties); + $widget->run(); + return ob_get_clean(); + } + else + { + $widget=$this->createWidget($className,$properties); + $widget->run(); + return $widget; + } + } + public function beginWidget($className,$properties=array()) + { + $widget=$this->createWidget($className,$properties); + $this->_widgetStack[]=$widget; + return $widget; + } + public function endWidget($id='') + { + if(($widget=array_pop($this->_widgetStack))!==null) + { + $widget->run(); + return $widget; + } + else + throw new CException(Yii::t('yii','{controller} has an extra endWidget({id}) call in its view.', + array('{controller}'=>get_class($this),'{id}'=>$id))); + } + public function beginClip($id,$properties=array()) + { + $properties['id']=$id; + $this->beginWidget('CClipWidget',$properties); + } + public function endClip() + { + $this->endWidget('CClipWidget'); + } + public function beginCache($id,$properties=array()) + { + $properties['id']=$id; + $cache=$this->beginWidget('COutputCache',$properties); + if($cache->getIsContentCached()) + { + $this->endCache(); + return false; + } + else + return true; + } + public function endCache() + { + $this->endWidget('COutputCache'); + } + public function beginContent($view=null,$data=array()) + { + $this->beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data)); + } + public function endContent() + { + $this->endWidget('CContentDecorator'); + } +} +class CController extends CBaseController +{ + const STATE_INPUT_NAME='YII_PAGE_STATE'; + public $layout; + public $defaultAction='index'; + private $_id; + private $_action; + private $_pageTitle; + private $_cachingStack; + private $_clips; + private $_dynamicOutput; + private $_pageStates; + private $_module; + public function __construct($id,$module=null) + { + $this->_id=$id; + $this->_module=$module; + $this->attachBehaviors($this->behaviors()); + } + public function init() + { + } + public function filters() + { + return array(); + } + public function actions() + { + return array(); + } + public function behaviors() + { + return array(); + } + public function accessRules() + { + return array(); + } + public function run($actionID) + { + if(($action=$this->createAction($actionID))!==null) + { + if(($parent=$this->getModule())===null) + $parent=Yii::app(); + if($parent->beforeControllerAction($this,$action)) + { + $this->runActionWithFilters($action,$this->filters()); + $parent->afterControllerAction($this,$action); + } + } + else + $this->missingAction($actionID); + } + public function runActionWithFilters($action,$filters) + { + if(empty($filters)) + $this->runAction($action); + else + { + $priorAction=$this->_action; + $this->_action=$action; + CFilterChain::create($this,$action,$filters)->run(); + $this->_action=$priorAction; + } + } + public function runAction($action) + { + $priorAction=$this->_action; + $this->_action=$action; + if($this->beforeAction($action)) + { + if($action->runWithParams($this->getActionParams())===false) + $this->invalidActionParams($action); + else + $this->afterAction($action); + } + $this->_action=$priorAction; + } + public function getActionParams() + { + return $_GET; + } + public function invalidActionParams($action) + { + throw new CHttpException(400,Yii::t('yii','Your request is invalid.')); + } + public function processOutput($output) + { + Yii::app()->getClientScript()->render($output); + // if using page caching, we should delay dynamic output replacement + if($this->_dynamicOutput!==null && $this->isCachingStackEmpty()) + { + $output=$this->processDynamicOutput($output); + $this->_dynamicOutput=null; + } + if($this->_pageStates===null) + $this->_pageStates=$this->loadPageStates(); + if(!empty($this->_pageStates)) + $this->savePageStates($this->_pageStates,$output); + return $output; + } + public function processDynamicOutput($output) + { + if($this->_dynamicOutput) + { + $output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output); + } + return $output; + } + protected function replaceDynamicOutput($matches) + { + $content=$matches[0]; + if(isset($this->_dynamicOutput[$matches[1]])) + { + $content=$this->_dynamicOutput[$matches[1]]; + $this->_dynamicOutput[$matches[1]]=null; + } + return $content; + } + public function createAction($actionID) + { + if($actionID==='') + $actionID=$this->defaultAction; + if(method_exists($this,'action'.$actionID) && strcasecmp($actionID,'s')) // we have actions method + return new CInlineAction($this,$actionID); + else + { + $action=$this->createActionFromMap($this->actions(),$actionID,$actionID); + if($action!==null && !method_exists($action,'run')) + throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}'=>get_class($action)))); + return $action; + } + } + protected function createActionFromMap($actionMap,$actionID,$requestActionID,$config=array()) + { + if(($pos=strpos($actionID,'.'))===false && isset($actionMap[$actionID])) + { + $baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID]); + return Yii::createComponent(empty($config)?$baseConfig:array_merge($baseConfig,$config),$this,$requestActionID); + } + else if($pos===false) + return null; + // the action is defined in a provider + $prefix=substr($actionID,0,$pos+1); + if(!isset($actionMap[$prefix])) + return null; + $actionID=(string)substr($actionID,$pos+1); + $provider=$actionMap[$prefix]; + if(is_string($provider)) + $providerType=$provider; + else if(is_array($provider) && isset($provider['class'])) + { + $providerType=$provider['class']; + if(isset($provider[$actionID])) + { + if(is_string($provider[$actionID])) + $config=array_merge(array('class'=>$provider[$actionID]),$config); + else + $config=array_merge($provider[$actionID],$config); + } + } + else + throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.')); + $class=Yii::import($providerType,true); + $map=call_user_func(array($class,'actions')); + return $this->createActionFromMap($map,$actionID,$requestActionID,$config); + } + public function missingAction($actionID) + { + throw new CHttpException(404,Yii::t('yii','The system is unable to find the requested action "{action}".', + array('{action}'=>$actionID==''?$this->defaultAction:$actionID))); + } + public function getAction() + { + return $this->_action; + } + public function setAction($value) + { + $this->_action=$value; + } + public function getId() + { + return $this->_id; + } + public function getUniqueId() + { + return $this->_module ? $this->_module->getId().'/'.$this->_id : $this->_id; + } + public function getRoute() + { + if(($action=$this->getAction())!==null) + return $this->getUniqueId().'/'.$action->getId(); + else + return $this->getUniqueId(); + } + public function getModule() + { + return $this->_module; + } + public function getViewPath() + { + if(($module=$this->getModule())===null) + $module=Yii::app(); + return $module->getViewPath().DIRECTORY_SEPARATOR.$this->getId(); + } + public function getViewFile($viewName) + { + if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false) + return $viewFile; + $moduleViewPath=$basePath=Yii::app()->getViewPath(); + if(($module=$this->getModule())!==null) + $moduleViewPath=$module->getViewPath(); + return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath); + } + public function getLayoutFile($layoutName) + { + if($layoutName===false) + return false; + if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false) + return $layoutFile; + if(empty($layoutName)) + { + $module=$this->getModule(); + while($module!==null) + { + if($module->layout===false) + return false; + if(!empty($module->layout)) + break; + $module=$module->getParentModule(); + } + if($module===null) + $module=Yii::app(); + $layoutName=$module->layout; + } + else if(($module=$this->getModule())===null) + $module=Yii::app(); + return $this->resolveViewFile($layoutName,$module->getLayoutPath(),Yii::app()->getViewPath(),$module->getViewPath()); + } + public function resolveViewFile($viewName,$viewPath,$basePath,$moduleViewPath=null) + { + if(empty($viewName)) + return false; + if($moduleViewPath===null) + $moduleViewPath=$basePath; + if(($renderer=Yii::app()->getViewRenderer())!==null) + $extension=$renderer->fileExtension; + else + $extension='.php'; + if($viewName[0]==='/') + { + if(strncmp($viewName,'//',2)===0) + $viewFile=$basePath.$viewName; + else + $viewFile=$moduleViewPath.$viewName; + } + else if(strpos($viewName,'.')) + $viewFile=Yii::getPathOfAlias($viewName); + else + $viewFile=$viewPath.DIRECTORY_SEPARATOR.$viewName; + if(is_file($viewFile.$extension)) + return Yii::app()->findLocalizedFile($viewFile.$extension); + else if($extension!=='.php' && is_file($viewFile.'.php')) + return Yii::app()->findLocalizedFile($viewFile.'.php'); + else + return false; + } + public function getClips() + { + if($this->_clips!==null) + return $this->_clips; + else + return $this->_clips=new CMap; + } + public function forward($route,$exit=true) + { + if(strpos($route,'/')===false) + $this->run($route); + else + { + if($route[0]!=='/' && ($module=$this->getModule())!==null) + $route=$module->getId().'/'.$route; + Yii::app()->runController($route); + } + if($exit) + Yii::app()->end(); + } + public function render($view,$data=null,$return=false) + { + if($this->beforeRender($view)) + { + $output=$this->renderPartial($view,$data,true); + if(($layoutFile=$this->getLayoutFile($this->layout))!==false) + $output=$this->renderFile($layoutFile,array('content'=>$output),true); + $this->afterRender($view,$output); + $output=$this->processOutput($output); + if($return) + return $output; + else + echo $output; + } + } + protected function beforeRender($view) + { + return true; + } + protected function afterRender($view, &$output) + { + } + public function renderText($text,$return=false) + { + if(($layoutFile=$this->getLayoutFile($this->layout))!==false) + $text=$this->renderFile($layoutFile,array('content'=>$text),true); + $text=$this->processOutput($text); + if($return) + return $text; + else + echo $text; + } + public function renderPartial($view,$data=null,$return=false,$processOutput=false) + { + if(($viewFile=$this->getViewFile($view))!==false) + { + $output=$this->renderFile($viewFile,$data,true); + if($processOutput) + $output=$this->processOutput($output); + if($return) + return $output; + else + echo $output; + } + else + throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".', + array('{controller}'=>get_class($this), '{view}'=>$view))); + } + public function renderClip($name,$params=array(),$return=false) + { + $text=isset($this->clips[$name]) ? strtr($this->clips[$name], $params) : ''; + if($return) + return $text; + else + echo $text; + } + public function renderDynamic($callback) + { + $n=count($this->_dynamicOutput); + echo "<###dynamic-$n###>"; + $params=func_get_args(); + array_shift($params); + $this->renderDynamicInternal($callback,$params); + } + public function renderDynamicInternal($callback,$params) + { + $this->recordCachingAction('','renderDynamicInternal',array($callback,$params)); + if(is_string($callback) && method_exists($this,$callback)) + $callback=array($this,$callback); + $this->_dynamicOutput[]=call_user_func_array($callback,$params); + } + public function createUrl($route,$params=array(),$ampersand='&') + { + if($route==='') + $route=$this->getId().'/'.$this->getAction()->getId(); + else if(strpos($route,'/')===false) + $route=$this->getId().'/'.$route; + if($route[0]!=='/' && ($module=$this->getModule())!==null) + $route=$module->getId().'/'.$route; + return Yii::app()->createUrl(trim($route,'/'),$params,$ampersand); + } + public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&') + { + $url=$this->createUrl($route,$params,$ampersand); + if(strpos($url,'http')===0) + return $url; + else + return Yii::app()->getRequest()->getHostInfo($schema).$url; + } + public function getPageTitle() + { + if($this->_pageTitle!==null) + return $this->_pageTitle; + else + { + $name=ucfirst(basename($this->getId())); + if($this->getAction()!==null && strcasecmp($this->getAction()->getId(),$this->defaultAction)) + return $this->_pageTitle=Yii::app()->name.' - '.ucfirst($this->getAction()->getId()).' '.$name; + else + return $this->_pageTitle=Yii::app()->name.' - '.$name; + } + } + public function setPageTitle($value) + { + $this->_pageTitle=$value; + } + public function redirect($url,$terminate=true,$statusCode=302) + { + if(is_array($url)) + { + $route=isset($url[0]) ? $url[0] : ''; + $url=$this->createUrl($route,array_splice($url,1)); + } + Yii::app()->getRequest()->redirect($url,$terminate,$statusCode); + } + public function refresh($terminate=true,$anchor='') + { + $this->redirect(Yii::app()->getRequest()->getUrl().$anchor,$terminate); + } + public function recordCachingAction($context,$method,$params) + { + if($this->_cachingStack) // record only when there is an active output cache + { + foreach($this->_cachingStack as $cache) + $cache->recordAction($context,$method,$params); + } + } + public function getCachingStack($createIfNull=true) + { + if(!$this->_cachingStack) + $this->_cachingStack=new CStack; + return $this->_cachingStack; + } + public function isCachingStackEmpty() + { + return $this->_cachingStack===null || !$this->_cachingStack->getCount(); + } + protected function beforeAction($action) + { + return true; + } + protected function afterAction($action) + { + } + public function filterPostOnly($filterChain) + { + if(Yii::app()->getRequest()->getIsPostRequest()) + $filterChain->run(); + else + throw new CHttpException(400,Yii::t('yii','Your request is invalid.')); + } + public function filterAjaxOnly($filterChain) + { + if(Yii::app()->getRequest()->getIsAjaxRequest()) + $filterChain->run(); + else + throw new CHttpException(400,Yii::t('yii','Your request is invalid.')); + } + public function filterAccessControl($filterChain) + { + $filter=new CAccessControlFilter; + $filter->setRules($this->accessRules()); + $filter->filter($filterChain); + } + public function getPageState($name,$defaultValue=null) + { + if($this->_pageStates===null) + $this->_pageStates=$this->loadPageStates(); + return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue; + } + public function setPageState($name,$value,$defaultValue=null) + { + if($this->_pageStates===null) + $this->_pageStates=$this->loadPageStates(); + if($value===$defaultValue) + unset($this->_pageStates[$name]); + else + $this->_pageStates[$name]=$value; + $params=func_get_args(); + $this->recordCachingAction('','setPageState',$params); + } + public function clearPageStates() + { + $this->_pageStates=array(); + } + protected function loadPageStates() + { + if(!empty($_POST[self::STATE_INPUT_NAME])) + { + if(($data=base64_decode($_POST[self::STATE_INPUT_NAME]))!==false) + { + if(extension_loaded('zlib')) + $data=@gzuncompress($data); + if(($data=Yii::app()->getSecurityManager()->validateData($data))!==false) + return unserialize($data); + } + } + return array(); + } + protected function savePageStates($states,&$output) + { + $data=Yii::app()->getSecurityManager()->hashData(serialize($states)); + if(extension_loaded('zlib')) + $data=gzcompress($data); + $value=base64_encode($data); + $output=str_replace(CHtml::pageStateField(''),CHtml::pageStateField($value),$output); + } +} +abstract class CAction extends CComponent implements IAction +{ + private $_id; + private $_controller; + public function __construct($controller,$id) + { + $this->_controller=$controller; + $this->_id=$id; + } + public function getController() + { + return $this->_controller; + } + public function getId() + { + return $this->_id; + } + public function runWithParams($params) + { + $method=new ReflectionMethod($this, 'run'); + if($method->getNumberOfParameters()>0) + return $this->runWithParamsInternal($this, $method, $params); + else + return $this->run(); + } + protected function runWithParamsInternal($object, $method, $params) + { + $ps=array(); + foreach($method->getParameters() as $i=>$param) + { + $name=$param->getName(); + if(isset($params[$name])) + { + if($param->isArray()) + $ps[]=is_array($params[$name]) ? $params[$name] : array($params[$name]); + else if(!is_array($params[$name])) + $ps[]=$params[$name]; + else + return false; + } + else if($param->isDefaultValueAvailable()) + $ps[]=$param->getDefaultValue(); + else + return false; + } + $method->invokeArgs($object,$ps); + return true; + } +} +class CInlineAction extends CAction +{ + public function run() + { + $method='action'.$this->getId(); + $this->getController()->$method(); + } + public function runWithParams($params) + { + $methodName='action'.$this->getId(); + $controller=$this->getController(); + $method=new ReflectionMethod($controller, $methodName); + if($method->getNumberOfParameters()>0) + return $this->runWithParamsInternal($controller, $method, $params); + else + return $controller->$methodName(); + } +} +class CWebUser extends CApplicationComponent implements IWebUser +{ + const FLASH_KEY_PREFIX='Yii.CWebUser.flash.'; + const FLASH_COUNTERS='Yii.CWebUser.flashcounters'; + const STATES_VAR='__states'; + const AUTH_TIMEOUT_VAR='__timeout'; + public $allowAutoLogin=false; + public $guestName='Guest'; + public $loginUrl=array('/site/login'); + public $identityCookie; + public $authTimeout; + public $autoRenewCookie=false; + public $autoUpdateFlash=true; + public $loginRequiredAjaxResponse; + private $_keyPrefix; + private $_access=array(); + public function __get($name) + { + if($this->hasState($name)) + return $this->getState($name); + else + return parent::__get($name); + } + public function __set($name,$value) + { + if($this->hasState($name)) + $this->setState($name,$value); + else + parent::__set($name,$value); + } + public function __isset($name) + { + if($this->hasState($name)) + return $this->getState($name)!==null; + else + return parent::__isset($name); + } + public function __unset($name) + { + if($this->hasState($name)) + $this->setState($name,null); + else + parent::__unset($name); + } + public function init() + { + parent::init(); + Yii::app()->getSession()->open(); + if($this->getIsGuest() && $this->allowAutoLogin) + $this->restoreFromCookie(); + else if($this->autoRenewCookie && $this->allowAutoLogin) + $this->renewCookie(); + if($this->autoUpdateFlash) + $this->updateFlash(); + $this->updateAuthStatus(); + } + public function login($identity,$duration=0) + { + $id=$identity->getId(); + $states=$identity->getPersistentStates(); + if($this->beforeLogin($id,$states,false)) + { + $this->changeIdentity($id,$identity->getName(),$states); + if($duration>0) + { + if($this->allowAutoLogin) + $this->saveToCookie($duration); + else + throw new CException(Yii::t('yii','{class}.allowAutoLogin must be set true in order to use cookie-based authentication.', + array('{class}'=>get_class($this)))); + } + $this->afterLogin(false); + } + return !$this->getIsGuest(); + } + public function logout($destroySession=true) + { + if($this->beforeLogout()) + { + if($this->allowAutoLogin) + { + Yii::app()->getRequest()->getCookies()->remove($this->getStateKeyPrefix()); + if($this->identityCookie!==null) + { + $cookie=$this->createIdentityCookie($this->getStateKeyPrefix()); + $cookie->value=null; + $cookie->expire=0; + Yii::app()->getRequest()->getCookies()->add($cookie->name,$cookie); + } + } + if($destroySession) + Yii::app()->getSession()->destroy(); + else + $this->clearStates(); + $this->afterLogout(); + } + } + public function getIsGuest() + { + return $this->getState('__id')===null; + } + public function getId() + { + return $this->getState('__id'); + } + public function setId($value) + { + $this->setState('__id',$value); + } + public function getName() + { + if(($name=$this->getState('__name'))!==null) + return $name; + else + return $this->guestName; + } + public function setName($value) + { + $this->setState('__name',$value); + } + public function getReturnUrl($defaultUrl=null) + { + return $this->getState('__returnUrl', $defaultUrl===null ? Yii::app()->getRequest()->getScriptUrl() : CHtml::normalizeUrl($defaultUrl)); + } + public function setReturnUrl($value) + { + $this->setState('__returnUrl',$value); + } + public function loginRequired() + { + $app=Yii::app(); + $request=$app->getRequest(); + if(!$request->getIsAjaxRequest()) + $this->setReturnUrl($request->getUrl()); + elseif(isset($this->loginRequiredAjaxResponse)) + { + echo $this->loginRequiredAjaxResponse; + Yii::app()->end(); + } + if(($url=$this->loginUrl)!==null) + { + if(is_array($url)) + { + $route=isset($url[0]) ? $url[0] : $app->defaultController; + $url=$app->createUrl($route,array_splice($url,1)); + } + $request->redirect($url); + } + else + throw new CHttpException(403,Yii::t('yii','Login Required')); + } + protected function beforeLogin($id,$states,$fromCookie) + { + return true; + } + protected function afterLogin($fromCookie) + { + } + protected function beforeLogout() + { + return true; + } + protected function afterLogout() + { + } + protected function restoreFromCookie() + { + $app=Yii::app(); + $request=$app->getRequest(); + $cookie=$request->getCookies()->itemAt($this->getStateKeyPrefix()); + if($cookie && !empty($cookie->value) && ($data=$app->getSecurityManager()->validateData($cookie->value))!==false) + { + $data=@unserialize($data); + if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3])) + { + list($id,$name,$duration,$states)=$data; + if($this->beforeLogin($id,$states,true)) + { + $this->changeIdentity($id,$name,$states); + if($this->autoRenewCookie) + { + $cookie->expire=time()+$duration; + $request->getCookies()->add($cookie->name,$cookie); + } + $this->afterLogin(true); + } + } + } + } + protected function renewCookie() + { + $request=Yii::app()->getRequest(); + $cookies=$request->getCookies(); + $cookie=$cookies->itemAt($this->getStateKeyPrefix()); + if($cookie && !empty($cookie->value) && ($data=Yii::app()->getSecurityManager()->validateData($cookie->value))!==false) + { + $data=@unserialize($data); + if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3])) + { + $cookie->expire=time()+$data[2]; + $cookies->add($cookie->name,$cookie); + } + } + } + protected function saveToCookie($duration) + { + $app=Yii::app(); + $cookie=$this->createIdentityCookie($this->getStateKeyPrefix()); + $cookie->expire=time()+$duration; + $data=array( + $this->getId(), + $this->getName(), + $duration, + $this->saveIdentityStates(), + ); + $cookie->value=$app->getSecurityManager()->hashData(serialize($data)); + $app->getRequest()->getCookies()->add($cookie->name,$cookie); + } + protected function createIdentityCookie($name) + { + $cookie=new CHttpCookie($name,''); + if(is_array($this->identityCookie)) + { + foreach($this->identityCookie as $name=>$value) + $cookie->$name=$value; + } + return $cookie; + } + public function getStateKeyPrefix() + { + if($this->_keyPrefix!==null) + return $this->_keyPrefix; + else + return $this->_keyPrefix=md5('Yii.'.get_class($this).'.'.Yii::app()->getId()); + } + public function setStateKeyPrefix($value) + { + $this->_keyPrefix=$value; + } + public function getState($key,$defaultValue=null) + { + $key=$this->getStateKeyPrefix().$key; + return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue; + } + public function setState($key,$value,$defaultValue=null) + { + $key=$this->getStateKeyPrefix().$key; + if($value===$defaultValue) + unset($_SESSION[$key]); + else + $_SESSION[$key]=$value; + } + public function hasState($key) + { + $key=$this->getStateKeyPrefix().$key; + return isset($_SESSION[$key]); + } + public function clearStates() + { + $keys=array_keys($_SESSION); + $prefix=$this->getStateKeyPrefix(); + $n=strlen($prefix); + foreach($keys as $key) + { + if(!strncmp($key,$prefix,$n)) + unset($_SESSION[$key]); + } + } + public function getFlashes($delete=true) + { + $flashes=array(); + $prefix=$this->getStateKeyPrefix().self::FLASH_KEY_PREFIX; + $keys=array_keys($_SESSION); + $n=strlen($prefix); + foreach($keys as $key) + { + if(!strncmp($key,$prefix,$n)) + { + $flashes[substr($key,$n)]=$_SESSION[$key]; + if($delete) + unset($_SESSION[$key]); + } + } + if($delete) + $this->setState(self::FLASH_COUNTERS,array()); + return $flashes; + } + public function getFlash($key,$defaultValue=null,$delete=true) + { + $value=$this->getState(self::FLASH_KEY_PREFIX.$key,$defaultValue); + if($delete) + $this->setFlash($key,null); + return $value; + } + public function setFlash($key,$value,$defaultValue=null) + { + $this->setState(self::FLASH_KEY_PREFIX.$key,$value,$defaultValue); + $counters=$this->getState(self::FLASH_COUNTERS,array()); + if($value===$defaultValue) + unset($counters[$key]); + else + $counters[$key]=0; + $this->setState(self::FLASH_COUNTERS,$counters,array()); + } + public function hasFlash($key) + { + return $this->getFlash($key, null, false)!==null; + } + protected function changeIdentity($id,$name,$states) + { + Yii::app()->getSession()->regenerateID(); + $this->setId($id); + $this->setName($name); + $this->loadIdentityStates($states); + } + protected function saveIdentityStates() + { + $states=array(); + foreach($this->getState(self::STATES_VAR,array()) as $name=>$dummy) + $states[$name]=$this->getState($name); + return $states; + } + protected function loadIdentityStates($states) + { + $names=array(); + if(is_array($states)) + { + foreach($states as $name=>$value) + { + $this->setState($name,$value); + $names[$name]=true; + } + } + $this->setState(self::STATES_VAR,$names); + } + protected function updateFlash() + { + $counters=$this->getState(self::FLASH_COUNTERS); + if(!is_array($counters)) + return; + foreach($counters as $key=>$count) + { + if($count) + { + unset($counters[$key]); + $this->setState(self::FLASH_KEY_PREFIX.$key,null); + } + else + $counters[$key]++; + } + $this->setState(self::FLASH_COUNTERS,$counters,array()); + } + protected function updateAuthStatus() + { + if($this->authTimeout!==null && !$this->getIsGuest()) + { + $expires=$this->getState(self::AUTH_TIMEOUT_VAR); + if ($expires!==null && $expires < time()) + $this->logout(false); + else + $this->setState(self::AUTH_TIMEOUT_VAR,time()+$this->authTimeout); + } + } + public function checkAccess($operation,$params=array(),$allowCaching=true) + { + if($allowCaching && $params===array() && isset($this->_access[$operation])) + return $this->_access[$operation]; + else + return $this->_access[$operation]=Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params); + } +} +class CHttpSession extends CApplicationComponent implements IteratorAggregate,ArrayAccess,Countable +{ + public $autoStart=true; + public function init() + { + parent::init(); + if($this->autoStart) + $this->open(); + register_shutdown_function(array($this,'close')); + } + public function getUseCustomStorage() + { + return false; + } + public function open() + { + if($this->getUseCustomStorage()) + @session_set_save_handler(array($this,'openSession'),array($this,'closeSession'),array($this,'readSession'),array($this,'writeSession'),array($this,'destroySession'),array($this,'gcSession')); + @session_start(); + if(YII_DEBUG && session_id()=='') + { + $message=Yii::t('yii','Failed to start session.'); + if(function_exists('error_get_last')) + { + $error=error_get_last(); + if(isset($error['message'])) + $message=$error['message']; + } + Yii::log($message, CLogger::LEVEL_WARNING, 'system.web.CHttpSession'); + } + } + public function close() + { + if(session_id()!=='') + @session_write_close(); + } + public function destroy() + { + if(session_id()!=='') + { + @session_unset(); + @session_destroy(); + } + } + public function getIsStarted() + { + return session_id()!==''; + } + public function getSessionID() + { + return session_id(); + } + public function setSessionID($value) + { + session_id($value); + } + public function regenerateID($deleteOldSession=false) + { + session_regenerate_id($deleteOldSession); + } + public function getSessionName() + { + return session_name(); + } + public function setSessionName($value) + { + session_name($value); + } + public function getSavePath() + { + return session_save_path(); + } + public function setSavePath($value) + { + if(is_dir($value)) + session_save_path($value); + else + throw new CException(Yii::t('yii','CHttpSession.savePath "{path}" is not a valid directory.', + array('{path}'=>$value))); + } + public function getCookieParams() + { + return session_get_cookie_params(); + } + public function setCookieParams($value) + { + $data=session_get_cookie_params(); + extract($data); + extract($value); + if(isset($httponly)) + session_set_cookie_params($lifetime,$path,$domain,$secure,$httponly); + else + session_set_cookie_params($lifetime,$path,$domain,$secure); + } + public function getCookieMode() + { + if(ini_get('session.use_cookies')==='0') + return 'none'; + else if(ini_get('session.use_only_cookies')==='0') + return 'allow'; + else + return 'only'; + } + public function setCookieMode($value) + { + if($value==='none') + { + ini_set('session.use_cookies','0'); + ini_set('session.use_only_cookies','0'); + } + else if($value==='allow') + { + ini_set('session.use_cookies','1'); + ini_set('session.use_only_cookies','0'); + } + else if($value==='only') + { + ini_set('session.use_cookies','1'); + ini_set('session.use_only_cookies','1'); + } + else + throw new CException(Yii::t('yii','CHttpSession.cookieMode can only be "none", "allow" or "only".')); + } + public function getGCProbability() + { + return (int)ini_get('session.gc_probability'); + } + public function setGCProbability($value) + { + $value=(int)$value; + if($value>=0 && $value<=100) + { + ini_set('session.gc_probability',$value); + ini_set('session.gc_divisor','100'); + } + else + throw new CException(Yii::t('yii','CHttpSession.gcProbability "{value}" is invalid. It must be an integer between 0 and 100.', + array('{value}'=>$value))); + } + public function getUseTransparentSessionID() + { + return ini_get('session.use_trans_sid')==1; + } + public function setUseTransparentSessionID($value) + { + ini_set('session.use_trans_sid',$value?'1':'0'); + } + public function getTimeout() + { + return (int)ini_get('session.gc_maxlifetime'); + } + public function setTimeout($value) + { + ini_set('session.gc_maxlifetime',$value); + } + public function openSession($savePath,$sessionName) + { + return true; + } + public function closeSession() + { + return true; + } + public function readSession($id) + { + return ''; + } + public function writeSession($id,$data) + { + return true; + } + public function destroySession($id) + { + return true; + } + public function gcSession($maxLifetime) + { + return true; + } + //------ The following methods enable CHttpSession to be CMap-like ----- + public function getIterator() + { + return new CHttpSessionIterator; + } + public function getCount() + { + return count($_SESSION); + } + public function count() + { + return $this->getCount(); + } + public function getKeys() + { + return array_keys($_SESSION); + } + public function get($key,$defaultValue=null) + { + return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue; + } + public function itemAt($key) + { + return isset($_SESSION[$key]) ? $_SESSION[$key] : null; + } + public function add($key,$value) + { + $_SESSION[$key]=$value; + } + public function remove($key) + { + if(isset($_SESSION[$key])) + { + $value=$_SESSION[$key]; + unset($_SESSION[$key]); + return $value; + } + else + return null; + } + public function clear() + { + foreach(array_keys($_SESSION) as $key) + unset($_SESSION[$key]); + } + public function contains($key) + { + return isset($_SESSION[$key]); + } + public function toArray() + { + return $_SESSION; + } + public function offsetExists($offset) + { + return isset($_SESSION[$offset]); + } + public function offsetGet($offset) + { + return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null; + } + public function offsetSet($offset,$item) + { + $_SESSION[$offset]=$item; + } + public function offsetUnset($offset) + { + unset($_SESSION[$offset]); + } +} +class CHtml +{ + const ID_PREFIX='yt'; + public static $errorSummaryCss='errorSummary'; + public static $errorMessageCss='errorMessage'; + public static $errorCss='error'; + public static $requiredCss='required'; + public static $beforeRequiredLabel=''; + public static $afterRequiredLabel=' <span class="required">*</span>'; + public static $count=0; + public static $liveEvents = true; + public static function encode($text) + { + return htmlspecialchars($text,ENT_QUOTES,Yii::app()->charset); + } + public static function decode($text) + { + return htmlspecialchars_decode($text,ENT_QUOTES); + } + public static function encodeArray($data) + { + $d=array(); + foreach($data as $key=>$value) + { + if(is_string($key)) + $key=htmlspecialchars($key,ENT_QUOTES,Yii::app()->charset); + if(is_string($value)) + $value=htmlspecialchars($value,ENT_QUOTES,Yii::app()->charset); + else if(is_array($value)) + $value=self::encodeArray($value); + $d[$key]=$value; + } + return $d; + } + public static function tag($tag,$htmlOptions=array(),$content=false,$closeTag=true) + { + $html='<' . $tag . self::renderAttributes($htmlOptions); + if($content===false) + return $closeTag ? $html.' />' : $html.'>'; + else + return $closeTag ? $html.'>'.$content.'</'.$tag.'>' : $html.'>'.$content; + } + public static function openTag($tag,$htmlOptions=array()) + { + return '<' . $tag . self::renderAttributes($htmlOptions) . '>'; + } + public static function closeTag($tag) + { + return '</'.$tag.'>'; + } + public static function cdata($text) + { + return '<![CDATA[' . $text . ']]>'; + } + public static function metaTag($content,$name=null,$httpEquiv=null,$options=array()) + { + if($name!==null) + $options['name']=$name; + if($httpEquiv!==null) + $options['http-equiv']=$httpEquiv; + $options['content']=$content; + return self::tag('meta',$options); + } + public static function linkTag($relation=null,$type=null,$href=null,$media=null,$options=array()) + { + if($relation!==null) + $options['rel']=$relation; + if($type!==null) + $options['type']=$type; + if($href!==null) + $options['href']=$href; + if($media!==null) + $options['media']=$media; + return self::tag('link',$options); + } + public static function css($text,$media='') + { + if($media!=='') + $media=' media="'.$media.'"'; + return "<style type=\"text/css\"{$media}>\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</style>"; + } + public static function refresh($seconds, $url='') + { + $content="$seconds"; + if($url!=='') + $content.=';'.self::normalizeUrl($url); + Yii::app()->clientScript->registerMetaTag($content,null,'refresh'); + } + public static function cssFile($url,$media='') + { + if($media!=='') + $media=' media="'.$media.'"'; + return '<link rel="stylesheet" type="text/css" href="'.self::encode($url).'"'.$media.' />'; + } + public static function script($text) + { + return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</script>"; + } + public static function scriptFile($url) + { + return '<script type="text/javascript" src="'.self::encode($url).'"></script>'; + } + public static function form($action='',$method='post',$htmlOptions=array()) + { + return self::beginForm($action,$method,$htmlOptions); + } + public static function beginForm($action='',$method='post',$htmlOptions=array()) + { + $htmlOptions['action']=$url=self::normalizeUrl($action); + $htmlOptions['method']=$method; + $form=self::tag('form',$htmlOptions,false,false); + $hiddens=array(); + if(!strcasecmp($method,'get') && ($pos=strpos($url,'?'))!==false) + { + foreach(explode('&',substr($url,$pos+1)) as $pair) + { + if(($pos=strpos($pair,'='))!==false) + $hiddens[]=self::hiddenField(urldecode(substr($pair,0,$pos)),urldecode(substr($pair,$pos+1)),array('id'=>false)); + } + } + $request=Yii::app()->request; + if($request->enableCsrfValidation && !strcasecmp($method,'post')) + $hiddens[]=self::hiddenField($request->csrfTokenName,$request->getCsrfToken(),array('id'=>false)); + if($hiddens!==array()) + $form.="\n".self::tag('div',array('style'=>'display:none'),implode("\n",$hiddens)); + return $form; + } + public static function endForm() + { + return '</form>'; + } + public static function statefulForm($action='',$method='post',$htmlOptions=array()) + { + return self::form($action,$method,$htmlOptions)."\n". + self::tag('div',array('style'=>'display:none'),self::pageStateField('')); + } + public static function pageStateField($value) + { + return '<input type="hidden" name="'.CController::STATE_INPUT_NAME.'" value="'.$value.'" />'; + } + public static function link($text,$url='#',$htmlOptions=array()) + { + if($url!=='') + $htmlOptions['href']=self::normalizeUrl($url); + self::clientChange('click',$htmlOptions); + return self::tag('a',$htmlOptions,$text); + } + public static function mailto($text,$email='',$htmlOptions=array()) + { + if($email==='') + $email=$text; + return self::link($text,'mailto:'.$email,$htmlOptions); + } + public static function image($src,$alt='',$htmlOptions=array()) + { + $htmlOptions['src']=$src; + $htmlOptions['alt']=$alt; + return self::tag('img',$htmlOptions); + } + public static function button($label='button',$htmlOptions=array()) + { + if(!isset($htmlOptions['name'])) + { + if(!array_key_exists('name',$htmlOptions)) + $htmlOptions['name']=self::ID_PREFIX.self::$count++; + } + if(!isset($htmlOptions['type'])) + $htmlOptions['type']='button'; + if(!isset($htmlOptions['value'])) + $htmlOptions['value']=$label; + self::clientChange('click',$htmlOptions); + return self::tag('input',$htmlOptions); + } + public static function htmlButton($label='button',$htmlOptions=array()) + { + if(!isset($htmlOptions['name'])) + $htmlOptions['name']=self::ID_PREFIX.self::$count++; + if(!isset($htmlOptions['type'])) + $htmlOptions['type']='button'; + self::clientChange('click',$htmlOptions); + return self::tag('button',$htmlOptions,$label); + } + public static function submitButton($label='submit',$htmlOptions=array()) + { + $htmlOptions['type']='submit'; + return self::button($label,$htmlOptions); + } + public static function resetButton($label='reset',$htmlOptions=array()) + { + $htmlOptions['type']='reset'; + return self::button($label,$htmlOptions); + } + public static function imageButton($src,$htmlOptions=array()) + { + $htmlOptions['src']=$src; + $htmlOptions['type']='image'; + return self::button('submit',$htmlOptions); + } + public static function linkButton($label='submit',$htmlOptions=array()) + { + if(!isset($htmlOptions['submit'])) + $htmlOptions['submit']=isset($htmlOptions['href']) ? $htmlOptions['href'] : ''; + return self::link($label,'#',$htmlOptions); + } + public static function label($label,$for,$htmlOptions=array()) + { + if($for===false) + unset($htmlOptions['for']); + else + $htmlOptions['for']=$for; + if(isset($htmlOptions['required'])) + { + if($htmlOptions['required']) + { + if(isset($htmlOptions['class'])) + $htmlOptions['class'].=' '.self::$requiredCss; + else + $htmlOptions['class']=self::$requiredCss; + $label=self::$beforeRequiredLabel.$label.self::$afterRequiredLabel; + } + unset($htmlOptions['required']); + } + return self::tag('label',$htmlOptions,$label); + } + public static function textField($name,$value='',$htmlOptions=array()) + { + self::clientChange('change',$htmlOptions); + return self::inputField('text',$name,$value,$htmlOptions); + } + public static function hiddenField($name,$value='',$htmlOptions=array()) + { + return self::inputField('hidden',$name,$value,$htmlOptions); + } + public static function passwordField($name,$value='',$htmlOptions=array()) + { + self::clientChange('change',$htmlOptions); + return self::inputField('password',$name,$value,$htmlOptions); + } + public static function fileField($name,$value='',$htmlOptions=array()) + { + return self::inputField('file',$name,$value,$htmlOptions); + } + public static function textArea($name,$value='',$htmlOptions=array()) + { + $htmlOptions['name']=$name; + if(!isset($htmlOptions['id'])) + $htmlOptions['id']=self::getIdByName($name); + else if($htmlOptions['id']===false) + unset($htmlOptions['id']); + self::clientChange('change',$htmlOptions); + return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value)); + } + public static function radioButton($name,$checked=false,$htmlOptions=array()) + { + if($checked) + $htmlOptions['checked']='checked'; + else + unset($htmlOptions['checked']); + $value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1; + self::clientChange('click',$htmlOptions); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck=null; + if($uncheck!==null) + { + // add a hidden field so that if the radio button is not selected, it still submits a value + if(isset($htmlOptions['id']) && $htmlOptions['id']!==false) + $uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']); + else + $uncheckOptions=array('id'=>false); + $hidden=self::hiddenField($name,$uncheck,$uncheckOptions); + } + else + $hidden=''; + // add a hidden field so that if the radio button is not selected, it still submits a value + return $hidden . self::inputField('radio',$name,$value,$htmlOptions); + } + public static function checkBox($name,$checked=false,$htmlOptions=array()) + { + if($checked) + $htmlOptions['checked']='checked'; + else + unset($htmlOptions['checked']); + $value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1; + self::clientChange('click',$htmlOptions); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck=null; + if($uncheck!==null) + { + // add a hidden field so that if the radio button is not selected, it still submits a value + if(isset($htmlOptions['id']) && $htmlOptions['id']!==false) + $uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']); + else + $uncheckOptions=array('id'=>false); + $hidden=self::hiddenField($name,$uncheck,$uncheckOptions); + } + else + $hidden=''; + // add a hidden field so that if the checkbox is not selected, it still submits a value + return $hidden . self::inputField('checkbox',$name,$value,$htmlOptions); + } + public static function dropDownList($name,$select,$data,$htmlOptions=array()) + { + $htmlOptions['name']=$name; + if(!isset($htmlOptions['id'])) + $htmlOptions['id']=self::getIdByName($name); + else if($htmlOptions['id']===false) + unset($htmlOptions['id']); + self::clientChange('change',$htmlOptions); + $options="\n".self::listOptions($select,$data,$htmlOptions); + return self::tag('select',$htmlOptions,$options); + } + public static function listBox($name,$select,$data,$htmlOptions=array()) + { + if(!isset($htmlOptions['size'])) + $htmlOptions['size']=4; + if(isset($htmlOptions['multiple'])) + { + if(substr($name,-2)!=='[]') + $name.='[]'; + } + return self::dropDownList($name,$select,$data,$htmlOptions); + } + public static function checkBoxList($name,$select,$data,$htmlOptions=array()) + { + $template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}'; + $separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n"; + unset($htmlOptions['template'],$htmlOptions['separator']); + if(substr($name,-2)!=='[]') + $name.='[]'; + if(isset($htmlOptions['checkAll'])) + { + $checkAllLabel=$htmlOptions['checkAll']; + $checkAllLast=isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast']; + } + unset($htmlOptions['checkAll'],$htmlOptions['checkAllLast']); + $labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array(); + unset($htmlOptions['labelOptions']); + $items=array(); + $baseID=self::getIdByName($name); + $id=0; + $checkAll=true; + foreach($data as $value=>$label) + { + $checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select); + $checkAll=$checkAll && $checked; + $htmlOptions['value']=$value; + $htmlOptions['id']=$baseID.'_'.$id++; + $option=self::checkBox($name,$checked,$htmlOptions); + $label=self::label($label,$htmlOptions['id'],$labelOptions); + $items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label)); + } + if(isset($checkAllLabel)) + { + $htmlOptions['value']=1; + $htmlOptions['id']=$id=$baseID.'_all'; + $option=self::checkBox($id,$checkAll,$htmlOptions); + $label=self::label($checkAllLabel,$id,$labelOptions); + $item=strtr($template,array('{input}'=>$option,'{label}'=>$label)); + if($checkAllLast) + $items[]=$item; + else + array_unshift($items,$item); + $name=strtr($name,array('['=>'\\[',']'=>'\\]')); + $js=<<<EOD +$('#$id').click(function() { + $("input[name='$name']").prop('checked', this.checked); +}); +$("input[name='$name']").click(function() { + $('#$id').prop('checked', !$("input[name='$name']:not(:checked)").length); +}); +$('#$id').prop('checked', !$("input[name='$name']:not(:checked)").length); +EOD; + $cs=Yii::app()->getClientScript(); + $cs->registerCoreScript('jquery'); + $cs->registerScript($id,$js); + } + return self::tag('span',array('id'=>$baseID),implode($separator,$items)); + } + public static function radioButtonList($name,$select,$data,$htmlOptions=array()) + { + $template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}'; + $separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n"; + unset($htmlOptions['template'],$htmlOptions['separator']); + $labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array(); + unset($htmlOptions['labelOptions']); + $items=array(); + $baseID=self::getIdByName($name); + $id=0; + foreach($data as $value=>$label) + { + $checked=!strcmp($value,$select); + $htmlOptions['value']=$value; + $htmlOptions['id']=$baseID.'_'.$id++; + $option=self::radioButton($name,$checked,$htmlOptions); + $label=self::label($label,$htmlOptions['id'],$labelOptions); + $items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label)); + } + return self::tag('span',array('id'=>$baseID),implode($separator,$items)); + } + public static function ajaxLink($text,$url,$ajaxOptions=array(),$htmlOptions=array()) + { + if(!isset($htmlOptions['href'])) + $htmlOptions['href']='#'; + $ajaxOptions['url']=$url; + $htmlOptions['ajax']=$ajaxOptions; + self::clientChange('click',$htmlOptions); + return self::tag('a',$htmlOptions,$text); + } + public static function ajaxButton($label,$url,$ajaxOptions=array(),$htmlOptions=array()) + { + $ajaxOptions['url']=$url; + $htmlOptions['ajax']=$ajaxOptions; + return self::button($label,$htmlOptions); + } + public static function ajaxSubmitButton($label,$url,$ajaxOptions=array(),$htmlOptions=array()) + { + $ajaxOptions['type']='POST'; + $htmlOptions['type']='submit'; + return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions); + } + public static function ajax($options) + { + Yii::app()->getClientScript()->registerCoreScript('jquery'); + if(!isset($options['url'])) + $options['url']='js:location.href'; + else + $options['url']=self::normalizeUrl($options['url']); + if(!isset($options['cache'])) + $options['cache']=false; + if(!isset($options['data']) && isset($options['type'])) + $options['data']='js:jQuery(this).parents("form").serialize()'; + foreach(array('beforeSend','complete','error','success') as $name) + { + if(isset($options[$name]) && strpos($options[$name],'js:')!==0) + $options[$name]='js:'.$options[$name]; + } + if(isset($options['update'])) + { + if(!isset($options['success'])) + $options['success']='js:function(html){jQuery("'.$options['update'].'").html(html)}'; + unset($options['update']); + } + if(isset($options['replace'])) + { + if(!isset($options['success'])) + $options['success']='js:function(html){jQuery("'.$options['replace'].'").replaceWith(html)}'; + unset($options['replace']); + } + return 'jQuery.ajax('.CJavaScript::encode($options).');'; + } + public static function asset($path,$hashByName=false) + { + return Yii::app()->getAssetManager()->publish($path,$hashByName); + } + public static function normalizeUrl($url) + { + if(is_array($url)) + { + if(isset($url[0])) + { + if(($c=Yii::app()->getController())!==null) + $url=$c->createUrl($url[0],array_splice($url,1)); + else + $url=Yii::app()->createUrl($url[0],array_splice($url,1)); + } + else + $url=''; + } + return $url==='' ? Yii::app()->getRequest()->getUrl() : $url; + } + protected static function inputField($type,$name,$value,$htmlOptions) + { + $htmlOptions['type']=$type; + $htmlOptions['value']=$value; + $htmlOptions['name']=$name; + if(!isset($htmlOptions['id'])) + $htmlOptions['id']=self::getIdByName($name); + else if($htmlOptions['id']===false) + unset($htmlOptions['id']); + return self::tag('input',$htmlOptions); + } + public static function activeLabel($model,$attribute,$htmlOptions=array()) + { + if(isset($htmlOptions['for'])) + { + $for=$htmlOptions['for']; + unset($htmlOptions['for']); + } + else + $for=self::getIdByName(self::resolveName($model,$attribute)); + if(isset($htmlOptions['label'])) + { + if(($label=$htmlOptions['label'])===false) + return ''; + unset($htmlOptions['label']); + } + else + $label=$model->getAttributeLabel($attribute); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + return self::label($label,$for,$htmlOptions); + } + public static function activeLabelEx($model,$attribute,$htmlOptions=array()) + { + $realAttribute=$attribute; + self::resolveName($model,$attribute); // strip off square brackets if any + $htmlOptions['required']=$model->isAttributeRequired($attribute); + return self::activeLabel($model,$realAttribute,$htmlOptions); + } + public static function activeTextField($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + self::clientChange('change',$htmlOptions); + return self::activeInputField('text',$model,$attribute,$htmlOptions); + } + public static function activeHiddenField($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + return self::activeInputField('hidden',$model,$attribute,$htmlOptions); + } + public static function activePasswordField($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + self::clientChange('change',$htmlOptions); + return self::activeInputField('password',$model,$attribute,$htmlOptions); + } + public static function activeTextArea($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + self::clientChange('change',$htmlOptions); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + $text=self::resolveValue($model,$attribute); + return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $text : self::encode($text)); + } + public static function activeFileField($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + // add a hidden field so that if a model only has a file field, we can + // still use isset($_POST[$modelClass]) to detect if the input is submitted + $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false); + return self::hiddenField($htmlOptions['name'],'',$hiddenOptions) + . self::activeInputField('file',$model,$attribute,$htmlOptions); + } + public static function activeRadioButton($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + if(!isset($htmlOptions['value'])) + $htmlOptions['value']=1; + if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value']) + $htmlOptions['checked']='checked'; + self::clientChange('click',$htmlOptions); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck='0'; + $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false); + $hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : ''; + // add a hidden field so that if the radio button is not selected, it still submits a value + return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions); + } + public static function activeCheckBox($model,$attribute,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + if(!isset($htmlOptions['value'])) + $htmlOptions['value']=1; + if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value']) + $htmlOptions['checked']='checked'; + self::clientChange('click',$htmlOptions); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck='0'; + $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false); + $hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : ''; + return $hidden . self::activeInputField('checkbox',$model,$attribute,$htmlOptions); + } + public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + $selection=self::resolveValue($model,$attribute); + $options="\n".self::listOptions($selection,$data,$htmlOptions); + self::clientChange('change',$htmlOptions); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + if(isset($htmlOptions['multiple'])) + { + if(substr($htmlOptions['name'],-2)!=='[]') + $htmlOptions['name'].='[]'; + } + return self::tag('select',$htmlOptions,$options); + } + public static function activeListBox($model,$attribute,$data,$htmlOptions=array()) + { + if(!isset($htmlOptions['size'])) + $htmlOptions['size']=4; + return self::activeDropDownList($model,$attribute,$data,$htmlOptions); + } + public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + $selection=self::resolveValue($model,$attribute); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + $name=$htmlOptions['name']; + unset($htmlOptions['name']); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck=''; + $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false); + $hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : ''; + return $hidden . self::checkBoxList($name,$selection,$data,$htmlOptions); + } + public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array()) + { + self::resolveNameID($model,$attribute,$htmlOptions); + $selection=self::resolveValue($model,$attribute); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + $name=$htmlOptions['name']; + unset($htmlOptions['name']); + if(array_key_exists('uncheckValue',$htmlOptions)) + { + $uncheck=$htmlOptions['uncheckValue']; + unset($htmlOptions['uncheckValue']); + } + else + $uncheck=''; + $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false); + $hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : ''; + return $hidden . self::radioButtonList($name,$selection,$data,$htmlOptions); + } + public static function errorSummary($model,$header=null,$footer=null,$htmlOptions=array()) + { + $content=''; + if(!is_array($model)) + $model=array($model); + if(isset($htmlOptions['firstError'])) + { + $firstError=$htmlOptions['firstError']; + unset($htmlOptions['firstError']); + } + else + $firstError=false; + foreach($model as $m) + { + foreach($m->getErrors() as $errors) + { + foreach($errors as $error) + { + if($error!='') + $content.="<li>$error</li>\n"; + if($firstError) + break; + } + } + } + if($content!=='') + { + if($header===null) + $header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>'; + if(!isset($htmlOptions['class'])) + $htmlOptions['class']=self::$errorSummaryCss; + return self::tag('div',$htmlOptions,$header."\n<ul>\n$content</ul>".$footer); + } + else + return ''; + } + public static function error($model,$attribute,$htmlOptions=array()) + { + self::resolveName($model,$attribute); // turn [a][b]attr into attr + $error=$model->getError($attribute); + if($error!='') + { + if(!isset($htmlOptions['class'])) + $htmlOptions['class']=self::$errorMessageCss; + return self::tag('div',$htmlOptions,$error); + } + else + return ''; + } + public static function listData($models,$valueField,$textField,$groupField='') + { + $listData=array(); + if($groupField==='') + { + foreach($models as $model) + { + $value=self::value($model,$valueField); + $text=self::value($model,$textField); + $listData[$value]=$text; + } + } + else + { + foreach($models as $model) + { + $group=self::value($model,$groupField); + $value=self::value($model,$valueField); + $text=self::value($model,$textField); + $listData[$group][$value]=$text; + } + } + return $listData; + } + public static function value($model,$attribute,$defaultValue=null) + { + foreach(explode('.',$attribute) as $name) + { + if(is_object($model)) + $model=$model->$name; + else if(is_array($model) && isset($model[$name])) + $model=$model[$name]; + else + return $defaultValue; + } + return $model; + } + public static function getIdByName($name) + { + return str_replace(array('[]', '][', '[', ']'), array('', '_', '_', ''), $name); + } + public static function activeId($model,$attribute) + { + return self::getIdByName(self::activeName($model,$attribute)); + } + public static function activeName($model,$attribute) + { + $a=$attribute; // because the attribute name may be changed by resolveName + return self::resolveName($model,$a); + } + protected static function activeInputField($type,$model,$attribute,$htmlOptions) + { + $htmlOptions['type']=$type; + if($type==='text' || $type==='password') + { + if(!isset($htmlOptions['maxlength'])) + { + foreach($model->getValidators($attribute) as $validator) + { + if($validator instanceof CStringValidator && $validator->max!==null) + { + $htmlOptions['maxlength']=$validator->max; + break; + } + } + } + else if($htmlOptions['maxlength']===false) + unset($htmlOptions['maxlength']); + } + if($type==='file') + unset($htmlOptions['value']); + else if(!isset($htmlOptions['value'])) + $htmlOptions['value']=self::resolveValue($model,$attribute); + if($model->hasErrors($attribute)) + self::addErrorCss($htmlOptions); + return self::tag('input',$htmlOptions); + } + public static function listOptions($selection,$listData,&$htmlOptions) + { + $raw=isset($htmlOptions['encode']) && !$htmlOptions['encode']; + $content=''; + if(isset($htmlOptions['prompt'])) + { + $content.='<option value="">'.strtr($htmlOptions['prompt'],array('<'=>'<', '>'=>'>'))."</option>\n"; + unset($htmlOptions['prompt']); + } + if(isset($htmlOptions['empty'])) + { + if(!is_array($htmlOptions['empty'])) + $htmlOptions['empty']=array(''=>$htmlOptions['empty']); + foreach($htmlOptions['empty'] as $value=>$label) + $content.='<option value="'.self::encode($value).'">'.strtr($label,array('<'=>'<', '>'=>'>'))."</option>\n"; + unset($htmlOptions['empty']); + } + if(isset($htmlOptions['options'])) + { + $options=$htmlOptions['options']; + unset($htmlOptions['options']); + } + else + $options=array(); + $key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey'; + if(is_array($selection)) + { + foreach($selection as $i=>$item) + { + if(is_object($item)) + $selection[$i]=$item->$key; + } + } + else if(is_object($selection)) + $selection=$selection->$key; + foreach($listData as $key=>$value) + { + if(is_array($value)) + { + $content.='<optgroup label="'.($raw?$key : self::encode($key))."\">\n"; + $dummy=array('options'=>$options); + if(isset($htmlOptions['encode'])) + $dummy['encode']=$htmlOptions['encode']; + $content.=self::listOptions($selection,$value,$dummy); + $content.='</optgroup>'."\n"; + } + else + { + $attributes=array('value'=>(string)$key, 'encode'=>!$raw); + if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection)) + $attributes['selected']='selected'; + if(isset($options[$key])) + $attributes=array_merge($attributes,$options[$key]); + $content.=self::tag('option',$attributes,$raw?(string)$value : self::encode((string)$value))."\n"; + } + } + unset($htmlOptions['key']); + return $content; + } + protected static function clientChange($event,&$htmlOptions) + { + if(!isset($htmlOptions['submit']) && !isset($htmlOptions['confirm']) && !isset($htmlOptions['ajax'])) + return; + if(isset($htmlOptions['live'])) + { + $live=$htmlOptions['live']; + unset($htmlOptions['live']); + } + else + $live = self::$liveEvents; + if(isset($htmlOptions['return']) && $htmlOptions['return']) + $return='return true'; + else + $return='return false'; + if(isset($htmlOptions['on'.$event])) + { + $handler=trim($htmlOptions['on'.$event],';').';'; + unset($htmlOptions['on'.$event]); + } + else + $handler=''; + if(isset($htmlOptions['id'])) + $id=$htmlOptions['id']; + else + $id=$htmlOptions['id']=isset($htmlOptions['name'])?$htmlOptions['name']:self::ID_PREFIX.self::$count++; + $cs=Yii::app()->getClientScript(); + $cs->registerCoreScript('jquery'); + if(isset($htmlOptions['submit'])) + { + $cs->registerCoreScript('yii'); + $request=Yii::app()->getRequest(); + if($request->enableCsrfValidation && isset($htmlOptions['csrf']) && $htmlOptions['csrf']) + $htmlOptions['params'][$request->csrfTokenName]=$request->getCsrfToken(); + if(isset($htmlOptions['params'])) + $params=CJavaScript::encode($htmlOptions['params']); + else + $params='{}'; + if($htmlOptions['submit']!=='') + $url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit'])); + else + $url=''; + $handler.="jQuery.yii.submitForm(this,'$url',$params);{$return};"; + } + if(isset($htmlOptions['ajax'])) + $handler.=self::ajax($htmlOptions['ajax'])."{$return};"; + if(isset($htmlOptions['confirm'])) + { + $confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')'; + if($handler!=='') + $handler="if($confirm) {".$handler."} else return false;"; + else + $handler="return $confirm;"; + } + if($live) + $cs->registerScript('Yii.CHtml.#' . $id, "$('body').on('$event','#$id',function(){{$handler}});"); + else + $cs->registerScript('Yii.CHtml.#' . $id, "$('#$id').on('$event', function(){{$handler}});"); + unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOptions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']); + } + public static function resolveNameID($model,&$attribute,&$htmlOptions) + { + if(!isset($htmlOptions['name'])) + $htmlOptions['name']=self::resolveName($model,$attribute); + if(!isset($htmlOptions['id'])) + $htmlOptions['id']=self::getIdByName($htmlOptions['name']); + else if($htmlOptions['id']===false) + unset($htmlOptions['id']); + } + public static function resolveName($model,&$attribute) + { + if(($pos=strpos($attribute,'['))!==false) + { + if($pos!==0) // e.g. name[a][b] + return get_class($model).'['.substr($attribute,0,$pos).']'.substr($attribute,$pos); + if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1) // e.g. [a][b]name + { + $sub=substr($attribute,0,$pos+1); + $attribute=substr($attribute,$pos+1); + return get_class($model).$sub.'['.$attribute.']'; + } + if(preg_match('/\](\w+\[.*)$/',$attribute,$matches)) + { + $name=get_class($model).'['.str_replace(']','][',trim(strtr($attribute,array(']['=>']','['=>']')),']')).']'; + $attribute=$matches[1]; + return $name; + } + } + return get_class($model).'['.$attribute.']'; + } + public static function resolveValue($model,$attribute) + { + if(($pos=strpos($attribute,'['))!==false) + { + if($pos===0) // [a]name[b][c], should ignore [a] + { + if(preg_match('/\](\w+)/',$attribute,$matches)) + $attribute=$matches[1]; + if(($pos=strpos($attribute,'['))===false) + return $model->$attribute; + } + $name=substr($attribute,0,$pos); + $value=$model->$name; + foreach(explode('][',rtrim(substr($attribute,$pos+1),']')) as $id) + { + if(is_array($value) && isset($value[$id])) + $value=$value[$id]; + else + return null; + } + return $value; + } + else + return $model->$attribute; + } + protected static function addErrorCss(&$htmlOptions) + { + if(isset($htmlOptions['class'])) + $htmlOptions['class'].=' '.self::$errorCss; + else + $htmlOptions['class']=self::$errorCss; + } + public static function renderAttributes($htmlOptions) + { + static $specialAttributes=array( + 'checked'=>1, + 'declare'=>1, + 'defer'=>1, + 'disabled'=>1, + 'ismap'=>1, + 'multiple'=>1, + 'nohref'=>1, + 'noresize'=>1, + 'readonly'=>1, + 'selected'=>1, + ); + if($htmlOptions===array()) + return ''; + $html=''; + if(isset($htmlOptions['encode'])) + { + $raw=!$htmlOptions['encode']; + unset($htmlOptions['encode']); + } + else + $raw=false; + if($raw) + { + foreach($htmlOptions as $name=>$value) + { + if(isset($specialAttributes[$name])) + { + if($value) + $html .= ' ' . $name . '="' . $name . '"'; + } + else if($value!==null) + $html .= ' ' . $name . '="' . $value . '"'; + } + } + else + { + foreach($htmlOptions as $name=>$value) + { + if(isset($specialAttributes[$name])) + { + if($value) + $html .= ' ' . $name . '="' . $name . '"'; + } + else if($value!==null) + $html .= ' ' . $name . '="' . self::encode($value) . '"'; + } + } + return $html; + } +} +class CWidgetFactory extends CApplicationComponent implements IWidgetFactory +{ + public $enableSkin=false; + public $widgets=array(); + public $skinnableWidgets; + public $skinPath; + private $_skins=array(); // class name, skin name, property name => value + public function init() + { + parent::init(); + if($this->enableSkin && $this->skinPath===null) + $this->skinPath=Yii::app()->getViewPath().DIRECTORY_SEPARATOR.'skins'; + } + public function createWidget($owner,$className,$properties=array()) + { + $className=Yii::import($className,true); + $widget=new $className($owner); + if(isset($this->widgets[$className])) + $properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties); + if($this->enableSkin) + { + if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets)) + { + $skinName=isset($properties['skin']) ? $properties['skin'] : 'default'; + if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array()) + $properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties); + } + } + foreach($properties as $name=>$value) + $widget->$name=$value; + return $widget; + } + protected function getSkin($className,$skinName) + { + if(!isset($this->_skins[$className][$skinName])) + { + $skinFile=$this->skinPath.DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($skinFile)) + $this->_skins[$className]=require($skinFile); + else + $this->_skins[$className]=array(); + if(($theme=Yii::app()->getTheme())!==null) + { + $skinFile=$theme->getSkinPath().DIRECTORY_SEPARATOR.$className.'.php'; + if(is_file($skinFile)) + { + $skins=require($skinFile); + foreach($skins as $name=>$skin) + $this->_skins[$className][$name]=$skin; + } + } + if(!isset($this->_skins[$className][$skinName])) + $this->_skins[$className][$skinName]=array(); + } + return $this->_skins[$className][$skinName]; + } +} +class CWidget extends CBaseController +{ + public $actionPrefix; + public $skin='default'; + private static $_viewPaths; + private static $_counter=0; + private $_id; + private $_owner; + public static function actions() + { + return array(); + } + public function __construct($owner=null) + { + $this->_owner=$owner===null?Yii::app()->getController():$owner; + } + public function getOwner() + { + return $this->_owner; + } + public function getId($autoGenerate=true) + { + if($this->_id!==null) + return $this->_id; + else if($autoGenerate) + return $this->_id='yw'.self::$_counter++; + } + public function setId($value) + { + $this->_id=$value; + } + public function getController() + { + if($this->_owner instanceof CController) + return $this->_owner; + else + return Yii::app()->getController(); + } + public function init() + { + } + public function run() + { + } + public function getViewPath($checkTheme=false) + { + $className=get_class($this); + if(isset(self::$_viewPaths[$className])) + return self::$_viewPaths[$className]; + else + { + if($checkTheme && ($theme=Yii::app()->getTheme())!==null) + { + $path=$theme->getViewPath().DIRECTORY_SEPARATOR; + if(strpos($className,'\\')!==false) // namespaced class + $path.=str_replace('\\','_',ltrim($className,'\\')); + else + $path.=$className; + if(is_dir($path)) + return self::$_viewPaths[$className]=$path; + } + $class=new ReflectionClass($className); + return self::$_viewPaths[$className]=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views'; + } + } + public function getViewFile($viewName) + { + if(($renderer=Yii::app()->getViewRenderer())!==null) + $extension=$renderer->fileExtension; + else + $extension='.php'; + if(strpos($viewName,'.')) // a path alias + $viewFile=Yii::getPathOfAlias($viewName); + else + { + $viewFile=$this->getViewPath(true).DIRECTORY_SEPARATOR.$viewName; + if(is_file($viewFile.$extension)) + return Yii::app()->findLocalizedFile($viewFile.$extension); + else if($extension!=='.php' && is_file($viewFile.'.php')) + return Yii::app()->findLocalizedFile($viewFile.'.php'); + $viewFile=$this->getViewPath(false).DIRECTORY_SEPARATOR.$viewName; + } + if(is_file($viewFile.$extension)) + return Yii::app()->findLocalizedFile($viewFile.$extension); + else if($extension!=='.php' && is_file($viewFile.'.php')) + return Yii::app()->findLocalizedFile($viewFile.'.php'); + else + return false; + } + public function render($view,$data=null,$return=false) + { + if(($viewFile=$this->getViewFile($view))!==false) + return $this->renderFile($viewFile,$data,$return); + else + throw new CException(Yii::t('yii','{widget} cannot find the view "{view}".', + array('{widget}'=>get_class($this), '{view}'=>$view))); + } +} +class CClientScript extends CApplicationComponent +{ + const POS_HEAD=0; + const POS_BEGIN=1; + const POS_END=2; + const POS_LOAD=3; + const POS_READY=4; + public $enableJavaScript=true; + public $scriptMap=array(); + public $packages=array(); + public $corePackages; + protected $cssFiles=array(); + protected $scriptFiles=array(); + protected $scripts=array(); + protected $metaTags=array(); + protected $linkTags=array(); + protected $css=array(); + protected $hasScripts=false; + protected $coreScripts=array(); + public $coreScriptPosition=self::POS_HEAD; + private $_baseUrl; + public function reset() + { + $this->hasScripts=false; + $this->coreScripts=array(); + $this->cssFiles=array(); + $this->css=array(); + $this->scriptFiles=array(); + $this->scripts=array(); + $this->metaTags=array(); + $this->linkTags=array(); + $this->recordCachingAction('clientScript','reset',array()); + } + public function render(&$output) + { + if(!$this->hasScripts) + return; + $this->renderCoreScripts(); + if(!empty($this->scriptMap)) + $this->remapScripts(); + $this->unifyScripts(); + $this->renderHead($output); + if($this->enableJavaScript) + { + $this->renderBodyBegin($output); + $this->renderBodyEnd($output); + } + } + protected function unifyScripts() + { + if(!$this->enableJavaScript) + return; + $map=array(); + if(isset($this->scriptFiles[self::POS_HEAD])) + $map=$this->scriptFiles[self::POS_HEAD]; + if(isset($this->scriptFiles[self::POS_BEGIN])) + { + foreach($this->scriptFiles[self::POS_BEGIN] as $key=>$scriptFile) + { + if(isset($map[$scriptFile])) + unset($this->scriptFiles[self::POS_BEGIN][$key]); + else + $map[$scriptFile]=true; + } + } + if(isset($this->scriptFiles[self::POS_END])) + { + foreach($this->scriptFiles[self::POS_END] as $key=>$scriptFile) + { + if(isset($map[$scriptFile])) + unset($this->scriptFiles[self::POS_END][$key]); + } + } + } + protected function remapScripts() + { + $cssFiles=array(); + foreach($this->cssFiles as $url=>$media) + { + $name=basename($url); + if(isset($this->scriptMap[$name])) + { + if($this->scriptMap[$name]!==false) + $cssFiles[$this->scriptMap[$name]]=$media; + } + else if(isset($this->scriptMap['*.css'])) + { + if($this->scriptMap['*.css']!==false) + $cssFiles[$this->scriptMap['*.css']]=$media; + } + else + $cssFiles[$url]=$media; + } + $this->cssFiles=$cssFiles; + $jsFiles=array(); + foreach($this->scriptFiles as $position=>$scripts) + { + $jsFiles[$position]=array(); + foreach($scripts as $key=>$script) + { + $name=basename($script); + if(isset($this->scriptMap[$name])) + { + if($this->scriptMap[$name]!==false) + $jsFiles[$position][$this->scriptMap[$name]]=$this->scriptMap[$name]; + } + else if(isset($this->scriptMap['*.js'])) + { + if($this->scriptMap['*.js']!==false) + $jsFiles[$position][$this->scriptMap['*.js']]=$this->scriptMap['*.js']; + } + else + $jsFiles[$position][$key]=$script; + } + } + $this->scriptFiles=$jsFiles; + } + public function renderCoreScripts() + { + if($this->coreScripts===null) + return; + $cssFiles=array(); + $jsFiles=array(); + foreach($this->coreScripts as $name=>$package) + { + $baseUrl=$this->getPackageBaseUrl($name); + if(!empty($package['js'])) + { + foreach($package['js'] as $js) + $jsFiles[$baseUrl.'/'.$js]=$baseUrl.'/'.$js; + } + if(!empty($package['css'])) + { + foreach($package['css'] as $css) + $cssFiles[$baseUrl.'/'.$css]=''; + } + } + // merge in place + if($cssFiles!==array()) + { + foreach($this->cssFiles as $cssFile=>$media) + $cssFiles[$cssFile]=$media; + $this->cssFiles=$cssFiles; + } + if($jsFiles!==array()) + { + if(isset($this->scriptFiles[$this->coreScriptPosition])) + { + foreach($this->scriptFiles[$this->coreScriptPosition] as $url) + $jsFiles[$url]=$url; + } + $this->scriptFiles[$this->coreScriptPosition]=$jsFiles; + } + } + public function renderHead(&$output) + { + $html=''; + foreach($this->metaTags as $meta) + $html.=CHtml::metaTag($meta['content'],null,null,$meta)."\n"; + foreach($this->linkTags as $link) + $html.=CHtml::linkTag(null,null,null,null,$link)."\n"; + foreach($this->cssFiles as $url=>$media) + $html.=CHtml::cssFile($url,$media)."\n"; + foreach($this->css as $css) + $html.=CHtml::css($css[0],$css[1])."\n"; + if($this->enableJavaScript) + { + if(isset($this->scriptFiles[self::POS_HEAD])) + { + foreach($this->scriptFiles[self::POS_HEAD] as $scriptFile) + $html.=CHtml::scriptFile($scriptFile)."\n"; + } + if(isset($this->scripts[self::POS_HEAD])) + $html.=CHtml::script(implode("\n",$this->scripts[self::POS_HEAD]))."\n"; + } + if($html!=='') + { + $count=0; + $output=preg_replace('/(<title\b[^>]*>|<\\/head\s*>)/is','<###head###>$1',$output,1,$count); + if($count) + $output=str_replace('<###head###>',$html,$output); + else + $output=$html.$output; + } + } + public function renderBodyBegin(&$output) + { + $html=''; + if(isset($this->scriptFiles[self::POS_BEGIN])) + { + foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFile) + $html.=CHtml::scriptFile($scriptFile)."\n"; + } + if(isset($this->scripts[self::POS_BEGIN])) + $html.=CHtml::script(implode("\n",$this->scripts[self::POS_BEGIN]))."\n"; + if($html!=='') + { + $count=0; + $output=preg_replace('/(<body\b[^>]*>)/is','$1<###begin###>',$output,1,$count); + if($count) + $output=str_replace('<###begin###>',$html,$output); + else + $output=$html.$output; + } + } + public function renderBodyEnd(&$output) + { + if(!isset($this->scriptFiles[self::POS_END]) && !isset($this->scripts[self::POS_END]) + && !isset($this->scripts[self::POS_READY]) && !isset($this->scripts[self::POS_LOAD])) + return; + $fullPage=0; + $output=preg_replace('/(<\\/body\s*>)/is','<###end###>$1',$output,1,$fullPage); + $html=''; + if(isset($this->scriptFiles[self::POS_END])) + { + foreach($this->scriptFiles[self::POS_END] as $scriptFile) + $html.=CHtml::scriptFile($scriptFile)."\n"; + } + $scripts=isset($this->scripts[self::POS_END]) ? $this->scripts[self::POS_END] : array(); + if(isset($this->scripts[self::POS_READY])) + { + if($fullPage) + $scripts[]="jQuery(function($) {\n".implode("\n",$this->scripts[self::POS_READY])."\n});"; + else + $scripts[]=implode("\n",$this->scripts[self::POS_READY]); + } + if(isset($this->scripts[self::POS_LOAD])) + { + if($fullPage) + $scripts[]="jQuery(window).load(function() {\n".implode("\n",$this->scripts[self::POS_LOAD])."\n});"; + else + $scripts[]=implode("\n",$this->scripts[self::POS_LOAD]); + } + if(!empty($scripts)) + $html.=CHtml::script(implode("\n",$scripts))."\n"; + if($fullPage) + $output=str_replace('<###end###>',$html,$output); + else + $output=$output.$html; + } + public function getCoreScriptUrl() + { + if($this->_baseUrl!==null) + return $this->_baseUrl; + else + return $this->_baseUrl=Yii::app()->getAssetManager()->publish(YII_PATH.'/web/js/source'); + } + public function setCoreScriptUrl($value) + { + $this->_baseUrl=$value; + } + public function getPackageBaseUrl($name) + { + if(!isset($this->coreScripts[$name])) + return false; + $package=$this->coreScripts[$name]; + if(isset($package['baseUrl'])) + { + $baseUrl=$package['baseUrl']; + if($baseUrl==='' || $baseUrl[0]!=='/' && strpos($baseUrl,'://')===false) + $baseUrl=Yii::app()->getRequest()->getBaseUrl().'/'.$baseUrl; + $baseUrl=rtrim($baseUrl,'/'); + } + else if(isset($package['basePath'])) + $baseUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias($package['basePath'])); + else + $baseUrl=$this->getCoreScriptUrl(); + return $this->coreScripts[$name]['baseUrl']=$baseUrl; + } + public function registerPackage($name) + { + return $this->registerCoreScript($name); + } + public function registerCoreScript($name) + { + if(isset($this->coreScripts[$name])) + return $this; + if(isset($this->packages[$name])) + $package=$this->packages[$name]; + else + { + if($this->corePackages===null) + $this->corePackages=require(YII_PATH.'/web/js/packages.php'); + if(isset($this->corePackages[$name])) + $package=$this->corePackages[$name]; + } + if(isset($package)) + { + if(!empty($package['depends'])) + { + foreach($package['depends'] as $p) + $this->registerCoreScript($p); + } + $this->coreScripts[$name]=$package; + $this->hasScripts=true; + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerCoreScript',$params); + } + return $this; + } + public function registerCssFile($url,$media='') + { + $this->hasScripts=true; + $this->cssFiles[$url]=$media; + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerCssFile',$params); + return $this; + } + public function registerCss($id,$css,$media='') + { + $this->hasScripts=true; + $this->css[$id]=array($css,$media); + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerCss',$params); + return $this; + } + public function registerScriptFile($url,$position=self::POS_HEAD) + { + $this->hasScripts=true; + $this->scriptFiles[$position][$url]=$url; + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerScriptFile',$params); + return $this; + } + public function registerScript($id,$script,$position=self::POS_READY) + { + $this->hasScripts=true; + $this->scripts[$position][$id]=$script; + if($position===self::POS_READY || $position===self::POS_LOAD) + $this->registerCoreScript('jquery'); + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerScript',$params); + return $this; + } + public function registerMetaTag($content,$name=null,$httpEquiv=null,$options=array()) + { + $this->hasScripts=true; + if($name!==null) + $options['name']=$name; + if($httpEquiv!==null) + $options['http-equiv']=$httpEquiv; + $options['content']=$content; + $this->metaTags[serialize($options)]=$options; + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerMetaTag',$params); + return $this; + } + public function registerLinkTag($relation=null,$type=null,$href=null,$media=null,$options=array()) + { + $this->hasScripts=true; + if($relation!==null) + $options['rel']=$relation; + if($type!==null) + $options['type']=$type; + if($href!==null) + $options['href']=$href; + if($media!==null) + $options['media']=$media; + $this->linkTags[serialize($options)]=$options; + $params=func_get_args(); + $this->recordCachingAction('clientScript','registerLinkTag',$params); + return $this; + } + public function isCssFileRegistered($url) + { + return isset($this->cssFiles[$url]); + } + public function isCssRegistered($id) + { + return isset($this->css[$id]); + } + public function isScriptFileRegistered($url,$position=self::POS_HEAD) + { + return isset($this->scriptFiles[$position][$url]); + } + public function isScriptRegistered($id,$position=self::POS_READY) + { + return isset($this->scripts[$position][$id]); + } + protected function recordCachingAction($context,$method,$params) + { + if(($controller=Yii::app()->getController())!==null) + $controller->recordCachingAction($context,$method,$params); + } + public function addPackage($name,$definition) + { + $this->packages[$name]=$definition; + return $this; + } +} +class CList extends CComponent implements IteratorAggregate,ArrayAccess,Countable +{ + private $_d=array(); + private $_c=0; + private $_r=false; + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + public function getReadOnly() + { + return $this->_r; + } + protected function setReadOnly($value) + { + $this->_r=$value; + } + public function getIterator() + { + return new CListIterator($this->_d); + } + public function count() + { + return $this->getCount(); + } + public function getCount() + { + return $this->_c; + } + public function itemAt($index) + { + if(isset($this->_d[$index])) + return $this->_d[$index]; + else if($index>=0 && $index<$this->_c) // in case the value is null + return $this->_d[$index]; + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + public function add($item) + { + $this->insertAt($this->_c,$item); + return $this->_c-1; + } + public function insertAt($index,$item) + { + if(!$this->_r) + { + if($index===$this->_c) + $this->_d[$this->_c++]=$item; + else if($index>=0 && $index<$this->_c) + { + array_splice($this->_d,$index,0,array($item)); + $this->_c++; + } + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + else + throw new CException(Yii::t('yii','The list is read only.')); + } + public function remove($item) + { + if(($index=$this->indexOf($item))>=0) + { + $this->removeAt($index); + return $index; + } + else + return false; + } + public function removeAt($index) + { + if(!$this->_r) + { + if($index>=0 && $index<$this->_c) + { + $this->_c--; + if($index===$this->_c) + return array_pop($this->_d); + else + { + $item=$this->_d[$index]; + array_splice($this->_d,$index,1); + return $item; + } + } + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + else + throw new CException(Yii::t('yii','The list is read only.')); + } + public function clear() + { + for($i=$this->_c-1;$i>=0;--$i) + $this->removeAt($i); + } + public function contains($item) + { + return $this->indexOf($item)>=0; + } + public function indexOf($item) + { + if(($index=array_search($item,$this->_d,true))!==false) + return $index; + else + return -1; + } + public function toArray() + { + return $this->_d; + } + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + if($this->_c>0) + $this->clear(); + if($data instanceof CList) + $data=$data->_d; + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.')); + } + public function mergeWith($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + if($data instanceof CList) + $data=$data->_d; + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.')); + } + public function offsetExists($offset) + { + return ($offset>=0 && $offset<$this->_c); + } + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + public function offsetSet($offset,$item) + { + if($offset===null || $offset===$this->_c) + $this->insertAt($this->_c,$item); + else + { + $this->removeAt($offset); + $this->insertAt($offset,$item); + } + } + public function offsetUnset($offset) + { + $this->removeAt($offset); + } +} +class CFilterChain extends CList +{ + public $controller; + public $action; + public $filterIndex=0; + public function __construct($controller,$action) + { + $this->controller=$controller; + $this->action=$action; + } + public static function create($controller,$action,$filters) + { + $chain=new CFilterChain($controller,$action); + $actionID=$action->getId(); + foreach($filters as $filter) + { + if(is_string($filter)) // filterName [+|- action1 action2] + { + if(($pos=strpos($filter,'+'))!==false || ($pos=strpos($filter,'-'))!==false) + { + $matched=preg_match("/\b{$actionID}\b/i",substr($filter,$pos+1))>0; + if(($filter[$pos]==='+')===$matched) + $filter=CInlineFilter::create($controller,trim(substr($filter,0,$pos))); + } + else + $filter=CInlineFilter::create($controller,$filter); + } + else if(is_array($filter)) // array('path.to.class [+|- action1, action2]','param1'=>'value1',...) + { + if(!isset($filter[0])) + throw new CException(Yii::t('yii','The first element in a filter configuration must be the filter class.')); + $filterClass=$filter[0]; + unset($filter[0]); + if(($pos=strpos($filterClass,'+'))!==false || ($pos=strpos($filterClass,'-'))!==false) + { + $matched=preg_match("/\b{$actionID}\b/i",substr($filterClass,$pos+1))>0; + if(($filterClass[$pos]==='+')===$matched) + $filterClass=trim(substr($filterClass,0,$pos)); + else + continue; + } + $filter['class']=$filterClass; + $filter=Yii::createComponent($filter); + } + if(is_object($filter)) + { + $filter->init(); + $chain->add($filter); + } + } + return $chain; + } + public function insertAt($index,$item) + { + if($item instanceof IFilter) + parent::insertAt($index,$item); + else + throw new CException(Yii::t('yii','CFilterChain can only take objects implementing the IFilter interface.')); + } + public function run() + { + if($this->offsetExists($this->filterIndex)) + { + $filter=$this->itemAt($this->filterIndex++); + $filter->filter($this); + } + else + $this->controller->runAction($this->action); + } +} +class CFilter extends CComponent implements IFilter +{ + public function filter($filterChain) + { + if($this->preFilter($filterChain)) + { + $filterChain->run(); + $this->postFilter($filterChain); + } + } + public function init() + { + } + protected function preFilter($filterChain) + { + return true; + } + protected function postFilter($filterChain) + { + } +} +class CInlineFilter extends CFilter +{ + public $name; + public static function create($controller,$filterName) + { + if(method_exists($controller,'filter'.$filterName)) + { + $filter=new CInlineFilter; + $filter->name=$filterName; + return $filter; + } + else + throw new CException(Yii::t('yii','Filter "{filter}" is invalid. Controller "{class}" does not have the filter method "filter{filter}".', + array('{filter}'=>$filterName, '{class}'=>get_class($controller)))); + } + public function filter($filterChain) + { + $method='filter'.$this->name; + $filterChain->controller->$method($filterChain); + } +} +class CAccessControlFilter extends CFilter +{ + public $message; + private $_rules=array(); + public function getRules() + { + return $this->_rules; + } + public function setRules($rules) + { + foreach($rules as $rule) + { + if(is_array($rule) && isset($rule[0])) + { + $r=new CAccessRule; + $r->allow=$rule[0]==='allow'; + foreach(array_slice($rule,1) as $name=>$value) + { + if($name==='expression' || $name==='roles' || $name==='message') + $r->$name=$value; + else + $r->$name=array_map('strtolower',$value); + } + $this->_rules[]=$r; + } + } + } + protected function preFilter($filterChain) + { + $app=Yii::app(); + $request=$app->getRequest(); + $user=$app->getUser(); + $verb=$request->getRequestType(); + $ip=$request->getUserHostAddress(); + foreach($this->getRules() as $rule) + { + if(($allow=$rule->isUserAllowed($user,$filterChain->controller,$filterChain->action,$ip,$verb))>0) // allowed + break; + else if($allow<0) // denied + { + $this->accessDenied($user,$this->resolveErrorMessage($rule)); + return false; + } + } + return true; + } + protected function resolveErrorMessage($rule) + { + if($rule->message!==null) + return $rule->message; + else if($this->message!==null) + return $this->message; + else + return Yii::t('yii','You are not authorized to perform this action.'); + } + protected function accessDenied($user,$message) + { + if($user->getIsGuest()) + $user->loginRequired(); + else + throw new CHttpException(403,$message); + } +} +class CAccessRule extends CComponent +{ + public $allow; + public $actions; + public $controllers; + public $users; + public $roles; + public $ips; + public $verbs; + public $expression; + public $message; + public function isUserAllowed($user,$controller,$action,$ip,$verb) + { + if($this->isActionMatched($action) + && $this->isUserMatched($user) + && $this->isRoleMatched($user) + && $this->isIpMatched($ip) + && $this->isVerbMatched($verb) + && $this->isControllerMatched($controller) + && $this->isExpressionMatched($user)) + return $this->allow ? 1 : -1; + else + return 0; + } + protected function isActionMatched($action) + { + return empty($this->actions) || in_array(strtolower($action->getId()),$this->actions); + } + protected function isControllerMatched($controller) + { + return empty($this->controllers) || in_array(strtolower($controller->getId()),$this->controllers); + } + protected function isUserMatched($user) + { + if(empty($this->users)) + return true; + foreach($this->users as $u) + { + if($u==='*') + return true; + else if($u==='?' && $user->getIsGuest()) + return true; + else if($u==='@' && !$user->getIsGuest()) + return true; + else if(!strcasecmp($u,$user->getName())) + return true; + } + return false; + } + protected function isRoleMatched($user) + { + if(empty($this->roles)) + return true; + foreach($this->roles as $role) + { + if($user->checkAccess($role)) + return true; + } + return false; + } + protected function isIpMatched($ip) + { + if(empty($this->ips)) + return true; + foreach($this->ips as $rule) + { + if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && !strncmp($ip,$rule,$pos))) + return true; + } + return false; + } + protected function isVerbMatched($verb) + { + return empty($this->verbs) || in_array(strtolower($verb),$this->verbs); + } + protected function isExpressionMatched($user) + { + if($this->expression===null) + return true; + else + return $this->evaluateExpression($this->expression, array('user'=>$user)); + } +} +abstract class CModel extends CComponent implements IteratorAggregate, ArrayAccess +{ + private $_errors=array(); // attribute name => array of errors + private $_validators; // validators + private $_scenario=''; // scenario + abstract public function attributeNames(); + public function rules() + { + return array(); + } + public function behaviors() + { + return array(); + } + public function attributeLabels() + { + return array(); + } + public function validate($attributes=null, $clearErrors=true) + { + if($clearErrors) + $this->clearErrors(); + if($this->beforeValidate()) + { + foreach($this->getValidators() as $validator) + $validator->validate($this,$attributes); + $this->afterValidate(); + return !$this->hasErrors(); + } + else + return false; + } + protected function afterConstruct() + { + if($this->hasEventHandler('onAfterConstruct')) + $this->onAfterConstruct(new CEvent($this)); + } + protected function beforeValidate() + { + $event=new CModelEvent($this); + $this->onBeforeValidate($event); + return $event->isValid; + } + protected function afterValidate() + { + $this->onAfterValidate(new CEvent($this)); + } + public function onAfterConstruct($event) + { + $this->raiseEvent('onAfterConstruct',$event); + } + public function onBeforeValidate($event) + { + $this->raiseEvent('onBeforeValidate',$event); + } + public function onAfterValidate($event) + { + $this->raiseEvent('onAfterValidate',$event); + } + public function getValidatorList() + { + if($this->_validators===null) + $this->_validators=$this->createValidators(); + return $this->_validators; + } + public function getValidators($attribute=null) + { + if($this->_validators===null) + $this->_validators=$this->createValidators(); + $validators=array(); + $scenario=$this->getScenario(); + foreach($this->_validators as $validator) + { + if($validator->applyTo($scenario)) + { + if($attribute===null || in_array($attribute,$validator->attributes,true)) + $validators[]=$validator; + } + } + return $validators; + } + public function createValidators() + { + $validators=new CList; + foreach($this->rules() as $rule) + { + if(isset($rule[0],$rule[1])) // attributes, validator name + $validators->add(CValidator::createValidator($rule[1],$this,$rule[0],array_slice($rule,2))); + else + throw new CException(Yii::t('yii','{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.', + array('{class}'=>get_class($this)))); + } + return $validators; + } + public function isAttributeRequired($attribute) + { + foreach($this->getValidators($attribute) as $validator) + { + if($validator instanceof CRequiredValidator) + return true; + } + return false; + } + public function isAttributeSafe($attribute) + { + $attributes=$this->getSafeAttributeNames(); + return in_array($attribute,$attributes); + } + public function getAttributeLabel($attribute) + { + $labels=$this->attributeLabels(); + if(isset($labels[$attribute])) + return $labels[$attribute]; + else + return $this->generateAttributeLabel($attribute); + } + public function hasErrors($attribute=null) + { + if($attribute===null) + return $this->_errors!==array(); + else + return isset($this->_errors[$attribute]); + } + public function getErrors($attribute=null) + { + if($attribute===null) + return $this->_errors; + else + return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : array(); + } + public function getError($attribute) + { + return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null; + } + public function addError($attribute,$error) + { + $this->_errors[$attribute][]=$error; + } + public function addErrors($errors) + { + foreach($errors as $attribute=>$error) + { + if(is_array($error)) + { + foreach($error as $e) + $this->_errors[$attribute][]=$e; + } + else + $this->_errors[$attribute][]=$error; + } + } + public function clearErrors($attribute=null) + { + if($attribute===null) + $this->_errors=array(); + else + unset($this->_errors[$attribute]); + } + public function generateAttributeLabel($name) + { + return ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $name))))); + } + public function getAttributes($names=null) + { + $values=array(); + foreach($this->attributeNames() as $name) + $values[$name]=$this->$name; + if(is_array($names)) + { + $values2=array(); + foreach($names as $name) + $values2[$name]=isset($values[$name]) ? $values[$name] : null; + return $values2; + } + else + return $values; + } + public function setAttributes($values,$safeOnly=true) + { + if(!is_array($values)) + return; + $attributes=array_flip($safeOnly ? $this->getSafeAttributeNames() : $this->attributeNames()); + foreach($values as $name=>$value) + { + if(isset($attributes[$name])) + $this->$name=$value; + else if($safeOnly) + $this->onUnsafeAttribute($name,$value); + } + } + public function unsetAttributes($names=null) + { + if($names===null) + $names=$this->attributeNames(); + foreach($names as $name) + $this->$name=null; + } + public function onUnsafeAttribute($name,$value) + { + if(YII_DEBUG) + Yii::log(Yii::t('yii','Failed to set unsafe attribute "{attribute}" of "{class}".',array('{attribute}'=>$name, '{class}'=>get_class($this))),CLogger::LEVEL_WARNING); + } + public function getScenario() + { + return $this->_scenario; + } + public function setScenario($value) + { + $this->_scenario=$value; + } + public function getSafeAttributeNames() + { + $attributes=array(); + $unsafe=array(); + foreach($this->getValidators() as $validator) + { + if(!$validator->safe) + { + foreach($validator->attributes as $name) + $unsafe[]=$name; + } + else + { + foreach($validator->attributes as $name) + $attributes[$name]=true; + } + } + foreach($unsafe as $name) + unset($attributes[$name]); + return array_keys($attributes); + } + public function getIterator() + { + $attributes=$this->getAttributes(); + return new CMapIterator($attributes); + } + public function offsetExists($offset) + { + return property_exists($this,$offset); + } + public function offsetGet($offset) + { + return $this->$offset; + } + public function offsetSet($offset,$item) + { + $this->$offset=$item; + } + public function offsetUnset($offset) + { + unset($this->$offset); + } +} +abstract class CActiveRecord extends CModel +{ + const BELONGS_TO='CBelongsToRelation'; + const HAS_ONE='CHasOneRelation'; + const HAS_MANY='CHasManyRelation'; + const MANY_MANY='CManyManyRelation'; + const STAT='CStatRelation'; + public static $db; + private static $_models=array(); // class name => model + private $_md; // meta data + private $_new=false; // whether this instance is new or not + private $_attributes=array(); // attribute name => attribute value + private $_related=array(); // attribute name => related objects + private $_c; // query criteria (used by finder only) + private $_pk; // old primary key value + private $_alias='t'; // the table alias being used for query + public function __construct($scenario='insert') + { + if($scenario===null) // internally used by populateRecord() and model() + return; + $this->setScenario($scenario); + $this->setIsNewRecord(true); + $this->_attributes=$this->getMetaData()->attributeDefaults; + $this->init(); + $this->attachBehaviors($this->behaviors()); + $this->afterConstruct(); + } + public function init() + { + } + public function cache($duration, $dependency=null, $queryCount=1) + { + $this->getDbConnection()->cache($duration, $dependency, $queryCount); + return $this; + } + public function __sleep() + { + $this->_md=null; + return array_keys((array)$this); + } + public function __get($name) + { + if(isset($this->_attributes[$name])) + return $this->_attributes[$name]; + else if(isset($this->getMetaData()->columns[$name])) + return null; + else if(isset($this->_related[$name])) + return $this->_related[$name]; + else if(isset($this->getMetaData()->relations[$name])) + return $this->getRelated($name); + else + return parent::__get($name); + } + public function __set($name,$value) + { + if($this->setAttribute($name,$value)===false) + { + if(isset($this->getMetaData()->relations[$name])) + $this->_related[$name]=$value; + else + parent::__set($name,$value); + } + } + public function __isset($name) + { + if(isset($this->_attributes[$name])) + return true; + else if(isset($this->getMetaData()->columns[$name])) + return false; + else if(isset($this->_related[$name])) + return true; + else if(isset($this->getMetaData()->relations[$name])) + return $this->getRelated($name)!==null; + else + return parent::__isset($name); + } + public function __unset($name) + { + if(isset($this->getMetaData()->columns[$name])) + unset($this->_attributes[$name]); + else if(isset($this->getMetaData()->relations[$name])) + unset($this->_related[$name]); + else + parent::__unset($name); + } + public function __call($name,$parameters) + { + if(isset($this->getMetaData()->relations[$name])) + { + if(empty($parameters)) + return $this->getRelated($name,false); + else + return $this->getRelated($name,false,$parameters[0]); + } + $scopes=$this->scopes(); + if(isset($scopes[$name])) + { + $this->getDbCriteria()->mergeWith($scopes[$name]); + return $this; + } + return parent::__call($name,$parameters); + } + public function getRelated($name,$refresh=false,$params=array()) + { + if(!$refresh && $params===array() && (isset($this->_related[$name]) || array_key_exists($name,$this->_related))) + return $this->_related[$name]; + $md=$this->getMetaData(); + if(!isset($md->relations[$name])) + throw new CDbException(Yii::t('yii','{class} does not have relation "{name}".', + array('{class}'=>get_class($this), '{name}'=>$name))); + $relation=$md->relations[$name]; + if($this->getIsNewRecord() && !$refresh && ($relation instanceof CHasOneRelation || $relation instanceof CHasManyRelation)) + return $relation instanceof CHasOneRelation ? null : array(); + if($params!==array()) // dynamic query + { + $exists=isset($this->_related[$name]) || array_key_exists($name,$this->_related); + if($exists) + $save=$this->_related[$name]; + $r=array($name=>$params); + } + else + $r=$name; + unset($this->_related[$name]); + $finder=new CActiveFinder($this,$r); + $finder->lazyFind($this); + if(!isset($this->_related[$name])) + { + if($relation instanceof CHasManyRelation) + $this->_related[$name]=array(); + else if($relation instanceof CStatRelation) + $this->_related[$name]=$relation->defaultValue; + else + $this->_related[$name]=null; + } + if($params!==array()) + { + $results=$this->_related[$name]; + if($exists) + $this->_related[$name]=$save; + else + unset($this->_related[$name]); + return $results; + } + else + return $this->_related[$name]; + } + public function hasRelated($name) + { + return isset($this->_related[$name]) || array_key_exists($name,$this->_related); + } + public function getDbCriteria($createIfNull=true) + { + if($this->_c===null) + { + if(($c=$this->defaultScope())!==array() || $createIfNull) + $this->_c=new CDbCriteria($c); + } + return $this->_c; + } + public function setDbCriteria($criteria) + { + $this->_c=$criteria; + } + public function defaultScope() + { + return array(); + } + public function resetScope() + { + $this->_c=new CDbCriteria(); + return $this; + } + public static function model($className=__CLASS__) + { + if(isset(self::$_models[$className])) + return self::$_models[$className]; + else + { + $model=self::$_models[$className]=new $className(null); + $model->_md=new CActiveRecordMetaData($model); + $model->attachBehaviors($model->behaviors()); + return $model; + } + } + public function getMetaData() + { + if($this->_md!==null) + return $this->_md; + else + return $this->_md=self::model(get_class($this))->_md; + } + public function refreshMetaData() + { + $finder=self::model(get_class($this)); + $finder->_md=new CActiveRecordMetaData($finder); + if($this!==$finder) + $this->_md=$finder->_md; + } + public function tableName() + { + return get_class($this); + } + public function primaryKey() + { + } + public function relations() + { + return array(); + } + public function scopes() + { + return array(); + } + public function attributeNames() + { + return array_keys($this->getMetaData()->columns); + } + public function getAttributeLabel($attribute) + { + $labels=$this->attributeLabels(); + if(isset($labels[$attribute])) + return $labels[$attribute]; + else if(strpos($attribute,'.')!==false) + { + $segs=explode('.',$attribute); + $name=array_pop($segs); + $model=$this; + foreach($segs as $seg) + { + $relations=$model->getMetaData()->relations; + if(isset($relations[$seg])) + $model=CActiveRecord::model($relations[$seg]->className); + else + break; + } + return $model->getAttributeLabel($name); + } + else + return $this->generateAttributeLabel($attribute); + } + public function getDbConnection() + { + if(self::$db!==null) + return self::$db; + else + { + self::$db=Yii::app()->getDb(); + if(self::$db instanceof CDbConnection) + return self::$db; + else + throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.')); + } + } + public function getActiveRelation($name) + { + return isset($this->getMetaData()->relations[$name]) ? $this->getMetaData()->relations[$name] : null; + } + public function getTableSchema() + { + return $this->getMetaData()->tableSchema; + } + public function getCommandBuilder() + { + return $this->getDbConnection()->getSchema()->getCommandBuilder(); + } + public function hasAttribute($name) + { + return isset($this->getMetaData()->columns[$name]); + } + public function getAttribute($name) + { + if(property_exists($this,$name)) + return $this->$name; + else if(isset($this->_attributes[$name])) + return $this->_attributes[$name]; + } + public function setAttribute($name,$value) + { + if(property_exists($this,$name)) + $this->$name=$value; + else if(isset($this->getMetaData()->columns[$name])) + $this->_attributes[$name]=$value; + else + return false; + return true; + } + public function addRelatedRecord($name,$record,$index) + { + if($index!==false) + { + if(!isset($this->_related[$name])) + $this->_related[$name]=array(); + if($record instanceof CActiveRecord) + { + if($index===true) + $this->_related[$name][]=$record; + else + $this->_related[$name][$index]=$record; + } + } + else if(!isset($this->_related[$name])) + $this->_related[$name]=$record; + } + public function getAttributes($names=true) + { + $attributes=$this->_attributes; + foreach($this->getMetaData()->columns as $name=>$column) + { + if(property_exists($this,$name)) + $attributes[$name]=$this->$name; + else if($names===true && !isset($attributes[$name])) + $attributes[$name]=null; + } + if(is_array($names)) + { + $attrs=array(); + foreach($names as $name) + { + if(property_exists($this,$name)) + $attrs[$name]=$this->$name; + else + $attrs[$name]=isset($attributes[$name])?$attributes[$name]:null; + } + return $attrs; + } + else + return $attributes; + } + public function save($runValidation=true,$attributes=null) + { + if(!$runValidation || $this->validate($attributes)) + return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes); + else + return false; + } + public function getIsNewRecord() + { + return $this->_new; + } + public function setIsNewRecord($value) + { + $this->_new=$value; + } + public function onBeforeSave($event) + { + $this->raiseEvent('onBeforeSave',$event); + } + public function onAfterSave($event) + { + $this->raiseEvent('onAfterSave',$event); + } + public function onBeforeDelete($event) + { + $this->raiseEvent('onBeforeDelete',$event); + } + public function onAfterDelete($event) + { + $this->raiseEvent('onAfterDelete',$event); + } + public function onBeforeFind($event) + { + $this->raiseEvent('onBeforeFind',$event); + } + public function onAfterFind($event) + { + $this->raiseEvent('onAfterFind',$event); + } + protected function beforeSave() + { + if($this->hasEventHandler('onBeforeSave')) + { + $event=new CModelEvent($this); + $this->onBeforeSave($event); + return $event->isValid; + } + else + return true; + } + protected function afterSave() + { + if($this->hasEventHandler('onAfterSave')) + $this->onAfterSave(new CEvent($this)); + } + protected function beforeDelete() + { + if($this->hasEventHandler('onBeforeDelete')) + { + $event=new CModelEvent($this); + $this->onBeforeDelete($event); + return $event->isValid; + } + else + return true; + } + protected function afterDelete() + { + if($this->hasEventHandler('onAfterDelete')) + $this->onAfterDelete(new CEvent($this)); + } + protected function beforeFind() + { + if($this->hasEventHandler('onBeforeFind')) + { + $event=new CModelEvent($this); + // for backward compatibility + $event->criteria=func_num_args()>0 ? func_get_arg(0) : null; + $this->onBeforeFind($event); + } + } + protected function afterFind() + { + if($this->hasEventHandler('onAfterFind')) + $this->onAfterFind(new CEvent($this)); + } + public function beforeFindInternal() + { + $this->beforeFind(); + } + public function afterFindInternal() + { + $this->afterFind(); + } + public function insert($attributes=null) + { + if(!$this->getIsNewRecord()) + throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.')); + if($this->beforeSave()) + { + $builder=$this->getCommandBuilder(); + $table=$this->getMetaData()->tableSchema; + $command=$builder->createInsertCommand($table,$this->getAttributes($attributes)); + if($command->execute()) + { + $primaryKey=$table->primaryKey; + if($table->sequenceName!==null) + { + if(is_string($primaryKey) && $this->$primaryKey===null) + $this->$primaryKey=$builder->getLastInsertID($table); + else if(is_array($primaryKey)) + { + foreach($primaryKey as $pk) + { + if($this->$pk===null) + { + $this->$pk=$builder->getLastInsertID($table); + break; + } + } + } + } + $this->_pk=$this->getPrimaryKey(); + $this->afterSave(); + $this->setIsNewRecord(false); + $this->setScenario('update'); + return true; + } + } + return false; + } + public function update($attributes=null) + { + if($this->getIsNewRecord()) + throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.')); + if($this->beforeSave()) + { + if($this->_pk===null) + $this->_pk=$this->getPrimaryKey(); + $this->updateByPk($this->getOldPrimaryKey(),$this->getAttributes($attributes)); + $this->_pk=$this->getPrimaryKey(); + $this->afterSave(); + return true; + } + else + return false; + } + public function saveAttributes($attributes) + { + if(!$this->getIsNewRecord()) + { + $values=array(); + foreach($attributes as $name=>$value) + { + if(is_integer($name)) + $values[$value]=$this->$value; + else + $values[$name]=$this->$name=$value; + } + if($this->_pk===null) + $this->_pk=$this->getPrimaryKey(); + if($this->updateByPk($this->getOldPrimaryKey(),$values)>0) + { + $this->_pk=$this->getPrimaryKey(); + return true; + } + else + return false; + } + else + throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.')); + } + public function saveCounters($counters) + { + $builder=$this->getCommandBuilder(); + $table=$this->getTableSchema(); + $criteria=$builder->createPkCriteria($table,$this->getOldPrimaryKey()); + $command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria); + if($command->execute()) + { + foreach($counters as $name=>$value) + $this->$name=$this->$name+$value; + return true; + } + else + return false; + } + public function delete() + { + if(!$this->getIsNewRecord()) + { + if($this->beforeDelete()) + { + $result=$this->deleteByPk($this->getPrimaryKey())>0; + $this->afterDelete(); + return $result; + } + else + return false; + } + else + throw new CDbException(Yii::t('yii','The active record cannot be deleted because it is new.')); + } + public function refresh() + { + if(!$this->getIsNewRecord() && ($record=$this->findByPk($this->getPrimaryKey()))!==null) + { + $this->_attributes=array(); + $this->_related=array(); + foreach($this->getMetaData()->columns as $name=>$column) + { + if(property_exists($this,$name)) + $this->$name=$record->$name; + else + $this->_attributes[$name]=$record->$name; + } + return true; + } + else + return false; + } + public function equals($record) + { + return $this->tableName()===$record->tableName() && $this->getPrimaryKey()===$record->getPrimaryKey(); + } + public function getPrimaryKey() + { + $table=$this->getMetaData()->tableSchema; + if(is_string($table->primaryKey)) + return $this->{$table->primaryKey}; + else if(is_array($table->primaryKey)) + { + $values=array(); + foreach($table->primaryKey as $name) + $values[$name]=$this->$name; + return $values; + } + else + return null; + } + public function setPrimaryKey($value) + { + $this->_pk=$this->getPrimaryKey(); + $table=$this->getMetaData()->tableSchema; + if(is_string($table->primaryKey)) + $this->{$table->primaryKey}=$value; + else if(is_array($table->primaryKey)) + { + foreach($table->primaryKey as $name) + $this->$name=$value[$name]; + } + } + public function getOldPrimaryKey() + { + return $this->_pk; + } + public function setOldPrimaryKey($value) + { + $this->_pk=$value; + } + protected function query($criteria,$all=false) + { + $this->beforeFind(); + $this->applyScopes($criteria); + if(empty($criteria->with)) + { + if(!$all) + $criteria->limit=1; + $command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria); + return $all ? $this->populateRecords($command->queryAll(), true, $criteria->index) : $this->populateRecord($command->queryRow()); + } + else + { + $finder=new CActiveFinder($this,$criteria->with); + return $finder->query($criteria,$all); + } + } + public function applyScopes(&$criteria) + { + if(!empty($criteria->scopes)) + { + $scs=$this->scopes(); + $c=$this->getDbCriteria(); + foreach((array)$criteria->scopes as $k=>$v) + { + if(is_integer($k)) + { + if(is_string($v)) + { + if(isset($scs[$v])) + { + $c->mergeWith($scs[$v],true); + continue; + } + $scope=$v; + $params=array(); + } + else if(is_array($v)) + { + $scope=key($v); + $params=current($v); + } + } + else if(is_string($k)) + { + $scope=$k; + $params=$v; + } + call_user_func_array(array($this,$scope),(array)$params); + } + } + if(isset($c) || ($c=$this->getDbCriteria(false))!==null) + { + $c->mergeWith($criteria); + $criteria=$c; + $this->_c=null; + } + } + public function getTableAlias($quote=false, $checkScopes=true) + { + if($checkScopes && ($criteria=$this->getDbCriteria(false))!==null && $criteria->alias!='') + $alias=$criteria->alias; + else + $alias=$this->_alias; + return $quote ? $this->getDbConnection()->getSchema()->quoteTableName($alias) : $alias; + } + public function setTableAlias($alias) + { + $this->_alias=$alias; + } + public function find($condition='',$params=array()) + { + $criteria=$this->getCommandBuilder()->createCriteria($condition,$params); + return $this->query($criteria); + } + public function findAll($condition='',$params=array()) + { + $criteria=$this->getCommandBuilder()->createCriteria($condition,$params); + return $this->query($criteria,true); + } + public function findByPk($pk,$condition='',$params=array()) + { + $prefix=$this->getTableAlias(true).'.'; + $criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix); + return $this->query($criteria); + } + public function findAllByPk($pk,$condition='',$params=array()) + { + $prefix=$this->getTableAlias(true).'.'; + $criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix); + return $this->query($criteria,true); + } + public function findByAttributes($attributes,$condition='',$params=array()) + { + $prefix=$this->getTableAlias(true).'.'; + $criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix); + return $this->query($criteria); + } + public function findAllByAttributes($attributes,$condition='',$params=array()) + { + $prefix=$this->getTableAlias(true).'.'; + $criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix); + return $this->query($criteria,true); + } + public function findBySql($sql,$params=array()) + { + $this->beforeFind(); + if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with)) + { + $this->_c=null; + $finder=new CActiveFinder($this,$criteria->with); + return $finder->findBySql($sql,$params); + } + else + { + $command=$this->getCommandBuilder()->createSqlCommand($sql,$params); + return $this->populateRecord($command->queryRow()); + } + } + public function findAllBySql($sql,$params=array()) + { + $this->beforeFind(); + if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with)) + { + $this->_c=null; + $finder=new CActiveFinder($this,$criteria->with); + return $finder->findAllBySql($sql,$params); + } + else + { + $command=$this->getCommandBuilder()->createSqlCommand($sql,$params); + return $this->populateRecords($command->queryAll()); + } + } + public function count($condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createCriteria($condition,$params); + $this->applyScopes($criteria); + if(empty($criteria->with)) + return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar(); + else + { + $finder=new CActiveFinder($this,$criteria->with); + return $finder->count($criteria); + } + } + public function countByAttributes($attributes,$condition='',$params=array()) + { + $prefix=$this->getTableAlias(true).'.'; + $builder=$this->getCommandBuilder(); + $criteria=$builder->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix); + $this->applyScopes($criteria); + if(empty($criteria->with)) + return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar(); + else + { + $finder=new CActiveFinder($this,$criteria->with); + return $finder->count($criteria); + } + } + public function countBySql($sql,$params=array()) + { + return $this->getCommandBuilder()->createSqlCommand($sql,$params)->queryScalar(); + } + public function exists($condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createCriteria($condition,$params); + $table=$this->getTableSchema(); + $criteria->select='1'; + $criteria->limit=1; + $this->applyScopes($criteria); + if(empty($criteria->with)) + return $builder->createFindCommand($table,$criteria)->queryRow()!==false; + else + { + $criteria->select='*'; + $finder=new CActiveFinder($this,$criteria->with); + return $finder->count($criteria)>0; + } + } + public function with() + { + if(func_num_args()>0) + { + $with=func_get_args(); + if(is_array($with[0])) // the parameter is given as an array + $with=$with[0]; + if(!empty($with)) + $this->getDbCriteria()->mergeWith(array('with'=>$with)); + } + return $this; + } + public function together() + { + $this->getDbCriteria()->together=true; + return $this; + } + public function updateByPk($pk,$attributes,$condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $table=$this->getTableSchema(); + $criteria=$builder->createPkCriteria($table,$pk,$condition,$params); + $command=$builder->createUpdateCommand($table,$attributes,$criteria); + return $command->execute(); + } + public function updateAll($attributes,$condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createCriteria($condition,$params); + $command=$builder->createUpdateCommand($this->getTableSchema(),$attributes,$criteria); + return $command->execute(); + } + public function updateCounters($counters,$condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createCriteria($condition,$params); + $command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria); + return $command->execute(); + } + public function deleteByPk($pk,$condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createPkCriteria($this->getTableSchema(),$pk,$condition,$params); + $command=$builder->createDeleteCommand($this->getTableSchema(),$criteria); + return $command->execute(); + } + public function deleteAll($condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $criteria=$builder->createCriteria($condition,$params); + $command=$builder->createDeleteCommand($this->getTableSchema(),$criteria); + return $command->execute(); + } + public function deleteAllByAttributes($attributes,$condition='',$params=array()) + { + $builder=$this->getCommandBuilder(); + $table=$this->getTableSchema(); + $criteria=$builder->createColumnCriteria($table,$attributes,$condition,$params); + $command=$builder->createDeleteCommand($table,$criteria); + return $command->execute(); + } + public function populateRecord($attributes,$callAfterFind=true) + { + if($attributes!==false) + { + $record=$this->instantiate($attributes); + $record->setScenario('update'); + $record->init(); + $md=$record->getMetaData(); + foreach($attributes as $name=>$value) + { + if(property_exists($record,$name)) + $record->$name=$value; + else if(isset($md->columns[$name])) + $record->_attributes[$name]=$value; + } + $record->_pk=$record->getPrimaryKey(); + $record->attachBehaviors($record->behaviors()); + if($callAfterFind) + $record->afterFind(); + return $record; + } + else + return null; + } + public function populateRecords($data,$callAfterFind=true,$index=null) + { + $records=array(); + foreach($data as $attributes) + { + if(($record=$this->populateRecord($attributes,$callAfterFind))!==null) + { + if($index===null) + $records[]=$record; + else + $records[$record->$index]=$record; + } + } + return $records; + } + protected function instantiate($attributes) + { + $class=get_class($this); + $model=new $class(null); + return $model; + } + public function offsetExists($offset) + { + return $this->__isset($offset); + } +} +class CBaseActiveRelation extends CComponent +{ + public $name; + public $className; + public $foreignKey; + public $select='*'; + public $condition=''; + public $params=array(); + public $group=''; + public $join=''; + public $having=''; + public $order=''; + public function __construct($name,$className,$foreignKey,$options=array()) + { + $this->name=$name; + $this->className=$className; + $this->foreignKey=$foreignKey; + foreach($options as $name=>$value) + $this->$name=$value; + } + public function mergeWith($criteria,$fromScope=false) + { + if($criteria instanceof CDbCriteria) + $criteria=$criteria->toArray(); + if(isset($criteria['select']) && $this->select!==$criteria['select']) + { + if($this->select==='*') + $this->select=$criteria['select']; + else if($criteria['select']!=='*') + { + $select1=is_string($this->select)?preg_split('/\s*,\s*/',trim($this->select),-1,PREG_SPLIT_NO_EMPTY):$this->select; + $select2=is_string($criteria['select'])?preg_split('/\s*,\s*/',trim($criteria['select']),-1,PREG_SPLIT_NO_EMPTY):$criteria['select']; + $this->select=array_merge($select1,array_diff($select2,$select1)); + } + } + if(isset($criteria['condition']) && $this->condition!==$criteria['condition']) + { + if($this->condition==='') + $this->condition=$criteria['condition']; + else if($criteria['condition']!=='') + $this->condition="({$this->condition}) AND ({$criteria['condition']})"; + } + if(isset($criteria['params']) && $this->params!==$criteria['params']) + $this->params=array_merge($this->params,$criteria['params']); + if(isset($criteria['order']) && $this->order!==$criteria['order']) + { + if($this->order==='') + $this->order=$criteria['order']; + else if($criteria['order']!=='') + $this->order=$criteria['order'].', '.$this->order; + } + if(isset($criteria['group']) && $this->group!==$criteria['group']) + { + if($this->group==='') + $this->group=$criteria['group']; + else if($criteria['group']!=='') + $this->group.=', '.$criteria['group']; + } + if(isset($criteria['join']) && $this->join!==$criteria['join']) + { + if($this->join==='') + $this->join=$criteria['join']; + else if($criteria['join']!=='') + $this->join.=' '.$criteria['join']; + } + if(isset($criteria['having']) && $this->having!==$criteria['having']) + { + if($this->having==='') + $this->having=$criteria['having']; + else if($criteria['having']!=='') + $this->having="({$this->having}) AND ({$criteria['having']})"; + } + } +} +class CStatRelation extends CBaseActiveRelation +{ + public $select='COUNT(*)'; + public $defaultValue=0; + public function mergeWith($criteria,$fromScope=false) + { + if($criteria instanceof CDbCriteria) + $criteria=$criteria->toArray(); + parent::mergeWith($criteria,$fromScope); + if(isset($criteria['defaultValue'])) + $this->defaultValue=$criteria['defaultValue']; + } +} +class CActiveRelation extends CBaseActiveRelation +{ + public $joinType='LEFT OUTER JOIN'; + public $on=''; + public $alias; + public $with=array(); + public $together; + public $scopes; + public function mergeWith($criteria,$fromScope=false) + { + if($criteria instanceof CDbCriteria) + $criteria=$criteria->toArray(); + if($fromScope) + { + if(isset($criteria['condition']) && $this->on!==$criteria['condition']) + { + if($this->on==='') + $this->on=$criteria['condition']; + else if($criteria['condition']!=='') + $this->on="({$this->on}) AND ({$criteria['condition']})"; + } + unset($criteria['condition']); + } + parent::mergeWith($criteria); + if(isset($criteria['joinType'])) + $this->joinType=$criteria['joinType']; + if(isset($criteria['on']) && $this->on!==$criteria['on']) + { + if($this->on==='') + $this->on=$criteria['on']; + else if($criteria['on']!=='') + $this->on="({$this->on}) AND ({$criteria['on']})"; + } + if(isset($criteria['with'])) + $this->with=$criteria['with']; + if(isset($criteria['alias'])) + $this->alias=$criteria['alias']; + if(isset($criteria['together'])) + $this->together=$criteria['together']; + } +} +class CBelongsToRelation extends CActiveRelation +{ +} +class CHasOneRelation extends CActiveRelation +{ + public $through; +} +class CHasManyRelation extends CActiveRelation +{ + public $limit=-1; + public $offset=-1; + public $index; + public $through; + public function mergeWith($criteria,$fromScope=false) + { + if($criteria instanceof CDbCriteria) + $criteria=$criteria->toArray(); + parent::mergeWith($criteria,$fromScope); + if(isset($criteria['limit']) && $criteria['limit']>0) + $this->limit=$criteria['limit']; + if(isset($criteria['offset']) && $criteria['offset']>=0) + $this->offset=$criteria['offset']; + if(isset($criteria['index'])) + $this->index=$criteria['index']; + } +} +class CManyManyRelation extends CHasManyRelation +{ +} +class CActiveRecordMetaData +{ + public $tableSchema; + public $columns; + public $relations=array(); + public $attributeDefaults=array(); + private $_model; + public function __construct($model) + { + $this->_model=$model; + $tableName=$model->tableName(); + if(($table=$model->getDbConnection()->getSchema()->getTable($tableName))===null) + throw new CDbException(Yii::t('yii','The table "{table}" for active record class "{class}" cannot be found in the database.', + array('{class}'=>get_class($model),'{table}'=>$tableName))); + if($table->primaryKey===null) + { + $table->primaryKey=$model->primaryKey(); + if(is_string($table->primaryKey) && isset($table->columns[$table->primaryKey])) + $table->columns[$table->primaryKey]->isPrimaryKey=true; + else if(is_array($table->primaryKey)) + { + foreach($table->primaryKey as $name) + { + if(isset($table->columns[$name])) + $table->columns[$name]->isPrimaryKey=true; + } + } + } + $this->tableSchema=$table; + $this->columns=$table->columns; + foreach($table->columns as $name=>$column) + { + if(!$column->isPrimaryKey && $column->defaultValue!==null) + $this->attributeDefaults[$name]=$column->defaultValue; + } + foreach($model->relations() as $name=>$config) + { + $this->addRelation($name,$config); + } + } + public function addRelation($name,$config) + { + if(isset($config[0],$config[1],$config[2])) // relation class, AR class, FK + $this->relations[$name]=new $config[0]($name,$config[1],$config[2],array_slice($config,3)); + else + throw new CDbException(Yii::t('yii','Active record "{class}" has an invalid configuration for relation "{relation}". It must specify the relation type, the related active record class and the foreign key.', array('{class}'=>get_class($this->_model),'{relation}'=>$name))); + } + public function hasRelation($name) + { + return isset($this->relations[$name]); + } + public function removeRelation($name) + { + unset($this->relations[$name]); + } +} +class CDbConnection extends CApplicationComponent +{ + public $connectionString; + public $username=''; + public $password=''; + public $schemaCachingDuration=0; + public $schemaCachingExclude=array(); + public $schemaCacheID='cache'; + public $queryCachingDuration=0; + public $queryCachingDependency; + public $queryCachingCount=0; + public $queryCacheID='cache'; + public $autoConnect=true; + public $charset; + public $emulatePrepare; + public $enableParamLogging=false; + public $enableProfiling=false; + public $tablePrefix; + public $initSQLs; + public $driverMap=array( + 'pgsql'=>'CPgsqlSchema', // PostgreSQL + 'mysqli'=>'CMysqlSchema', // MySQL + 'mysql'=>'CMysqlSchema', // MySQL + 'sqlite'=>'CSqliteSchema', // sqlite 3 + 'sqlite2'=>'CSqliteSchema', // sqlite 2 + 'mssql'=>'CMssqlSchema', // Mssql driver on windows hosts + 'dblib'=>'CMssqlSchema', // dblib drivers on linux (and maybe others os) hosts + 'sqlsrv'=>'CMssqlSchema', // Mssql + 'oci'=>'COciSchema', // Oracle driver + ); + public $pdoClass = 'PDO'; + private $_attributes=array(); + private $_active=false; + private $_pdo; + private $_transaction; + private $_schema; + public function __construct($dsn='',$username='',$password='') + { + $this->connectionString=$dsn; + $this->username=$username; + $this->password=$password; + } + public function __sleep() + { + $this->close(); + return array_keys(get_object_vars($this)); + } + public static function getAvailableDrivers() + { + return PDO::getAvailableDrivers(); + } + public function init() + { + parent::init(); + if($this->autoConnect) + $this->setActive(true); + } + public function getActive() + { + return $this->_active; + } + public function setActive($value) + { + if($value!=$this->_active) + { + if($value) + $this->open(); + else + $this->close(); + } + } + public function cache($duration, $dependency=null, $queryCount=1) + { + $this->queryCachingDuration=$duration; + $this->queryCachingDependency=$dependency; + $this->queryCachingCount=$queryCount; + return $this; + } + protected function open() + { + if($this->_pdo===null) + { + if(empty($this->connectionString)) + throw new CDbException(Yii::t('yii','CDbConnection.connectionString cannot be empty.')); + try + { + $this->_pdo=$this->createPdoInstance(); + $this->initConnection($this->_pdo); + $this->_active=true; + } + catch(PDOException $e) + { + if(YII_DEBUG) + { + throw new CDbException(Yii::t('yii','CDbConnection failed to open the DB connection: {error}', + array('{error}'=>$e->getMessage())),(int)$e->getCode(),$e->errorInfo); + } + else + { + Yii::log($e->getMessage(),CLogger::LEVEL_ERROR,'exception.CDbException'); + throw new CDbException(Yii::t('yii','CDbConnection failed to open the DB connection.'),(int)$e->getCode(),$e->errorInfo); + } + } + } + } + protected function close() + { + $this->_pdo=null; + $this->_active=false; + $this->_schema=null; + } + protected function createPdoInstance() + { + $pdoClass=$this->pdoClass; + if(($pos=strpos($this->connectionString,':'))!==false) + { + $driver=strtolower(substr($this->connectionString,0,$pos)); + if($driver==='mssql' || $driver==='dblib' || $driver==='sqlsrv') + $pdoClass='CMssqlPdoAdapter'; + } + return new $pdoClass($this->connectionString,$this->username, + $this->password,$this->_attributes); + } + protected function initConnection($pdo) + { + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + if($this->emulatePrepare!==null && constant('PDO::ATTR_EMULATE_PREPARES')) + $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,$this->emulatePrepare); + if($this->charset!==null) + { + $driver=strtolower($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)); + if(in_array($driver,array('pgsql','mysql','mysqli'))) + $pdo->exec('SET NAMES '.$pdo->quote($this->charset)); + } + if($this->initSQLs!==null) + { + foreach($this->initSQLs as $sql) + $pdo->exec($sql); + } + } + public function getPdoInstance() + { + return $this->_pdo; + } + public function createCommand($query=null) + { + $this->setActive(true); + return new CDbCommand($this,$query); + } + public function getCurrentTransaction() + { + if($this->_transaction!==null) + { + if($this->_transaction->getActive()) + return $this->_transaction; + } + return null; + } + public function beginTransaction() + { + $this->setActive(true); + $this->_pdo->beginTransaction(); + return $this->_transaction=new CDbTransaction($this); + } + public function getSchema() + { + if($this->_schema!==null) + return $this->_schema; + else + { + $driver=$this->getDriverName(); + if(isset($this->driverMap[$driver])) + return $this->_schema=Yii::createComponent($this->driverMap[$driver], $this); + else + throw new CDbException(Yii::t('yii','CDbConnection does not support reading schema for {driver} database.', + array('{driver}'=>$driver))); + } + } + public function getCommandBuilder() + { + return $this->getSchema()->getCommandBuilder(); + } + public function getLastInsertID($sequenceName='') + { + $this->setActive(true); + return $this->_pdo->lastInsertId($sequenceName); + } + public function quoteValue($str) + { + if(is_int($str) || is_float($str)) + return $str; + $this->setActive(true); + if(($value=$this->_pdo->quote($str))!==false) + return $value; + else // the driver doesn't support quote (e.g. oci) + return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'"; + } + public function quoteTableName($name) + { + return $this->getSchema()->quoteTableName($name); + } + public function quoteColumnName($name) + { + return $this->getSchema()->quoteColumnName($name); + } + public function getPdoType($type) + { + static $map=array + ( + 'boolean'=>PDO::PARAM_BOOL, + 'integer'=>PDO::PARAM_INT, + 'string'=>PDO::PARAM_STR, + 'NULL'=>PDO::PARAM_NULL, + ); + return isset($map[$type]) ? $map[$type] : PDO::PARAM_STR; + } + public function getColumnCase() + { + return $this->getAttribute(PDO::ATTR_CASE); + } + public function setColumnCase($value) + { + $this->setAttribute(PDO::ATTR_CASE,$value); + } + public function getNullConversion() + { + return $this->getAttribute(PDO::ATTR_ORACLE_NULLS); + } + public function setNullConversion($value) + { + $this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value); + } + public function getAutoCommit() + { + return $this->getAttribute(PDO::ATTR_AUTOCOMMIT); + } + public function setAutoCommit($value) + { + $this->setAttribute(PDO::ATTR_AUTOCOMMIT,$value); + } + public function getPersistent() + { + return $this->getAttribute(PDO::ATTR_PERSISTENT); + } + public function setPersistent($value) + { + return $this->setAttribute(PDO::ATTR_PERSISTENT,$value); + } + public function getDriverName() + { + if(($pos=strpos($this->connectionString, ':'))!==false) + return strtolower(substr($this->connectionString, 0, $pos)); + // return $this->getAttribute(PDO::ATTR_DRIVER_NAME); + } + public function getClientVersion() + { + return $this->getAttribute(PDO::ATTR_CLIENT_VERSION); + } + public function getConnectionStatus() + { + return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS); + } + public function getPrefetch() + { + return $this->getAttribute(PDO::ATTR_PREFETCH); + } + public function getServerInfo() + { + return $this->getAttribute(PDO::ATTR_SERVER_INFO); + } + public function getServerVersion() + { + return $this->getAttribute(PDO::ATTR_SERVER_VERSION); + } + public function getTimeout() + { + return $this->getAttribute(PDO::ATTR_TIMEOUT); + } + public function getAttribute($name) + { + $this->setActive(true); + return $this->_pdo->getAttribute($name); + } + public function setAttribute($name,$value) + { + if($this->_pdo instanceof PDO) + $this->_pdo->setAttribute($name,$value); + else + $this->_attributes[$name]=$value; + } + public function getAttributes() + { + return $this->_attributes; + } + public function setAttributes($values) + { + foreach($values as $name=>$value) + $this->_attributes[$name]=$value; + } + public function getStats() + { + $logger=Yii::getLogger(); + $timings=$logger->getProfilingResults(null,'system.db.CDbCommand.query'); + $count=count($timings); + $time=array_sum($timings); + $timings=$logger->getProfilingResults(null,'system.db.CDbCommand.execute'); + $count+=count($timings); + $time+=array_sum($timings); + return array($count,$time); + } +} +abstract class CDbSchema extends CComponent +{ + public $columnTypes=array(); + private $_tableNames=array(); + private $_tables=array(); + private $_connection; + private $_builder; + private $_cacheExclude=array(); + abstract protected function loadTable($name); + public function __construct($conn) + { + $this->_connection=$conn; + foreach($conn->schemaCachingExclude as $name) + $this->_cacheExclude[$name]=true; + } + public function getDbConnection() + { + return $this->_connection; + } + public function getTable($name,$refresh=false) + { + if($refresh===false && isset($this->_tables[$name])) + return $this->_tables[$name]; + else + { + if($this->_connection->tablePrefix!==null && strpos($name,'{{')!==false) + $realName=preg_replace('/\{\{(.*?)\}\}/',$this->_connection->tablePrefix.'$1',$name); + else + $realName=$name; + // temporarily disable query caching + if($this->_connection->queryCachingDuration>0) + { + $qcDuration=$this->_connection->queryCachingDuration; + $this->_connection->queryCachingDuration=0; + } + if(!isset($this->_cacheExclude[$name]) && ($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null) + { + $key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name; + $table=$cache->get($key); + if($refresh===true || $table===false) + { + $table=$this->loadTable($realName); + if($table!==null) + $cache->set($key,$table,$duration); + } + $this->_tables[$name]=$table; + } + else + $this->_tables[$name]=$table=$this->loadTable($realName); + if(isset($qcDuration)) // re-enable query caching + $this->_connection->queryCachingDuration=$qcDuration; + return $table; + } + } + public function getTables($schema='') + { + $tables=array(); + foreach($this->getTableNames($schema) as $name) + { + if(($table=$this->getTable($name))!==null) + $tables[$name]=$table; + } + return $tables; + } + public function getTableNames($schema='') + { + if(!isset($this->_tableNames[$schema])) + $this->_tableNames[$schema]=$this->findTableNames($schema); + return $this->_tableNames[$schema]; + } + public function getCommandBuilder() + { + if($this->_builder!==null) + return $this->_builder; + else + return $this->_builder=$this->createCommandBuilder(); + } + public function refresh() + { + if(($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null) + { + foreach(array_keys($this->_tables) as $name) + { + if(!isset($this->_cacheExclude[$name])) + { + $key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name; + $cache->delete($key); + } + } + } + $this->_tables=array(); + $this->_tableNames=array(); + $this->_builder=null; + } + public function quoteTableName($name) + { + if(strpos($name,'.')===false) + return $this->quoteSimpleTableName($name); + $parts=explode('.',$name); + foreach($parts as $i=>$part) + $parts[$i]=$this->quoteSimpleTableName($part); + return implode('.',$parts); + } + public function quoteSimpleTableName($name) + { + return "'".$name."'"; + } + public function quoteColumnName($name) + { + if(($pos=strrpos($name,'.'))!==false) + { + $prefix=$this->quoteTableName(substr($name,0,$pos)).'.'; + $name=substr($name,$pos+1); + } + else + $prefix=''; + return $prefix . ($name==='*' ? $name : $this->quoteSimpleColumnName($name)); + } + public function quoteSimpleColumnName($name) + { + return '"'.$name.'"'; + } + public function compareTableNames($name1,$name2) + { + $name1=str_replace(array('"','`',"'"),'',$name1); + $name2=str_replace(array('"','`',"'"),'',$name2); + if(($pos=strrpos($name1,'.'))!==false) + $name1=substr($name1,$pos+1); + if(($pos=strrpos($name2,'.'))!==false) + $name2=substr($name2,$pos+1); + if($this->_connection->tablePrefix!==null) + { + if(strpos($name1,'{')!==false) + $name1=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name1); + if(strpos($name2,'{')!==false) + $name2=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name2); + } + return $name1===$name2; + } + public function resetSequence($table,$value=null) + { + } + public function checkIntegrity($check=true,$schema='') + { + } + protected function createCommandBuilder() + { + return new CDbCommandBuilder($this); + } + protected function findTableNames($schema='') + { + throw new CDbException(Yii::t('yii','{class} does not support fetching all table names.', + array('{class}'=>get_class($this)))); + } + public function getColumnType($type) + { + if(isset($this->columnTypes[$type])) + return $this->columnTypes[$type]; + else if(($pos=strpos($type,' '))!==false) + { + $t=substr($type,0,$pos); + return (isset($this->columnTypes[$t]) ? $this->columnTypes[$t] : $t).substr($type,$pos); + } + else + return $type; + } + public function createTable($table, $columns, $options=null) + { + $cols=array(); + foreach($columns as $name=>$type) + { + if(is_string($name)) + $cols[]="\t".$this->quoteColumnName($name).' '.$this->getColumnType($type); + else + $cols[]="\t".$type; + } + $sql="CREATE TABLE ".$this->quoteTableName($table)." (\n".implode(",\n",$cols)."\n)"; + return $options===null ? $sql : $sql.' '.$options; + } + public function renameTable($table, $newName) + { + return 'RENAME TABLE ' . $this->quoteTableName($table) . ' TO ' . $this->quoteTableName($newName); + } + public function dropTable($table) + { + return "DROP TABLE ".$this->quoteTableName($table); + } + public function truncateTable($table) + { + return "TRUNCATE TABLE ".$this->quoteTableName($table); + } + public function addColumn($table, $column, $type) + { + return 'ALTER TABLE ' . $this->quoteTableName($table) + . ' ADD ' . $this->quoteColumnName($column) . ' ' + . $this->getColumnType($type); + } + public function dropColumn($table, $column) + { + return "ALTER TABLE ".$this->quoteTableName($table) + ." DROP COLUMN ".$this->quoteColumnName($column); + } + public function renameColumn($table, $name, $newName) + { + return "ALTER TABLE ".$this->quoteTableName($table) + . " RENAME COLUMN ".$this->quoteColumnName($name) + . " TO ".$this->quoteColumnName($newName); + } + public function alterColumn($table, $column, $type) + { + return 'ALTER TABLE ' . $this->quoteTableName($table) . ' CHANGE ' + . $this->quoteColumnName($column) . ' ' + . $this->quoteColumnName($column) . ' ' + . $this->getColumnType($type); + } + public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null) + { + $columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY); + foreach($columns as $i=>$col) + $columns[$i]=$this->quoteColumnName($col); + $refColumns=preg_split('/\s*,\s*/',$refColumns,-1,PREG_SPLIT_NO_EMPTY); + foreach($refColumns as $i=>$col) + $refColumns[$i]=$this->quoteColumnName($col); + $sql='ALTER TABLE '.$this->quoteTableName($table) + .' ADD CONSTRAINT '.$this->quoteColumnName($name) + .' FOREIGN KEY ('.implode(', ', $columns).')' + .' REFERENCES '.$this->quoteTableName($refTable) + .' ('.implode(', ', $refColumns).')'; + if($delete!==null) + $sql.=' ON DELETE '.$delete; + if($update!==null) + $sql.=' ON UPDATE '.$update; + return $sql; + } + public function dropForeignKey($name, $table) + { + return 'ALTER TABLE '.$this->quoteTableName($table) + .' DROP CONSTRAINT '.$this->quoteColumnName($name); + } + public function createIndex($name, $table, $column, $unique=false) + { + $cols=array(); + $columns=preg_split('/\s*,\s*/',$column,-1,PREG_SPLIT_NO_EMPTY); + foreach($columns as $col) + { + if(strpos($col,'(')!==false) + $cols[]=$col; + else + $cols[]=$this->quoteColumnName($col); + } + return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ') + . $this->quoteTableName($name).' ON ' + . $this->quoteTableName($table).' ('.implode(', ',$cols).')'; + } + public function dropIndex($name, $table) + { + return 'DROP INDEX '.$this->quoteTableName($name).' ON '.$this->quoteTableName($table); + } +} +class CSqliteSchema extends CDbSchema +{ + public $columnTypes=array( + 'pk' => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL', + 'string' => 'varchar(255)', + 'text' => 'text', + 'integer' => 'integer', + 'float' => 'float', + 'decimal' => 'decimal', + 'datetime' => 'datetime', + 'timestamp' => 'timestamp', + 'time' => 'time', + 'date' => 'date', + 'binary' => 'blob', + 'boolean' => 'tinyint(1)', + 'money' => 'decimal(19,4)', + ); + public function resetSequence($table,$value=null) + { + if($table->sequenceName!==null) + { + if($value===null) + $value=$this->getDbConnection()->createCommand("SELECT MAX(`{$table->primaryKey}`) FROM {$table->rawName}")->queryScalar(); + else + $value=(int)$value-1; + try + { + // it's possible sqlite_sequence does not exist + $this->getDbConnection()->createCommand("UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->name}'")->execute(); + } + catch(Exception $e) + { + } + } + } + public function checkIntegrity($check=true,$schema='') + { + // SQLite doesn't enforce integrity + return; + } + protected function findTableNames($schema='') + { + $sql="SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'"; + return $this->getDbConnection()->createCommand($sql)->queryColumn(); + } + protected function createCommandBuilder() + { + return new CSqliteCommandBuilder($this); + } + protected function loadTable($name) + { + $table=new CDbTableSchema; + $table->name=$name; + $table->rawName=$this->quoteTableName($name); + if($this->findColumns($table)) + { + $this->findConstraints($table); + return $table; + } + else + return null; + } + protected function findColumns($table) + { + $sql="PRAGMA table_info({$table->rawName})"; + $columns=$this->getDbConnection()->createCommand($sql)->queryAll(); + if(empty($columns)) + return false; + foreach($columns as $column) + { + $c=$this->createColumn($column); + $table->columns[$c->name]=$c; + if($c->isPrimaryKey) + { + if($table->primaryKey===null) + $table->primaryKey=$c->name; + else if(is_string($table->primaryKey)) + $table->primaryKey=array($table->primaryKey,$c->name); + else + $table->primaryKey[]=$c->name; + } + } + if(is_string($table->primaryKey) && !strncasecmp($table->columns[$table->primaryKey]->dbType,'int',3)) + { + $table->sequenceName=''; + $table->columns[$table->primaryKey]->autoIncrement=true; + } + return true; + } + protected function findConstraints($table) + { + $foreignKeys=array(); + $sql="PRAGMA foreign_key_list({$table->rawName})"; + $keys=$this->getDbConnection()->createCommand($sql)->queryAll(); + foreach($keys as $key) + { + $column=$table->columns[$key['from']]; + $column->isForeignKey=true; + $foreignKeys[$key['from']]=array($key['table'],$key['to']); + } + $table->foreignKeys=$foreignKeys; + } + protected function createColumn($column) + { + $c=new CSqliteColumnSchema; + $c->name=$column['name']; + $c->rawName=$this->quoteColumnName($c->name); + $c->allowNull=!$column['notnull']; + $c->isPrimaryKey=$column['pk']!=0; + $c->isForeignKey=false; + $c->init(strtolower($column['type']),$column['dflt_value']); + return $c; + } + public function truncateTable($table) + { + return "DELETE FROM ".$this->quoteTableName($table); + } + public function dropColumn($table, $column) + { + throw new CDbException(Yii::t('yii', 'Dropping DB column is not supported by SQLite.')); + } + public function renameColumn($table, $name, $newName) + { + throw new CDbException(Yii::t('yii', 'Renaming a DB column is not supported by SQLite.')); + } + public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null) + { + throw new CDbException(Yii::t('yii', 'Adding a foreign key constraint to an existing table is not supported by SQLite.')); + } + public function dropForeignKey($name, $table) + { + throw new CDbException(Yii::t('yii', 'Dropping a foreign key constraint is not supported by SQLite.')); + } + public function alterColumn($table, $column, $type) + { + throw new CDbException(Yii::t('yii', 'Altering a DB column is not supported by SQLite.')); + } + public function dropIndex($name, $table) + { + return 'DROP INDEX '.$this->quoteTableName($name); + } +} +class CDbTableSchema extends CComponent +{ + public $name; + public $rawName; + public $primaryKey; + public $sequenceName; + public $foreignKeys=array(); + public $columns=array(); + public function getColumn($name) + { + return isset($this->columns[$name]) ? $this->columns[$name] : null; + } + public function getColumnNames() + { + return array_keys($this->columns); + } +} +class CDbCommand extends CComponent +{ + public $params=array(); + private $_connection; + private $_text; + private $_statement; + private $_paramLog=array(); + private $_query; + private $_fetchMode = array(PDO::FETCH_ASSOC); + public function __construct(CDbConnection $connection,$query=null) + { + $this->_connection=$connection; + if(is_array($query)) + { + foreach($query as $name=>$value) + $this->$name=$value; + } + else + $this->setText($query); + } + public function __sleep() + { + $this->_statement=null; + return array_keys(get_object_vars($this)); + } + public function setFetchMode($mode) + { + $params=func_get_args(); + $this->_fetchMode = $params; + return $this; + } + public function reset() + { + $this->_text=null; + $this->_query=null; + $this->_statement=null; + $this->_paramLog=array(); + $this->params=array(); + return $this; + } + public function getText() + { + if($this->_text=='' && !empty($this->_query)) + $this->setText($this->buildQuery($this->_query)); + return $this->_text; + } + public function setText($value) + { + if($this->_connection->tablePrefix!==null && $value!='') + $this->_text=preg_replace('/{{(.*?)}}/',$this->_connection->tablePrefix.'\1',$value); + else + $this->_text=$value; + $this->cancel(); + return $this; + } + public function getConnection() + { + return $this->_connection; + } + public function getPdoStatement() + { + return $this->_statement; + } + public function prepare() + { + if($this->_statement==null) + { + try + { + $this->_statement=$this->getConnection()->getPdoInstance()->prepare($this->getText()); + $this->_paramLog=array(); + } + catch(Exception $e) + { + Yii::log('Error in preparing SQL: '.$this->getText(),CLogger::LEVEL_ERROR,'system.db.CDbCommand'); + $errorInfo = $e instanceof PDOException ? $e->errorInfo : null; + throw new CDbException(Yii::t('yii','CDbCommand failed to prepare the SQL statement: {error}', + array('{error}'=>$e->getMessage())),(int)$e->getCode(),$errorInfo); + } + } + } + public function cancel() + { + $this->_statement=null; + } + public function bindParam($name, &$value, $dataType=null, $length=null, $driverOptions=null) + { + $this->prepare(); + if($dataType===null) + $this->_statement->bindParam($name,$value,$this->_connection->getPdoType(gettype($value))); + else if($length===null) + $this->_statement->bindParam($name,$value,$dataType); + else if($driverOptions===null) + $this->_statement->bindParam($name,$value,$dataType,$length); + else + $this->_statement->bindParam($name,$value,$dataType,$length,$driverOptions); + $this->_paramLog[$name]=&$value; + return $this; + } + public function bindValue($name, $value, $dataType=null) + { + $this->prepare(); + if($dataType===null) + $this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value))); + else + $this->_statement->bindValue($name,$value,$dataType); + $this->_paramLog[$name]=$value; + return $this; + } + public function bindValues($values) + { + $this->prepare(); + foreach($values as $name=>$value) + { + $this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value))); + $this->_paramLog[$name]=$value; + } + return $this; + } + public function execute($params=array()) + { + if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array()) + { + $p=array(); + foreach($pars as $name=>$value) + $p[$name]=$name.'='.var_export($value,true); + $par='. Bound with ' .implode(', ',$p); + } + else + $par=''; + try + { + if($this->_connection->enableProfiling) + Yii::beginProfile('system.db.CDbCommand.execute('.$this->getText().')','system.db.CDbCommand.execute'); + $this->prepare(); + if($params===array()) + $this->_statement->execute(); + else + $this->_statement->execute($params); + $n=$this->_statement->rowCount(); + if($this->_connection->enableProfiling) + Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().')','system.db.CDbCommand.execute'); + return $n; + } + catch(Exception $e) + { + if($this->_connection->enableProfiling) + Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().')','system.db.CDbCommand.execute'); + $errorInfo = $e instanceof PDOException ? $e->errorInfo : null; + $message = $e->getMessage(); + Yii::log(Yii::t('yii','CDbCommand::execute() failed: {error}. The SQL statement executed was: {sql}.', + array('{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand'); + if(YII_DEBUG) + $message .= '. The SQL statement executed was: '.$this->getText().$par; + throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}', + array('{error}'=>$message)),(int)$e->getCode(),$errorInfo); + } + } + public function query($params=array()) + { + return $this->queryInternal('',0,$params); + } + public function queryAll($fetchAssociative=true,$params=array()) + { + return $this->queryInternal('fetchAll',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); + } + public function queryRow($fetchAssociative=true,$params=array()) + { + return $this->queryInternal('fetch',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); + } + public function queryScalar($params=array()) + { + $result=$this->queryInternal('fetchColumn',0,$params); + if(is_resource($result) && get_resource_type($result)==='stream') + return stream_get_contents($result); + else + return $result; + } + public function queryColumn($params=array()) + { + return $this->queryInternal('fetchAll',PDO::FETCH_COLUMN,$params); + } + private function queryInternal($method,$mode,$params=array()) + { + $params=array_merge($this->params,$params); + if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array()) + { + $p=array(); + foreach($pars as $name=>$value) + $p[$name]=$name.'='.var_export($value,true); + $par='. Bound with '.implode(', ',$p); + } + else + $par=''; + if($this->_connection->queryCachingCount>0 && $method!=='' + && $this->_connection->queryCachingDuration>0 + && $this->_connection->queryCacheID!==false + && ($cache=Yii::app()->getComponent($this->_connection->queryCacheID))!==null) + { + $this->_connection->queryCachingCount--; + $cacheKey='yii:dbquery'.$this->_connection->connectionString.':'.$this->_connection->username; + $cacheKey.=':'.$this->getText().':'.serialize(array_merge($this->_paramLog,$params)); + if(($result=$cache->get($cacheKey))!==false) + { + return $result; + } + } + try + { + if($this->_connection->enableProfiling) + Yii::beginProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query'); + $this->prepare(); + if($params===array()) + $this->_statement->execute(); + else + $this->_statement->execute($params); + if($method==='') + $result=new CDbDataReader($this); + else + { + $mode=(array)$mode; + $result=call_user_func_array(array($this->_statement, $method), $mode); + $this->_statement->closeCursor(); + } + if($this->_connection->enableProfiling) + Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query'); + if(isset($cache,$cacheKey)) + $cache->set($cacheKey, $result, $this->_connection->queryCachingDuration, $this->_connection->queryCachingDependency); + return $result; + } + catch(Exception $e) + { + if($this->_connection->enableProfiling) + Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query'); + $errorInfo = $e instanceof PDOException ? $e->errorInfo : null; + $message = $e->getMessage(); + Yii::log(Yii::t('yii','CDbCommand::{method}() failed: {error}. The SQL statement executed was: {sql}.', + array('{method}'=>$method, '{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand'); + if(YII_DEBUG) + $message .= '. The SQL statement executed was: '.$this->getText().$par; + throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}', + array('{error}'=>$message)),(int)$e->getCode(),$errorInfo); + } + } + public function buildQuery($query) + { + $sql=isset($query['distinct']) && $query['distinct'] ? 'SELECT DISTINCT' : 'SELECT'; + $sql.=' '.(isset($query['select']) ? $query['select'] : '*'); + if(isset($query['from'])) + $sql.="\nFROM ".$query['from']; + else + throw new CDbException(Yii::t('yii','The DB query must contain the "from" portion.')); + if(isset($query['join'])) + $sql.="\n".(is_array($query['join']) ? implode("\n",$query['join']) : $query['join']); + if(isset($query['where'])) + $sql.="\nWHERE ".$query['where']; + if(isset($query['group'])) + $sql.="\nGROUP BY ".$query['group']; + if(isset($query['having'])) + $sql.="\nHAVING ".$query['having']; + if(isset($query['order'])) + $sql.="\nORDER BY ".$query['order']; + $limit=isset($query['limit']) ? (int)$query['limit'] : -1; + $offset=isset($query['offset']) ? (int)$query['offset'] : -1; + if($limit>=0 || $offset>0) + $sql=$this->_connection->getCommandBuilder()->applyLimit($sql,$limit,$offset); + if(isset($query['union'])) + $sql.="\nUNION (\n".(is_array($query['union']) ? implode("\n) UNION (\n",$query['union']) : $query['union']) . ')'; + return $sql; + } + public function select($columns='*', $option='') + { + if(is_string($columns) && strpos($columns,'(')!==false) + $this->_query['select']=$columns; + else + { + if(!is_array($columns)) + $columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY); + foreach($columns as $i=>$column) + { + if(is_object($column)) + $columns[$i]=(string)$column; + else if(strpos($column,'(')===false) + { + if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$column,$matches)) + $columns[$i]=$this->_connection->quoteColumnName($matches[1]).' AS '.$this->_connection->quoteColumnName($matches[2]); + else + $columns[$i]=$this->_connection->quoteColumnName($column); + } + } + $this->_query['select']=implode(', ',$columns); + } + if($option!='') + $this->_query['select']=$option.' '.$this->_query['select']; + return $this; + } + public function getSelect() + { + return isset($this->_query['select']) ? $this->_query['select'] : ''; + } + public function setSelect($value) + { + $this->select($value); + } + public function selectDistinct($columns='*') + { + $this->_query['distinct']=true; + return $this->select($columns); + } + public function getDistinct() + { + return isset($this->_query['distinct']) ? $this->_query['distinct'] : false; + } + public function setDistinct($value) + { + $this->_query['distinct']=$value; + } + public function from($tables) + { + if(is_string($tables) && strpos($tables,'(')!==false) + $this->_query['from']=$tables; + else + { + if(!is_array($tables)) + $tables=preg_split('/\s*,\s*/',trim($tables),-1,PREG_SPLIT_NO_EMPTY); + foreach($tables as $i=>$table) + { + if(strpos($table,'(')===false) + { + if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$table,$matches)) // with alias + $tables[$i]=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]); + else + $tables[$i]=$this->_connection->quoteTableName($table); + } + } + $this->_query['from']=implode(', ',$tables); + } + return $this; + } + public function getFrom() + { + return isset($this->_query['from']) ? $this->_query['from'] : ''; + } + public function setFrom($value) + { + $this->from($value); + } + public function where($conditions, $params=array()) + { + $this->_query['where']=$this->processConditions($conditions); + foreach($params as $name=>$value) + $this->params[$name]=$value; + return $this; + } + public function getWhere() + { + return isset($this->_query['where']) ? $this->_query['where'] : ''; + } + public function setWhere($value) + { + $this->where($value); + } + public function join($table, $conditions, $params=array()) + { + return $this->joinInternal('join', $table, $conditions, $params); + } + public function getJoin() + { + return isset($this->_query['join']) ? $this->_query['join'] : ''; + } + public function setJoin($value) + { + $this->_query['join']=$value; + } + public function leftJoin($table, $conditions, $params=array()) + { + return $this->joinInternal('left join', $table, $conditions, $params); + } + public function rightJoin($table, $conditions, $params=array()) + { + return $this->joinInternal('right join', $table, $conditions, $params); + } + public function crossJoin($table) + { + return $this->joinInternal('cross join', $table); + } + public function naturalJoin($table) + { + return $this->joinInternal('natural join', $table); + } + public function group($columns) + { + if(is_string($columns) && strpos($columns,'(')!==false) + $this->_query['group']=$columns; + else + { + if(!is_array($columns)) + $columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY); + foreach($columns as $i=>$column) + { + if(is_object($column)) + $columns[$i]=(string)$column; + else if(strpos($column,'(')===false) + $columns[$i]=$this->_connection->quoteColumnName($column); + } + $this->_query['group']=implode(', ',$columns); + } + return $this; + } + public function getGroup() + { + return isset($this->_query['group']) ? $this->_query['group'] : ''; + } + public function setGroup($value) + { + $this->group($value); + } + public function having($conditions, $params=array()) + { + $this->_query['having']=$this->processConditions($conditions); + foreach($params as $name=>$value) + $this->params[$name]=$value; + return $this; + } + public function getHaving() + { + return isset($this->_query['having']) ? $this->_query['having'] : ''; + } + public function setHaving($value) + { + $this->having($value); + } + public function order($columns) + { + if(is_string($columns) && strpos($columns,'(')!==false) + $this->_query['order']=$columns; + else + { + if(!is_array($columns)) + $columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY); + foreach($columns as $i=>$column) + { + if(is_object($column)) + $columns[$i]=(string)$column; + else if(strpos($column,'(')===false) + { + if(preg_match('/^(.*?)\s+(asc|desc)$/i',$column,$matches)) + $columns[$i]=$this->_connection->quoteColumnName($matches[1]).' '.strtoupper($matches[2]); + else + $columns[$i]=$this->_connection->quoteColumnName($column); + } + } + $this->_query['order']=implode(', ',$columns); + } + return $this; + } + public function getOrder() + { + return isset($this->_query['order']) ? $this->_query['order'] : ''; + } + public function setOrder($value) + { + $this->order($value); + } + public function limit($limit, $offset=null) + { + $this->_query['limit']=(int)$limit; + if($offset!==null) + $this->offset($offset); + return $this; + } + public function getLimit() + { + return isset($this->_query['limit']) ? $this->_query['limit'] : -1; + } + public function setLimit($value) + { + $this->limit($value); + } + public function offset($offset) + { + $this->_query['offset']=(int)$offset; + return $this; + } + public function getOffset() + { + return isset($this->_query['offset']) ? $this->_query['offset'] : -1; + } + public function setOffset($value) + { + $this->offset($value); + } + public function union($sql) + { + if(isset($this->_query['union']) && is_string($this->_query['union'])) + $this->_query['union']=array($this->_query['union']); + $this->_query['union'][]=$sql; + return $this; + } + public function getUnion() + { + return isset($this->_query['union']) ? $this->_query['union'] : ''; + } + public function setUnion($value) + { + $this->_query['union']=$value; + } + public function insert($table, $columns) + { + $params=array(); + $names=array(); + $placeholders=array(); + foreach($columns as $name=>$value) + { + $names[]=$this->_connection->quoteColumnName($name); + if($value instanceof CDbExpression) + { + $placeholders[] = $value->expression; + foreach($value->params as $n => $v) + $params[$n] = $v; + } + else + { + $placeholders[] = ':' . $name; + $params[':' . $name] = $value; + } + } + $sql='INSERT INTO ' . $this->_connection->quoteTableName($table) + . ' (' . implode(', ',$names) . ') VALUES (' + . implode(', ', $placeholders) . ')'; + return $this->setText($sql)->execute($params); + } + public function update($table, $columns, $conditions='', $params=array()) + { + $lines=array(); + foreach($columns as $name=>$value) + { + if($value instanceof CDbExpression) + { + $lines[]=$this->_connection->quoteColumnName($name) . '=' . $value->expression; + foreach($value->params as $n => $v) + $params[$n] = $v; + } + else + { + $lines[]=$this->_connection->quoteColumnName($name) . '=:' . $name; + $params[':' . $name]=$value; + } + } + $sql='UPDATE ' . $this->_connection->quoteTableName($table) . ' SET ' . implode(', ', $lines); + if(($where=$this->processConditions($conditions))!='') + $sql.=' WHERE '.$where; + return $this->setText($sql)->execute($params); + } + public function delete($table, $conditions='', $params=array()) + { + $sql='DELETE FROM ' . $this->_connection->quoteTableName($table); + if(($where=$this->processConditions($conditions))!='') + $sql.=' WHERE '.$where; + return $this->setText($sql)->execute($params); + } + public function createTable($table, $columns, $options=null) + { + return $this->setText($this->getConnection()->getSchema()->createTable($table, $columns, $options))->execute(); + } + public function renameTable($table, $newName) + { + return $this->setText($this->getConnection()->getSchema()->renameTable($table, $newName))->execute(); + } + public function dropTable($table) + { + return $this->setText($this->getConnection()->getSchema()->dropTable($table))->execute(); + } + public function truncateTable($table) + { + $schema=$this->getConnection()->getSchema(); + $n=$this->setText($schema->truncateTable($table))->execute(); + if(strncasecmp($this->getConnection()->getDriverName(),'sqlite',6)===0) + $schema->resetSequence($schema->getTable($table)); + return $n; + } + public function addColumn($table, $column, $type) + { + return $this->setText($this->getConnection()->getSchema()->addColumn($table, $column, $type))->execute(); + } + public function dropColumn($table, $column) + { + return $this->setText($this->getConnection()->getSchema()->dropColumn($table, $column))->execute(); + } + public function renameColumn($table, $name, $newName) + { + return $this->setText($this->getConnection()->getSchema()->renameColumn($table, $name, $newName))->execute(); + } + public function alterColumn($table, $column, $type) + { + return $this->setText($this->getConnection()->getSchema()->alterColumn($table, $column, $type))->execute(); + } + public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null) + { + return $this->setText($this->getConnection()->getSchema()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update))->execute(); + } + public function dropForeignKey($name, $table) + { + return $this->setText($this->getConnection()->getSchema()->dropForeignKey($name, $table))->execute(); + } + public function createIndex($name, $table, $column, $unique=false) + { + return $this->setText($this->getConnection()->getSchema()->createIndex($name, $table, $column, $unique))->execute(); + } + public function dropIndex($name, $table) + { + return $this->setText($this->getConnection()->getSchema()->dropIndex($name, $table))->execute(); + } + private function processConditions($conditions) + { + if(!is_array($conditions)) + return $conditions; + else if($conditions===array()) + return ''; + $n=count($conditions); + $operator=strtoupper($conditions[0]); + if($operator==='OR' || $operator==='AND') + { + $parts=array(); + for($i=1;$i<$n;++$i) + { + $condition=$this->processConditions($conditions[$i]); + if($condition!=='') + $parts[]='('.$condition.')'; + } + return $parts===array() ? '' : implode(' '.$operator.' ', $parts); + } + if(!isset($conditions[1],$conditions[2])) + return ''; + $column=$conditions[1]; + if(strpos($column,'(')===false) + $column=$this->_connection->quoteColumnName($column); + $values=$conditions[2]; + if(!is_array($values)) + $values=array($values); + if($operator==='IN' || $operator==='NOT IN') + { + if($values===array()) + return $operator==='IN' ? '0=1' : ''; + foreach($values as $i=>$value) + { + if(is_string($value)) + $values[$i]=$this->_connection->quoteValue($value); + else + $values[$i]=(string)$value; + } + return $column.' '.$operator.' ('.implode(', ',$values).')'; + } + if($operator==='LIKE' || $operator==='NOT LIKE' || $operator==='OR LIKE' || $operator==='OR NOT LIKE') + { + if($values===array()) + return $operator==='LIKE' || $operator==='OR LIKE' ? '0=1' : ''; + if($operator==='LIKE' || $operator==='NOT LIKE') + $andor=' AND '; + else + { + $andor=' OR '; + $operator=$operator==='OR LIKE' ? 'LIKE' : 'NOT LIKE'; + } + $expressions=array(); + foreach($values as $value) + $expressions[]=$column.' '.$operator.' '.$this->_connection->quoteValue($value); + return implode($andor,$expressions); + } + throw new CDbException(Yii::t('yii', 'Unknown operator "{operator}".', array('{operator}'=>$operator))); + } + private function joinInternal($type, $table, $conditions='', $params=array()) + { + if(strpos($table,'(')===false) + { + if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$table,$matches)) // with alias + $table=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]); + else + $table=$this->_connection->quoteTableName($table); + } + $conditions=$this->processConditions($conditions); + if($conditions!='') + $conditions=' ON '.$conditions; + if(isset($this->_query['join']) && is_string($this->_query['join'])) + $this->_query['join']=array($this->_query['join']); + $this->_query['join'][]=strtoupper($type) . ' ' . $table . $conditions; + foreach($params as $name=>$value) + $this->params[$name]=$value; + return $this; + } +} +class CDbColumnSchema extends CComponent +{ + public $name; + public $rawName; + public $allowNull; + public $dbType; + public $type; + public $defaultValue; + public $size; + public $precision; + public $scale; + public $isPrimaryKey; + public $isForeignKey; + public $autoIncrement=false; + public function init($dbType, $defaultValue) + { + $this->dbType=$dbType; + $this->extractType($dbType); + $this->extractLimit($dbType); + if($defaultValue!==null) + $this->extractDefault($defaultValue); + } + protected function extractType($dbType) + { + if(stripos($dbType,'int')!==false && stripos($dbType,'unsigned int')===false) + $this->type='integer'; + else if(stripos($dbType,'bool')!==false) + $this->type='boolean'; + else if(preg_match('/(real|floa|doub)/i',$dbType)) + $this->type='double'; + else + $this->type='string'; + } + protected function extractLimit($dbType) + { + if(strpos($dbType,'(') && preg_match('/\((.*)\)/',$dbType,$matches)) + { + $values=explode(',',$matches[1]); + $this->size=$this->precision=(int)$values[0]; + if(isset($values[1])) + $this->scale=(int)$values[1]; + } + } + protected function extractDefault($defaultValue) + { + $this->defaultValue=$this->typecast($defaultValue); + } + public function typecast($value) + { + if(gettype($value)===$this->type || $value===null || $value instanceof CDbExpression) + return $value; + if($value==='' && $this->allowNull) + return $this->type==='string' ? '' : null; + switch($this->type) + { + case 'string': return (string)$value; + case 'integer': return (integer)$value; + case 'boolean': return (boolean)$value; + case 'double': + default: return $value; + } + } +} +class CSqliteColumnSchema extends CDbColumnSchema +{ + protected function extractDefault($defaultValue) + { + if($this->type==='string') // PHP 5.2.6 adds single quotes while 5.2.0 doesn't + $this->defaultValue=trim($defaultValue,"'\""); + else + $this->defaultValue=$this->typecast(strcasecmp($defaultValue,'null') ? $defaultValue : null); + } +} +abstract class CValidator extends CComponent +{ + public static $builtInValidators=array( + 'required'=>'CRequiredValidator', + 'filter'=>'CFilterValidator', + 'match'=>'CRegularExpressionValidator', + 'email'=>'CEmailValidator', + 'url'=>'CUrlValidator', + 'unique'=>'CUniqueValidator', + 'compare'=>'CCompareValidator', + 'length'=>'CStringValidator', + 'in'=>'CRangeValidator', + 'numerical'=>'CNumberValidator', + 'captcha'=>'CCaptchaValidator', + 'type'=>'CTypeValidator', + 'file'=>'CFileValidator', + 'default'=>'CDefaultValueValidator', + 'exist'=>'CExistValidator', + 'boolean'=>'CBooleanValidator', + 'safe'=>'CSafeValidator', + 'unsafe'=>'CUnsafeValidator', + 'date'=>'CDateValidator', + ); + public $attributes; + public $message; + public $skipOnError=false; + public $on; + public $safe=true; + public $enableClientValidation=true; + abstract protected function validateAttribute($object,$attribute); + public static function createValidator($name,$object,$attributes,$params=array()) + { + if(is_string($attributes)) + $attributes=preg_split('/[\s,]+/',$attributes,-1,PREG_SPLIT_NO_EMPTY); + if(isset($params['on'])) + { + if(is_array($params['on'])) + $on=$params['on']; + else + $on=preg_split('/[\s,]+/',$params['on'],-1,PREG_SPLIT_NO_EMPTY); + } + else + $on=array(); + if(method_exists($object,$name)) + { + $validator=new CInlineValidator; + $validator->attributes=$attributes; + $validator->method=$name; + if(isset($params['clientValidate'])) + { + $validator->clientValidate=$params['clientValidate']; + unset($params['clientValidate']); + } + $validator->params=$params; + if(isset($params['skipOnError'])) + $validator->skipOnError=$params['skipOnError']; + } + else + { + $params['attributes']=$attributes; + if(isset(self::$builtInValidators[$name])) + $className=Yii::import(self::$builtInValidators[$name],true); + else + $className=Yii::import($name,true); + $validator=new $className; + foreach($params as $name=>$value) + $validator->$name=$value; + } + $validator->on=empty($on) ? array() : array_combine($on,$on); + return $validator; + } + public function validate($object,$attributes=null) + { + if(is_array($attributes)) + $attributes=array_intersect($this->attributes,$attributes); + else + $attributes=$this->attributes; + foreach($attributes as $attribute) + { + if(!$this->skipOnError || !$object->hasErrors($attribute)) + $this->validateAttribute($object,$attribute); + } + } + public function clientValidateAttribute($object,$attribute) + { + } + public function applyTo($scenario) + { + return empty($this->on) || isset($this->on[$scenario]); + } + protected function addError($object,$attribute,$message,$params=array()) + { + $params['{attribute}']=$object->getAttributeLabel($attribute); + $object->addError($attribute,strtr($message,$params)); + } + protected function isEmpty($value,$trim=false) + { + return $value===null || $value===array() || $value==='' || $trim && is_scalar($value) && trim($value)===''; + } +} +class CStringValidator extends CValidator +{ + public $max; + public $min; + public $is; + public $tooShort; + public $tooLong; + public $allowEmpty=true; + public $encoding; + protected function validateAttribute($object,$attribute) + { + $value=$object->$attribute; + if($this->allowEmpty && $this->isEmpty($value)) + return; + if(function_exists('mb_strlen') && $this->encoding!==false) + $length=mb_strlen($value, $this->encoding ? $this->encoding : Yii::app()->charset); + else + $length=strlen($value); + if($this->min!==null && $length<$this->min) + { + $message=$this->tooShort!==null?$this->tooShort:Yii::t('yii','{attribute} is too short (minimum is {min} characters).'); + $this->addError($object,$attribute,$message,array('{min}'=>$this->min)); + } + if($this->max!==null && $length>$this->max) + { + $message=$this->tooLong!==null?$this->tooLong:Yii::t('yii','{attribute} is too long (maximum is {max} characters).'); + $this->addError($object,$attribute,$message,array('{max}'=>$this->max)); + } + if($this->is!==null && $length!==$this->is) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).'); + $this->addError($object,$attribute,$message,array('{length}'=>$this->is)); + } + } + public function clientValidateAttribute($object,$attribute) + { + $label=$object->getAttributeLabel($attribute); + if(($message=$this->message)===null) + $message=Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).'); + $message=strtr($message, array( + '{attribute}'=>$label, + '{length}'=>$this->is, + )); + if(($tooShort=$this->tooShort)===null) + $tooShort=Yii::t('yii','{attribute} is too short (minimum is {min} characters).'); + $tooShort=strtr($tooShort, array( + '{attribute}'=>$label, + '{min}'=>$this->min, + )); + if(($tooLong=$this->tooLong)===null) + $tooLong=Yii::t('yii','{attribute} is too long (maximum is {max} characters).'); + $tooLong=strtr($tooLong, array( + '{attribute}'=>$label, + '{max}'=>$this->max, + )); + $js=''; + if($this->min!==null) + { + $js.=" +if(value.length<{$this->min}) { + messages.push(".CJSON::encode($tooShort)."); +} +"; + } + if($this->max!==null) + { + $js.=" +if(value.length>{$this->max}) { + messages.push(".CJSON::encode($tooLong)."); +} +"; + } + if($this->is!==null) + { + $js.=" +if(value.length!={$this->is}) { + messages.push(".CJSON::encode($message)."); +} +"; + } + if($this->allowEmpty) + { + $js=" +if($.trim(value)!='') { + $js +} +"; + } + return $js; + } +} +class CRequiredValidator extends CValidator +{ + public $requiredValue; + public $strict=false; + protected function validateAttribute($object,$attribute) + { + $value=$object->$attribute; + if($this->requiredValue!==null) + { + if(!$this->strict && $value!=$this->requiredValue || $this->strict && $value!==$this->requiredValue) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be {value}.', + array('{value}'=>$this->requiredValue)); + $this->addError($object,$attribute,$message); + } + } + else if($this->isEmpty($value,true)) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} cannot be blank.'); + $this->addError($object,$attribute,$message); + } + } + public function clientValidateAttribute($object,$attribute) + { + $message=$this->message; + if($this->requiredValue!==null) + { + if($message===null) + $message=Yii::t('yii','{attribute} must be {value}.'); + $message=strtr($message, array( + '{value}'=>$this->requiredValue, + '{attribute}'=>$object->getAttributeLabel($attribute), + )); + return " +if(value!=" . CJSON::encode($this->requiredValue) . ") { + messages.push(".CJSON::encode($message)."); +} +"; + } + else + { + if($message===null) + $message=Yii::t('yii','{attribute} cannot be blank.'); + $message=strtr($message, array( + '{attribute}'=>$object->getAttributeLabel($attribute), + )); + return " +if($.trim(value)=='') { + messages.push(".CJSON::encode($message)."); +} +"; + } + } +} +class CNumberValidator extends CValidator +{ + public $integerOnly=false; + public $allowEmpty=true; + public $max; + public $min; + public $tooBig; + public $tooSmall; + public $integerPattern='/^\s*[+-]?\d+\s*$/'; + public $numberPattern='/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/'; + protected function validateAttribute($object,$attribute) + { + $value=$object->$attribute; + if($this->allowEmpty && $this->isEmpty($value)) + return; + if($this->integerOnly) + { + if(!preg_match($this->integerPattern,"$value")) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be an integer.'); + $this->addError($object,$attribute,$message); + } + } + else + { + if(!preg_match($this->numberPattern,"$value")) + { + $message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be a number.'); + $this->addError($object,$attribute,$message); + } + } + if($this->min!==null && $value<$this->min) + { + $message=$this->tooSmall!==null?$this->tooSmall:Yii::t('yii','{attribute} is too small (minimum is {min}).'); + $this->addError($object,$attribute,$message,array('{min}'=>$this->min)); + } + if($this->max!==null && $value>$this->max) + { + $message=$this->tooBig!==null?$this->tooBig:Yii::t('yii','{attribute} is too big (maximum is {max}).'); + $this->addError($object,$attribute,$message,array('{max}'=>$this->max)); + } + } + public function clientValidateAttribute($object,$attribute) + { + $label=$object->getAttributeLabel($attribute); + if(($message=$this->message)===null) + $message=$this->integerOnly ? Yii::t('yii','{attribute} must be an integer.') : Yii::t('yii','{attribute} must be a number.'); + $message=strtr($message, array( + '{attribute}'=>$label, + )); + if(($tooBig=$this->tooBig)===null) + $tooBig=Yii::t('yii','{attribute} is too big (maximum is {max}).'); + $tooBig=strtr($tooBig, array( + '{attribute}'=>$label, + '{max}'=>$this->max, + )); + if(($tooSmall=$this->tooSmall)===null) + $tooSmall=Yii::t('yii','{attribute} is too small (minimum is {min}).'); + $tooSmall=strtr($tooSmall, array( + '{attribute}'=>$label, + '{min}'=>$this->min, + )); + $pattern=$this->integerOnly ? $this->integerPattern : $this->numberPattern; + $js=" +if(!value.match($pattern)) { + messages.push(".CJSON::encode($message)."); +} +"; + if($this->min!==null) + { + $js.=" +if(value<{$this->min}) { + messages.push(".CJSON::encode($tooSmall)."); +} +"; + } + if($this->max!==null) + { + $js.=" +if(value>{$this->max}) { + messages.push(".CJSON::encode($tooBig)."); +} +"; + } + if($this->allowEmpty) + { + $js=" +if($.trim(value)!='') { + $js +} +"; + } + return $js; + } +} +class CListIterator implements Iterator +{ + private $_d; + private $_i; + private $_c; + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + public function rewind() + { + $this->_i=0; + } + public function key() + { + return $this->_i; + } + public function current() + { + return $this->_d[$this->_i]; + } + public function next() + { + $this->_i++; + } + public function valid() + { + return $this->_i<$this->_c; + } +} +interface IApplicationComponent +{ + public function init(); + public function getIsInitialized(); +} +interface ICache +{ + public function get($id); + public function mget($ids); + public function set($id,$value,$expire=0,$dependency=null); + public function add($id,$value,$expire=0,$dependency=null); + public function delete($id); + public function flush(); +} +interface ICacheDependency +{ + public function evaluateDependency(); + public function getHasChanged(); +} +interface IStatePersister +{ + public function load(); + public function save($state); +} +interface IFilter +{ + public function filter($filterChain); +} +interface IAction +{ + public function getId(); + public function getController(); +} +interface IWebServiceProvider +{ + public function beforeWebMethod($service); + public function afterWebMethod($service); +} +interface IViewRenderer +{ + public function renderFile($context,$file,$data,$return); +} +interface IUserIdentity +{ + public function authenticate(); + public function getIsAuthenticated(); + public function getId(); + public function getName(); + public function getPersistentStates(); +} +interface IWebUser +{ + public function getId(); + public function getName(); + public function getIsGuest(); + public function checkAccess($operation,$params=array()); +} +interface IAuthManager +{ + public function checkAccess($itemName,$userId,$params=array()); + public function createAuthItem($name,$type,$description='',$bizRule=null,$data=null); + public function removeAuthItem($name); + public function getAuthItems($type=null,$userId=null); + public function getAuthItem($name); + public function saveAuthItem($item,$oldName=null); + public function addItemChild($itemName,$childName); + public function removeItemChild($itemName,$childName); + public function hasItemChild($itemName,$childName); + public function getItemChildren($itemName); + public function assign($itemName,$userId,$bizRule=null,$data=null); + public function revoke($itemName,$userId); + public function isAssigned($itemName,$userId); + public function getAuthAssignment($itemName,$userId); + public function getAuthAssignments($userId); + public function saveAuthAssignment($assignment); + public function clearAll(); + public function clearAuthAssignments(); + public function save(); + public function executeBizRule($bizRule,$params,$data); +} +interface IBehavior +{ + public function attach($component); + public function detach($component); + public function getEnabled(); + public function setEnabled($value); +} +interface IWidgetFactory +{ + public function createWidget($owner,$className,$properties=array()); +} +interface IDataProvider +{ + public function getId(); + public function getItemCount($refresh=false); + public function getTotalItemCount($refresh=false); + public function getData($refresh=false); + public function getKeys($refresh=false); + public function getSort(); + public function getPagination(); +} +?>
\ No newline at end of file |
