* @link http://www.yiiframework.com/ * @copyright 2008-2013 Yii Software LLC * @license http://www.yiiframework.com/license/ * @version $Id: $ * @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.14'; } 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 (); } elseif (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] ); elseif ($n === 3) $object = new $type ( $args [1], $args [2] ); elseif ($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 and the file is readable.', array ( '{alias}' => $alias ) ) ); self::$_imports [$alias] = $alias; } else self::$classMap [$alias] = $classFile; return $alias; } else { // try to autoload the class with an autoloader if (class_exists ( $alias, true )) return self::$_imports [$alias] = $alias; else throw new CException ( Yii::t ( 'yii', 'Alias "{alias}" is invalid. Make sure it points to an existing directory or file.', 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 and the file is readable.', 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]; elseif (($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 ); elseif (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]); elseif (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); if (YII_DEBUG && basename ( realpath ( $classFile ) ) !== $className . '.php') throw new CException ( Yii::t ( 'yii', 'Class name "{class}" does not match class file "{file}".', array ( '{class}' => $className, '{file}' => $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}' => 'Yii Framework' ) ); } 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', 'CRedisCache' => '/caching/CRedisCache.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', 'CConsoleCommandBehavior' => '/console/CConsoleCommandBehavior.php', 'CConsoleCommandEvent' => '/console/CConsoleCommandEvent.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', 'CMssqlSqlsrvPdoAdapter' => '/db/schema/mssql/CMssqlSqlsrvPdoAdapter.php', 'CMssqlTableSchema' => '/db/schema/mssql/CMssqlTableSchema.php', 'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php', 'CMysqlCommandBuilder' => '/db/schema/mysql/CMysqlCommandBuilder.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', 'CPgsqlCommandBuilder' => '/db/schema/pgsql/CPgsqlCommandBuilder.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', 'CChainedLogFilter' => '/logging/CChainedLogFilter.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', 'CLocalizedFormatter' => '/utils/CLocalizedFormatter.php', 'CMarkdownParser' => '/utils/CMarkdownParser.php', 'CPasswordHelper' => '/utils/CPasswordHelper.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', 'CDataProviderIterator' => '/web/CDataProviderIterator.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', 'CHttpCacheFilter' => '/web/filters/CHttpCacheFilter.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', 'CJavaScriptExpression' => '/web/helpers/CJavaScriptExpression.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 (); elseif (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]; } elseif (isset ( $this->_m [$name] )) return $this->_m [$name]; elseif (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 ); elseif (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 ); } elseif (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; elseif (strncasecmp ( $name, 'on', 2 ) === 0 && method_exists ( $this, $name )) { $name = strtolower ( $name ); return isset ( $this->_e [$name] ) && $this->_e [$name]->getCount (); } elseif (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 ); elseif (strncasecmp ( $name, 'on', 2 ) === 0 && method_exists ( $this, $name )) unset ( $this->_e [strtolower ( $name )] ); elseif (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; elseif ($object->canSetProperty ( $name )) return $object->$setter ( null ); } } } } elseif (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 ); elseif (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 ); elseif (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; } } elseif (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]; elseif (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]; elseif (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, $merge = true) { if ($component === null) { unset ( $this->_components [$id] ); return; } elseif ($component instanceof IApplicationComponent) { $this->_components [$id] = $component; if (! $component->getIsInitialized ()) $component->init (); return; } elseif (isset ( $this->_components [$id] )) { if (isset ( $component ['class'] ) && get_class ( $this->_components [$id] ) !== $component ['class']) { unset ( $this->_components [$id] ); $this->_componentConfig [$id] = $component; // we should ignore merge here return; } foreach ( $component as $key => $value ) { if ($key !== 'class') $this->_components [$id]->$key = $value; } } elseif (isset ( $this->_componentConfig [$id] ['class'], $component ['class'] ) && $this->_componentConfig [$id] ['class'] !== $component ['class']) { $this->_componentConfig [$id] = $component; // we should ignore merge here return; } if (isset ( $this->_componentConfig [$id] ) && $merge) $this->_componentConfig [$id] = CMap::mergeArray ( $this->_componentConfig [$id], $component ); else $this->_componentConfig [$id] = $component; } 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 ) $this->setComponent ( $id, $component, $merge ); } 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'] ) ); if (isset ( $config ['extensionPath'] )) { $this->setExtensionPath ( $config ['extensionPath'] ); unset ( $config ['extensionPath'] ); } else Yii::setPathOfAlias ( 'ext', $this->getBasePath () . DIRECTORY_SEPARATOR . 'extensions' ); if (isset ( $config ['aliases'] )) { $this->setAliases ( $config ['aliases'] ); unset ( $config ['aliases'] ); } $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 ) ); register_shutdown_function ( array ( $this, 'end' ), 0, false ); $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; } } elseif (! 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 "

PHP Error [$code]

\n"; echo "

$message ($file:$line)

\n"; echo '
';
			$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 '
'; } else { echo "

PHP Error [$code]

\n"; echo "

$message

\n"; } } public function displayException($exception) { if (YII_DEBUG) { echo '

' . get_class ( $exception ) . "

\n"; echo '

' . $exception->getMessage () . ' (' . $exception->getFile () . ':' . $exception->getLine () . ')

'; echo '
' . $exception->getTraceAsString () . '
'; } else { echo '

' . get_class ( $exception ) . "

\n"; echo '

' . $exception->getMessage () . '

'; } } 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; public $controllerNamespace; 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 ($owner->controllerNamespace !== null) $className = $owner->controllerNamespace . '\\' . $className; 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 ); } elseif ($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 ); } } elseif ($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; elseif (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 $_except = array (); 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 = array(), $except = array()) { $this->_levels = preg_split ( '/[\s,]+/', strtolower ( $levels ), - 1, PREG_SPLIT_NO_EMPTY ); if (is_string ( $categories )) $this->_categories = preg_split ( '/[\s,]+/', strtolower ( $categories ), - 1, PREG_SPLIT_NO_EMPTY ); else $this->_categories = array_filter ( array_map ( 'strtolower', $categories ) ); if (is_string ( $except )) $this->_except = preg_split ( '/[\s,]+/', strtolower ( $except ), - 1, PREG_SPLIT_NO_EMPTY ); else $this->_except = array_filter ( array_map ( 'strtolower', $except ) ); $ret = $this->_logs; if (! empty ( $levels )) $ret = array_values ( array_filter ( $ret, array ( $this, 'filterByLevel' ) ) ); if (! empty ( $this->_categories ) || ! empty ( $this->_except )) $ret = array_values ( array_filter ( $ret, array ( $this, 'filterByCategory' ) ) ); return $ret; } private function filterByCategory($value) { return $this->filterAllCategories ( $value, 2 ); } private function filterTimingByCategory($value) { return $this->filterAllCategories ( $value, 1 ); } private function filterAllCategories($value, $index) { $cat = strtolower ( $value [$index] ); $ret = empty ( $this->_categories ); foreach ( $this->_categories as $category ) { if ($cat === $category || (($c = rtrim ( $category, '.*' )) !== $category && strpos ( $cat, $c ) === 0)) $ret = true; } if ($ret) { foreach ( $this->_except as $category ) { if ($cat === $category || (($c = rtrim ( $category, '.*' )) !== $category && strpos ( $cat, $c ) === 0)) $ret = false; } } return $ret; } private function filterByLevel($value) { return in_array ( strtolower ( $value [1] ), $this->_levels ); } 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, $categories = null, $refresh = false) { if ($this->_timings === null || $refresh) $this->calculateTimings (); if ($token === null && $categories === null) return $this->_timings; $timings = $this->_timings; if ($categories !== null) { $this->_categories = preg_split ( '/[\s,]+/', strtolower ( $categories ), - 1, PREG_SPLIT_NO_EMPTY ); $timings = array_filter ( $timings, array ( $this, 'filterTimingByCategory' ) ); } $results = array (); foreach ( $timings as $timing ) { if ($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; } elseif (! strncasecmp ( $message, 'end:', 4 )) { $token = substr ( $message, 4 ); if (($last = array_pop ( $stack )) !== null && $last [0] === $token) { $delta = $log [3] - $last [3]; $this->_timings [] = array ( $message, $category, $delta ); } else throw new 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 $_preferredAcceptTypes; private $_preferredLanguages; private $_csrfToken; private $_restParams; 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) { if (is_array ( $data )) { if (count ( $data ) == 0) return $data; $keys = array_map ( 'stripslashes', array_keys ( $data ) ); $data = array_combine ( $keys, array_values ( $data ) ); return array_map ( array ( $this, 'stripSlashes' ), $data ); } else return 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->getIsDeleteViaPostRequest ()) return $this->getPost ( $name, $defaultValue ); if ($this->getIsDeleteRequest ()) { $restParams = $this->getRestParams (); return isset ( $restParams [$name] ) ? $restParams [$name] : $defaultValue; } else return $defaultValue; } public function getPut($name, $defaultValue = null) { if ($this->getIsPutViaPostRequest ()) return $this->getPost ( $name, $defaultValue ); if ($this->getIsPutRequest ()) { $restParams = $this->getRestParams (); return isset ( $restParams [$name] ) ? $restParams [$name] : $defaultValue; } else return $defaultValue; } public function getRestParams() { if ($this->_restParams === null) { $result = array (); if (function_exists ( 'mb_parse_str' )) mb_parse_str ( $this->getRawBody (), $result ); else parse_str ( $this->getRawBody (), $result ); $this->_restParams = $result; } return $this->_restParams; } public function getRawBody() { static $rawBody; if ($rawBody === null) $rawBody = file_get_contents ( 'php://input' ); return $rawBody; } 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']; elseif (basename ( $_SERVER ['PHP_SELF'] ) === $scriptName) $this->_scriptUrl = $_SERVER ['PHP_SELF']; elseif (isset ( $_SERVER ['ORIG_SCRIPT_NAME'] ) && basename ( $_SERVER ['ORIG_SCRIPT_NAME'] ) === $scriptName) $this->_scriptUrl = $_SERVER ['ORIG_SCRIPT_NAME']; elseif (($pos = strpos ( $_SERVER ['PHP_SELF'], '/' . $scriptName )) !== false) $this->_scriptUrl = substr ( $_SERVER ['SCRIPT_NAME'], 0, $pos ) . '/' . $scriptName; elseif (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 ) ); elseif ($baseUrl === '' || strpos ( $pathInfo, $baseUrl ) === 0) $pathInfo = substr ( $pathInfo, strlen ( $baseUrl ) ); elseif (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']; elseif (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 ); } elseif (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'] ) && ($_SERVER ['HTTPS'] == 'on' || $_SERVER ['HTTPS'] == 1) || isset ( $_SERVER ['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER ['HTTP_X_FORWARDED_PROTO'] == 'https'; } public function getRequestType() { if (isset ( $_POST ['_method'] )) return strtoupper ( $_POST ['_method'] ); 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' )) || $this->getIsDeleteViaPostRequest (); } protected function getIsDeleteViaPostRequest() { return isset ( $_POST ['_method'] ) && ! strcasecmp ( $_POST ['_method'], 'DELETE' ); } public function getIsPutRequest() { return (isset ( $_SERVER ['REQUEST_METHOD'] ) && ! strcasecmp ( $_SERVER ['REQUEST_METHOD'], 'PUT' )) || $this->getIsPutViaPostRequest (); } protected function getIsPutViaPostRequest() { return isset ( $_POST ['_method'] ) && ! strcasecmp ( $_POST ['_method'], 'PUT' ); } public function getIsAjaxRequest() { return isset ( $_SERVER ['HTTP_X_REQUESTED_WITH'] ) && $_SERVER ['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; } public function getIsFlashRequest() { return isset ( $_SERVER ['HTTP_USER_AGENT'] ) && (stripos ( $_SERVER ['HTTP_USER_AGENT'], 'Shockwave' ) !== false || stripos ( $_SERVER ['HTTP_USER_AGENT'], 'Flash' ) !== false); } 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 && strpos ( $url, '//' ) !== 0) $url = $this->getHostInfo () . $url; header ( 'Location: ' . $url, true, $statusCode ); if ($terminate) Yii::app ()->end (); } public static function parseAcceptHeader($header) { $matches = array (); $accepts = array (); // get individual entries with their type, subtype, basetype and params preg_match_all ( '/(?:\G\s?,\s?|^)(\w+|\*)\/(\w+|\*)(?:\+(\w+))?|(? $matches [1] [$i], 'subType' => $matches [2] [$i], 'baseType' => null, 'params' => array () ); // fill in the base type if it exists if ($matches [3] [$i] !== null && $matches [3] [$i] !== '') $accept ['baseType'] = $matches [3] [$i]; // continue looping while there is no new content type, to fill in all accompanying params for($i ++; $i < $itemLen; $i ++) { // if the next content type is null, then the item is a param for the current content type if ($matches [1] [$i] === null || $matches [1] [$i] === '') { // if this is the quality param, convert it to a double if ($matches [4] [$i] === 'q') { // sanity check on q value $q = ( double ) $matches [5] [$i]; if ($q > 1) $q = ( double ) 1; elseif ($q < 0) $q = ( double ) 0; $accept ['params'] [$matches [4] [$i]] = $q; } else $accept ['params'] [$matches [4] [$i]] = $matches [5] [$i]; } else break; } // q defaults to 1 if not explicitly given if (! isset ( $accept ['params'] ['q'] )) $accept ['params'] ['q'] = ( double ) 1; $accepts [] = $accept; } } return $accepts; } public static function compareAcceptTypes($a, $b) { // check for equal quality first if ($a ['params'] ['q'] === $b ['params'] ['q']) if (! ($a ['type'] === '*' xor $b ['type'] === '*')) if (! ($a ['subType'] === '*' xor $b ['subType'] === '*')) // finally, higher number of parameters counts as greater precedence if (count ( $a ['params'] ) === count ( $b ['params'] )) return 0; else return count ( $a ['params'] ) < count ( $b ['params'] ) ? 1 : - 1; // more specific takes precedence - whichever one doesn't have a * subType else return $a ['subType'] === '*' ? 1 : - 1; // more specific takes precedence - whichever one doesn't have a * type else return $a ['type'] === '*' ? 1 : - 1; else return ($a ['params'] ['q'] < $b ['params'] ['q']) ? 1 : - 1; } public function getPreferredAcceptTypes() { if ($this->_preferredAcceptTypes === null) { $accepts = self::parseAcceptHeader ( $this->getAcceptTypes () ); usort ( $accepts, array ( get_class ( $this ), 'compareAcceptTypes' ) ); $this->_preferredAcceptTypes = $accepts; } return $this->_preferredAcceptTypes; } public function getPreferredAcceptType() { $preferredAcceptTypes = $this->getPreferredAcceptTypes (); return empty ( $preferredAcceptTypes ) ? false : $preferredAcceptTypes [0]; } public function getPreferredLanguages() { if ($this->_preferredLanguages === null) { $sortedLanguages = array (); if (isset ( $_SERVER ['HTTP_ACCEPT_LANGUAGE'] ) && $n = preg_match_all ( '/([\w\-_]+)(?:\s*;\s*q\s*=\s*(\d*\.?\d*))?/', $_SERVER ['HTTP_ACCEPT_LANGUAGE'], $matches )) { $languages = array (); for($i = 0; $i < $n; ++ $i) { $q = $matches [2] [$i]; if ($q === '') $q = 1; if ($q) $languages [] = array ( ( float ) $q, $matches [1] [$i] ); } usort ( $languages, create_function ( '$a,$b', 'if($a[0]==$b[0]) {return 0;} return ($a[0]<$b[0]) ? 1 : -1;' ) ); foreach ( $languages as $language ) $sortedLanguages [] = $language [1]; } $this->_preferredLanguages = $sortedLanguages; } return $this->_preferredLanguages; } public function getPreferredLanguage() { $preferredLanguages = $this->getPreferredLanguages (); return ! empty ( $preferredLanguages ) ? CLocale::getCanonicalID ( $preferredLanguages [0] ) : false; } public function sendFile($fileName, $content, $mimeType = null, $terminate = true) { if ($mimeType === null) { if (($mimeType = CFileHelper::getMimeTypeByExtension ( $fileName )) === null) $mimeType = 'text/plain'; } $fileSize = (function_exists ( 'mb_strlen' ) ? mb_strlen ( $content, '8bit' ) : strlen ( $content )); $contentStart = 0; $contentEnd = $fileSize - 1; if (isset ( $_SERVER ['HTTP_RANGE'] )) { header ( 'Accept-Ranges: bytes' ); // client sent us a multibyte range, can not hold this one for now if (strpos ( $_SERVER ['HTTP_RANGE'], ',' ) !== false) { header ( "Content-Range: bytes $contentStart-$contentEnd/$fileSize" ); throw new CHttpException ( 416, 'Requested Range Not Satisfiable' ); } $range = str_replace ( 'bytes=', '', $_SERVER ['HTTP_RANGE'] ); // range requests starts from "-", so it means that data must be dumped the end point. if ($range [0] === '-') $contentStart = $fileSize - substr ( $range, 1 ); else { $range = explode ( '-', $range ); $contentStart = $range [0]; // check if the last-byte-pos presents in header if ((isset ( $range [1] ) && is_numeric ( $range [1] ))) $contentEnd = $range [1]; } /* * Check the range and make sure it's treated according to the specs. * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */ // End bytes can not be larger than $end. $contentEnd = ($contentEnd > $fileSize) ? $fileSize - 1 : $contentEnd; // Validate the requested range and return an error if it's not correct. $wrongContentStart = ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0); if ($wrongContentStart) { header ( "Content-Range: bytes $contentStart-$contentEnd/$fileSize" ); throw new CHttpException ( 416, 'Requested Range Not Satisfiable' ); } header ( 'HTTP/1.1 206 Partial Content' ); header ( "Content-Range: bytes $contentStart-$contentEnd/$fileSize" ); } else header ( 'HTTP/1.1 200 OK' ); $length = $contentEnd - $contentStart + 1; // Calculate new content length header ( 'Pragma: public' ); header ( 'Expires: 0' ); header ( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); header ( "Content-Type: $mimeType" ); header ( 'Content-Length: ' . $length ); header ( "Content-Disposition: attachment; filename=\"$fileName\"" ); header ( 'Content-Transfer-Encoding: binary' ); $content = function_exists ( 'mb_substr' ) ? mb_substr ( $content, $contentStart, $length ) : substr ( $content, $contentStart, $length ); 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) ob_start (); Yii::app ()->end ( 0, false ); ob_end_clean (); 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 () || $this->getIsPutRequest () || $this->getIsDeleteRequest ()) { $cookies = $this->getCookies (); $method = $this->getRequestType (); switch ($method) { case 'POST' : $userToken = $this->getPost ( $this->csrfTokenName ); break; case 'PUT' : $userToken = $this->getPut ( $this->csrfTokenName ); break; case 'DELETE' : $userToken = $this->getDelete ( $this->csrfTokenName ); } if (! empty ( $userToken ) && $cookies->contains ( $this->csrfTokenName )) { $cookieToken = $cookies->itemAt ( $this->csrfTokenName )->value; $valid = $cookieToken === $userToken; } 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, $options = array()) { if (($cookie = parent::remove ( $name )) !== null) { if ($this->_initialized) { $cookie->configure ( $options ); $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, '', 0, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly ); else setcookie ( $cookie->name, '', 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 { $rules = array_reverse ( $rules ); 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 { $urlRuleClass = Yii::import ( $this->urlRuleClass, true ); return new $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; } elseif (($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; } elseif (isset ( $_GET [$this->routeVar] )) return $_GET [$this->routeVar]; elseif (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 ( '/\A' . $value . '\z/u' . $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; elseif (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 ); } elseif ($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; elseif (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; } elseif (($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; } elseif (strpos ( $viewName, '.' )) $viewFile = Yii::getPathOfAlias ( $viewName ); else $viewFile = $viewPath . DIRECTORY_SEPARATOR . $viewName; if (is_file ( $viewFile . $extension )) return Yii::app ()->findLocalizedFile ( $viewFile . $extension ); elseif ($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 (); elseif (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] ); elseif (! is_array ( $params [$name] )) $ps [] = $params [$name]; else return false; } elseif ($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'; const AUTH_ABSOLUTE_TIMEOUT_VAR = '__absolute_timeout'; public $allowAutoLogin = false; public $guestName = 'Guest'; public $loginUrl = array ( '/site/login' ); public $identityCookie; public $authTimeout; public $absoluteAuthTimeout; 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 (); elseif ($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 ) ) ) ); } if ($this->absoluteAuthTimeout) $this->setState ( self::AUTH_ABSOLUTE_TIMEOUT_VAR, time () + $this->absoluteAuthTimeout ); $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->_access = array (); $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) { if ($defaultUrl === null) { $defaultReturnUrl = Yii::app ()->getUrlManager ()->showScriptName ? Yii::app ()->getRequest ()->getScriptUrl () : Yii::app ()->getRequest ()->getBaseUrl () . '/'; } else { $defaultReturnUrl = CHtml::normalizeUrl ( $defaultUrl ); } return $this->getState ( '__returnUrl', $defaultReturnUrl ); } public function setReturnUrl($value) { $this->setState ( '__returnUrl', $value ); } public function loginRequired() { $app = Yii::app (); $request = $app->getRequest (); if (! $request->getIsAjaxRequest ()) { $this->setReturnUrl ( $request->getUrl () ); 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 ); } } elseif (isset ( $this->loginRequiredAjaxResponse )) { echo $this->loginRequiredAjaxResponse; Yii::app ()->end (); } 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 ) && is_string ( $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) { $this->saveToCookie ( $duration ); } $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] )) { $this->saveToCookie ( $data [2] ); } } } 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 ( true ); $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->absoluteAuthTimeout !== null) && ! $this->getIsGuest ()) { $expires = $this->getState ( self::AUTH_TIMEOUT_VAR ); $expiresAbsolute = $this->getState ( self::AUTH_ABSOLUTE_TIMEOUT_VAR ); if ($expires !== null && $expires < time () || $expiresAbsolute !== null && $expiresAbsolute < 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]; $access = Yii::app ()->getAuthManager ()->checkAccess ( $operation, $this->getId (), $params ); if ($allowCaching && $params === array ()) $this->_access [$operation] = $access; return $access; } } 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'; elseif (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' ); } elseif ($value === 'allow') { ini_set ( 'session.use_cookies', '1' ); ini_set ( 'session.use_only_cookies', '0' ); } elseif ($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 ( float ) (ini_get ( 'session.gc_probability' ) / ini_get ( 'session.gc_divisor' ) * 100); } public function setGCProbability($value) { if ($value >= 0 && $value <= 100) { // percent * 21474837 / 2147483647 ≈ percent * 0.01 ini_set ( 'session.gc_probability', floor ( $value * 21474836.47 ) ); ini_set ( 'session.gc_divisor', 2147483647 ); } else throw new CException ( Yii::t ( 'yii', 'CHttpSession.gcProbability "{value}" is invalid. It must be a float 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 $errorContainerTag = 'div'; public static $requiredCss = 'required'; public static $beforeRequiredLabel = ''; public static $afterRequiredLabel = ' *'; public static $count = 0; public static $liveEvents = true; public static $closeSingleTags = true; public static $renderSpecialAttributesValue = true; private static $_modelNameConverter; 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 ); elseif (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 && self::$closeSingleTags ? $html . ' />' : $html . '>'; else return $closeTag ? $html . '>' . $content . '' : $html . '>' . $content; } public static function openTag($tag, $htmlOptions = array()) { return '<' . $tag . self::renderAttributes ( $htmlOptions ) . '>'; } public static function closeTag($tag) { return ''; } public static function cdata($text) { return ''; } 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 ""; } public static function refresh($seconds, $url = '') { $content = "$seconds"; if ($url !== '') $content .= ';url=' . self::normalizeUrl ( $url ); Yii::app ()->clientScript->registerMetaTag ( $content, null, 'refresh' ); } public static function cssFile($url, $media = '') { return CHtml::linkTag ( 'stylesheet', 'text/css', $url, $media !== '' ? $media : null ); } public static function script($text, array $htmlOptions = array()) { $defaultHtmlOptions = array ( 'type' => 'text/javascript' ); $htmlOptions = array_merge ( $defaultHtmlOptions, $htmlOptions ); return self::tag ( 'script', $htmlOptions, "\n/**/\n" ); } public static function scriptFile($url, array $htmlOptions = array()) { $defaultHtmlOptions = array ( 'type' => 'text/javascript', 'src' => $url ); $htmlOptions = array_merge ( $defaultHtmlOptions, $htmlOptions ); return self::tag ( 'script', $htmlOptions, '' ); } 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 ) ); else $hiddens [] = self::hiddenField ( urldecode ( $pair ), '', 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 ''; } 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 ''; } 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 ['type'] != 'image') $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 numberField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'number', $name, $value, $htmlOptions ); } public static function rangeField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'range', $name, $value, $htmlOptions ); } public static function dateField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'date', $name, $value, $htmlOptions ); } public static function timeField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'time', $name, $value, $htmlOptions ); } public static function emailField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'email', $name, $value, $htmlOptions ); } public static function telField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'tel', $name, $value, $htmlOptions ); } public static function urlField($name, $value = '', $htmlOptions = array()) { self::clientChange ( 'change', $htmlOptions ); return self::inputField ( 'url', $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 ); elseif ($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 check box is not checked, 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 check box is not checked, 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 ); elseif ($htmlOptions ['id'] === false) unset ( $htmlOptions ['id'] ); self::clientChange ( 'change', $htmlOptions ); $options = "\n" . self::listOptions ( $select, $data, $htmlOptions ); $hidden = ''; if (! empty ( $htmlOptions ['multiple'] )) { if (substr ( $htmlOptions ['name'], - 2 ) !== '[]') $htmlOptions ['name'] .= '[]'; if (isset ( $htmlOptions ['unselectValue'] )) { $hiddenOptions = isset ( $htmlOptions ['id'] ) ? array ( 'id' => self::ID_PREFIX . $htmlOptions ['id'] ) : array ( 'id' => false ); $hidden = self::hiddenField ( substr ( $htmlOptions ['name'], 0, - 2 ), $htmlOptions ['unselectValue'], $hiddenOptions ); unset ( $htmlOptions ['unselectValue'] ); } } // add a hidden field so that if the option is not selected, it still submits a value return $hidden . self::tag ( 'select', $htmlOptions, $options ); } public static function listBox($name, $select, $data, $htmlOptions = array()) { if (! isset ( $htmlOptions ['size'] )) $htmlOptions ['size'] = 4; if (! empty ( $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'] : "
\n"; $container = isset ( $htmlOptions ['container'] ) ? $htmlOptions ['container'] : 'span'; unset ( $htmlOptions ['template'], $htmlOptions ['separator'], $htmlOptions ['container'] ); 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 = isset ( $htmlOptions ['baseID'] ) ? $htmlOptions ['baseID'] : self::getIdByName ( $name ); unset ( $htmlOptions ['baseID'] ); $id = 0; $checkAll = true; foreach ( $data as $value => $labelTitle ) { $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 ); $beginLabel = self::openTag ( 'label', $labelOptions ); $label = self::label ( $labelTitle, $htmlOptions ['id'], $labelOptions ); $endLabel = self::closeTag ( 'label' ); $items [] = strtr ( $template, array ( '{input}' => $option, '{beginLabel}' => $beginLabel, '{label}' => $label, '{labelTitle}' => $labelTitle, '{endLabel}' => $endLabel ) ); } if (isset ( $checkAllLabel )) { $htmlOptions ['value'] = 1; $htmlOptions ['id'] = $id = $baseID . '_all'; $option = self::checkBox ( $id, $checkAll, $htmlOptions ); $beginLabel = self::openTag ( 'label', $labelOptions ); $label = self::label ( $checkAllLabel, $id, $labelOptions ); $endLabel = self::closeTag ( 'label' ); $item = strtr ( $template, array ( '{input}' => $option, '{beginLabel}' => $beginLabel, '{label}' => $label, '{labelTitle}' => $checkAllLabel, '{endLabel}' => $endLabel ) ); if ($checkAllLast) $items [] = $item; else array_unshift ( $items, $item ); $name = strtr ( $name, array ( '[' => '\\[', ']' => '\\]' ) ); $js = <<getClientScript (); $cs->registerCoreScript ( 'jquery' ); $cs->registerScript ( $id, $js ); } if (empty ( $container )) return implode ( $separator, $items ); else return self::tag ( $container, 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'] : "
\n"; $container = isset ( $htmlOptions ['container'] ) ? $htmlOptions ['container'] : 'span'; unset ( $htmlOptions ['template'], $htmlOptions ['separator'], $htmlOptions ['container'] ); $labelOptions = isset ( $htmlOptions ['labelOptions'] ) ? $htmlOptions ['labelOptions'] : array (); unset ( $htmlOptions ['labelOptions'] ); if (isset ( $htmlOptions ['empty'] )) { if (! is_array ( $htmlOptions ['empty'] )) $htmlOptions ['empty'] = array ( '' => $htmlOptions ['empty'] ); $data = array_merge ( $htmlOptions ['empty'], $data ); unset ( $htmlOptions ['empty'] ); } $items = array (); $baseID = isset ( $htmlOptions ['baseID'] ) ? $htmlOptions ['baseID'] : self::getIdByName ( $name ); unset ( $htmlOptions ['baseID'] ); $id = 0; foreach ( $data as $value => $labelTitle ) { $checked = ! strcmp ( $value, $select ); $htmlOptions ['value'] = $value; $htmlOptions ['id'] = $baseID . '_' . $id ++; $option = self::radioButton ( $name, $checked, $htmlOptions ); $beginLabel = self::openTag ( 'label', $labelOptions ); $label = self::label ( $labelTitle, $htmlOptions ['id'], $labelOptions ); $endLabel = self::closeTag ( 'label' ); $items [] = strtr ( $template, array ( '{input}' => $option, '{beginLabel}' => $beginLabel, '{label}' => $label, '{labelTitle}' => $labelTitle, '{endLabel}' => $endLabel ) ); } if (empty ( $container )) return implode ( $separator, $items ); else return self::tag ( $container, 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'] = new CJavaScriptExpression ( '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'] = new CJavaScriptExpression ( 'jQuery(this).parents("form").serialize()' ); foreach ( array ( 'beforeSend', 'complete', 'error', 'success' ) as $name ) { if (isset ( $options [$name] ) && ! ($options [$name] instanceof CJavaScriptExpression)) $options [$name] = new CJavaScriptExpression ( $options [$name] ); } if (isset ( $options ['update'] )) { if (! isset ( $options ['success'] )) $options ['success'] = new CJavaScriptExpression ( 'function(html){jQuery("' . $options ['update'] . '").html(html)}' ); unset ( $options ['update'] ); } if (isset ( $options ['replace'] )) { if (! isset ( $options ['success'] )) $options ['success'] = new CJavaScriptExpression ( '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 ); elseif ($htmlOptions ['id'] === false) unset ( $htmlOptions ['id'] ); return self::tag ( 'input', $htmlOptions ); } public static function activeLabel($model, $attribute, $htmlOptions = array()) { $inputName = self::resolveName ( $model, $attribute ); if (isset ( $htmlOptions ['for'] )) { $for = $htmlOptions ['for']; unset ( $htmlOptions ['for'] ); } else $for = self::getIdByName ( $inputName ); 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 activeSearchField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'search', $model, $attribute, $htmlOptions ); } public static function activeUrlField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'url', $model, $attribute, $htmlOptions ); } public static function activeEmailField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'email', $model, $attribute, $htmlOptions ); } public static function activeNumberField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'number', $model, $attribute, $htmlOptions ); } public static function activeRangeField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'range', $model, $attribute, $htmlOptions ); } public static function activeDateField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'date', $model, $attribute, $htmlOptions ); } public static function activeTimeField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'time', $model, $attribute, $htmlOptions ); } public static function activeTelField($model, $attribute, $htmlOptions = array()) { self::resolveNameID ( $model, $attribute, $htmlOptions ); self::clientChange ( 'change', $htmlOptions ); return self::activeInputField ( 'tel', $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 ); if (isset ( $htmlOptions ['value'] )) { $text = $htmlOptions ['value']; unset ( $htmlOptions ['value'] ); } else $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 ); $hidden = ''; if (! empty ( $htmlOptions ['multiple'] )) { if (substr ( $htmlOptions ['name'], - 2 ) !== '[]') $htmlOptions ['name'] .= '[]'; if (isset ( $htmlOptions ['unselectValue'] )) { $hiddenOptions = isset ( $htmlOptions ['id'] ) ? array ( 'id' => self::ID_PREFIX . $htmlOptions ['id'] ) : array ( 'id' => false ); $hidden = self::hiddenField ( substr ( $htmlOptions ['name'], 0, - 2 ), $htmlOptions ['unselectValue'], $hiddenOptions ); unset ( $htmlOptions ['unselectValue'] ); } } return $hidden . 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 .= "
  • $error
  • \n"; if ($firstError) break; } } } if ($content !== '') { if ($header === null) $header = '

    ' . Yii::t ( 'yii', 'Please fix the following input errors:' ) . '

    '; if (! isset ( $htmlOptions ['class'] )) $htmlOptions ['class'] = self::$errorSummaryCss; return self::tag ( 'div', $htmlOptions, $header . "\n" . $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 ( self::$errorContainerTag, $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 ); if ($group === null) $listData [$value] = $text; else $listData [$group] [$value] = $text; } } return $listData; } public static function value($model, $attribute, $defaultValue = null) { if (is_scalar ( $attribute ) || $attribute === null) foreach ( explode ( '.', $attribute ) as $name ) { if (is_object ( $model ) && isset ( $model->$name )) $model = $model->$name; elseif (is_array ( $model ) && isset ( $model [$name] )) $model = $model [$name]; else return $defaultValue; } else return call_user_func ( $attribute, $model ); 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 modelName($model) { if (is_callable ( self::$_modelNameConverter )) return call_user_func ( self::$_modelNameConverter, $model ); $className = is_object ( $model ) ? get_class ( $model ) : ( string ) $model; return trim ( str_replace ( '\\', '_', $className ), '_' ); } public static function setModelNameConverter($converter) { if (is_callable ( $converter )) self::$_modelNameConverter = $converter; elseif ($converter === null) self::$_modelNameConverter = null; else throw new CException ( Yii::t ( 'yii', 'The $converter argument must be a valid callback or null.' ) ); } 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; } } } elseif ($htmlOptions ['maxlength'] === false) unset ( $htmlOptions ['maxlength'] ); } if ($type === 'file') unset ( $htmlOptions ['value'] ); elseif (! 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 .= '\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 .= '\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; } } elseif (is_object ( $selection )) $selection = $selection->$key; foreach ( $listData as $key => $value ) { if (is_array ( $value )) { $content .= '\n"; $dummy = array ( 'options' => $options ); if (isset ( $htmlOptions ['encode'] )) $dummy ['encode'] = $htmlOptions ['encode']; $content .= self::listOptions ( $selection, $value, $dummy ); $content .= '' . "\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, "jQuery('body').on('$event','#$id',function(){{$handler}});" ); else $cs->registerScript ( 'Yii.CHtml.#' . $id, "jQuery('#$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'] ); elseif ($htmlOptions ['id'] === false) unset ( $htmlOptions ['id'] ); } public static function resolveName($model, &$attribute) { $modelName = self::modelName ( $model ); if (($pos = strpos ( $attribute, '[' )) !== false) { if ($pos !== 0) // e.g. name[a][b] return $modelName . '[' . 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 $modelName . $sub . '[' . $attribute . ']'; } if (preg_match ( '/\](\w+\[.*)$/', $attribute, $matches )) { $name = $modelName . '[' . str_replace ( ']', '][', trim ( strtr ( $attribute, array ( '][' => ']', '[' => ']' ) ), ']' ) ) . ']'; $attribute = $matches [1]; return $name; } } return $modelName . '[' . $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]; // we get: name[b][c] 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 ) || $value instanceof ArrayAccess) && isset ( $value [$id] )) $value = $value [$id]; else return null; } return $value; } else return $model->$attribute; } protected static function addErrorCss(&$htmlOptions) { if (empty ( self::$errorCss )) return; if (isset ( $htmlOptions ['class'] )) $htmlOptions ['class'] .= ' ' . self::$errorCss; else $htmlOptions ['class'] = self::$errorCss; } public static function renderAttributes($htmlOptions) { static $specialAttributes = array ( 'async' => 1, 'autofocus' => 1, 'autoplay' => 1, 'checked' => 1, 'controls' => 1, 'declare' => 1, 'default' => 1, 'defer' => 1, 'disabled' => 1, 'formnovalidate' => 1, 'hidden' => 1, 'ismap' => 1, 'loop' => 1, 'multiple' => 1, 'muted' => 1, 'nohref' => 1, 'noresize' => 1, 'novalidate' => 1, 'open' => 1, 'readonly' => 1, 'required' => 1, 'reversed' => 1, 'scoped' => 1, 'seamless' => 1, 'selected' => 1, 'typemustmatch' => 1 ); if ($htmlOptions === array ()) return ''; $html = ''; if (isset ( $htmlOptions ['encode'] )) { $raw = ! $htmlOptions ['encode']; unset ( $htmlOptions ['encode'] ); } else $raw = false; foreach ( $htmlOptions as $name => $value ) { if (isset ( $specialAttributes [$name] )) { if ($value) { $html .= ' ' . $name; if (self::$renderSpecialAttributesValue) $html .= '="' . $name . '"'; } } elseif ($value !== null) $html .= ' ' . $name . '="' . ($raw ? $value : 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; elseif ($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 ); $scope = $checkTheme ? 'theme' : 'local'; if (isset ( self::$_viewPaths [$className] [$scope] )) return self::$_viewPaths [$className] [$scope]; 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] ['theme'] = $path; } $class = new ReflectionClass ( $className ); return self::$_viewPaths [$className] ['local'] = 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 ); elseif ($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 ); elseif ($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; public $scripts = array (); protected $cssFiles = array (); protected $scriptFiles = array (); protected $metaTags = array (); protected $linkTags = array (); protected $css = array (); protected $hasScripts = false; protected $coreScripts = array (); public $coreScriptPosition = self::POS_HEAD; public $defaultScriptFilePosition = self::POS_HEAD; public $defaultScriptPosition = self::POS_READY; 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 $scriptFile => $scriptFileValue ) { if (isset ( $map [$scriptFile] )) unset ( $this->scriptFiles [self::POS_BEGIN] [$scriptFile] ); else $map [$scriptFile] = true; } } if (isset ( $this->scriptFiles [self::POS_END] )) { foreach ( $this->scriptFiles [self::POS_END] as $key => $scriptFile ) { if (isset ( $map [$key] )) 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; } elseif (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 => $scriptFiles ) { $jsFiles [$position] = array (); foreach ( $scriptFiles as $scriptFile => $scriptFileValue ) { $name = basename ( $scriptFile ); if (isset ( $this->scriptMap [$name] )) { if ($this->scriptMap [$name] !== false) $jsFiles [$position] [$this->scriptMap [$name]] = $this->scriptMap [$name]; } elseif (isset ( $this->scriptMap ['*.js'] )) { if ($this->scriptMap ['*.js'] !== false) $jsFiles [$position] [$this->scriptMap ['*.js']] = $this->scriptMap ['*.js']; } else $jsFiles [$position] [$scriptFile] = $scriptFileValue; } } $this->scriptFiles = $jsFiles; } protected function renderScriptBatch(array $scripts) { $html = ''; $scriptBatches = array (); foreach ( $scripts as $scriptValue ) { if (is_array ( $scriptValue )) { $scriptContent = $scriptValue ['content']; unset ( $scriptValue ['content'] ); $scriptHtmlOptions = $scriptValue; } else { $scriptContent = $scriptValue; $scriptHtmlOptions = array (); } $key = serialize ( ksort ( $scriptHtmlOptions ) ); $scriptBatches [$key] ['htmlOptions'] = $scriptHtmlOptions; $scriptBatches [$key] ['scripts'] [] = $scriptContent; } foreach ( $scriptBatches as $scriptBatch ) if (! empty ( $scriptBatch ['scripts'] )) $html .= CHtml::script ( implode ( "\n", $scriptBatch ['scripts'] ), $scriptBatch ['htmlOptions'] ) . "\n"; return $html; } 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 => $value ) $jsFiles [$url] = $value; } $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 $scriptFileValueUrl => $scriptFileValue ) { if (is_array ( $scriptFileValue )) $html .= CHtml::scriptFile ( $scriptFileValueUrl, $scriptFileValue ) . "\n"; else $html .= CHtml::scriptFile ( $scriptFileValueUrl ) . "\n"; } } if (isset ( $this->scripts [self::POS_HEAD] )) $html .= $this->renderScriptBatch ( $this->scripts [self::POS_HEAD] ); } if ($html !== '') { $count = 0; $output = preg_replace ( '/(]*>|<\\/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 $scriptFileUrl => $scriptFileValue ) { if (is_array ( $scriptFileValue )) $html .= CHtml::scriptFile ( $scriptFileUrl, $scriptFileValue ) . "\n"; else $html .= CHtml::scriptFile ( $scriptFileUrl ) . "\n"; } } if (isset ( $this->scripts [self::POS_BEGIN] )) $html .= $this->renderScriptBatch ( $this->scripts [self::POS_BEGIN] ); if ($html !== '') { $count = 0; $output = preg_replace ( '/(]*>)/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 $scriptFileUrl => $scriptFileValue ) { if (is_array ( $scriptFileValue )) $html .= CHtml::scriptFile ( $scriptFileUrl, $scriptFileValue ) . "\n"; else $html .= CHtml::scriptFile ( $scriptFileUrl ) . "\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).on('load',function() {\n" . implode ( "\n", $this->scripts [self::POS_LOAD] ) . "\n});"; else $scripts [] = implode ( "\n", $this->scripts [self::POS_LOAD] ); } if (! empty ( $scripts )) $html .= $this->renderScriptBatch ( $scripts ); 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, '/' ); } elseif (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 = null, array $htmlOptions = array()) { if ($position === null) $position = $this->defaultScriptFilePosition; $this->hasScripts = true; if (empty ( $htmlOptions )) $value = $url; else { $value = $htmlOptions; $value ['src'] = $url; } $this->scriptFiles [$position] [$url] = $value; $params = func_get_args (); $this->recordCachingAction ( 'clientScript', 'registerScriptFile', $params ); return $this; } public function registerScript($id, $script, $position = null, array $htmlOptions = array()) { if ($position === null) $position = $this->defaultScriptPosition; $this->hasScripts = true; if (empty ( $htmlOptions )) $scriptValue = $script; else { if ($position == self::POS_LOAD || $position == self::POS_READY) throw new CException ( Yii::t ( 'yii', 'Script HTML options are not allowed for "CClientScript::POS_LOAD" and "CClientScript::POS_READY".' ) ); $scriptValue = $htmlOptions; $scriptValue ['content'] = $script; } $this->scripts [$position] [$id] = $scriptValue; 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(), $id = null) { $this->hasScripts = true; if ($name !== null) $options ['name'] = $name; if ($httpEquiv !== null) $options ['http-equiv'] = $httpEquiv; $options ['content'] = $content; $this->metaTags [null === $id ? count ( $this->metaTags ) : $id] = $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]; elseif ($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; elseif ($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 ); } elseif ($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 ); } elseif ($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 ); } elseif (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' || $name === 'deniedCallback') $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; elseif ($allow < 0) // denied { if (isset ( $rule->deniedCallback )) call_user_func ( $rule->deniedCallback, $rule ); else $this->accessDenied ( $user, $this->resolveErrorMessage ( $rule ) ); return false; } } return true; } protected function resolveErrorMessage($rule) { if ($rule->message !== null) return $rule->message; elseif ($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 $deniedCallback; 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->getUniqueId () ), $this->controllers ); } protected function isUserMatched($user) { if (empty ( $this->users )) return true; foreach ( $this->users as $u ) { if ($u === '*') return true; elseif ($u === '?' && $user->getIsGuest ()) return true; elseif ($u === '@' && ! $user->getIsGuest ()) return true; elseif (! strcasecmp ( $u, $user->getName () )) return true; } return false; } protected function isRoleMatched($user) { if (empty ( $this->roles )) return true; foreach ( $this->roles as $key => $role ) { if (is_numeric ( $key )) { if ($user->checkAccess ( $role )) return true; } else { if ($user->checkAccess ( $key, $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->addError ( $attribute, $e ); } else $this->addError ( $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 ( '/(?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; elseif ($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 static $_md = array (); // class name => 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() { return array_keys ( ( array ) $this ); } public function __get($name) { if (isset ( $this->_attributes [$name] )) return $this->_attributes [$name]; elseif (isset ( $this->getMetaData ()->columns [$name] )) return null; elseif (isset ( $this->_related [$name] )) return $this->_related [$name]; elseif (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; elseif (isset ( $this->getMetaData ()->columns [$name] )) return false; elseif (isset ( $this->_related [$name] )) return true; elseif (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] ); elseif (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]; if ($params instanceof CDbCriteria) $params = $params->toArray (); $r = array ( $name => $params ); } else $r = $name; unset ( $this->_related [$name] ); $finder = $this->getActiveFinder ( $r ); $finder->lazyFind ( $this ); if (! isset ( $this->_related [$name] )) { if ($relation instanceof CHasManyRelation) $this->_related [$name] = array (); elseif ($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($resetDefault = true) { if ($resetDefault) $this->_c = new CDbCriteria (); else $this->_c = null; 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->attachBehaviors ( $model->behaviors () ); return $model; } } public function getMetaData() { $className = get_class ( $this ); if (! array_key_exists ( $className, self::$_md )) { self::$_md [$className] = null; // preventing recursive invokes of {@link getMetaData()} via {@link __get()} self::$_md [$className] = new CActiveRecordMetaData ( $this ); } return self::$_md [$className]; } public function refreshMetaData() { $className = get_class ( $this ); if (array_key_exists ( $className, self::$_md )) unset ( self::$_md [$className] ); } 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]; elseif (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; elseif (isset ( $this->_attributes [$name] )) return $this->_attributes [$name]; } public function setAttribute($name, $value) { if (property_exists ( $this, $name )) $this->$name = $value; elseif (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; } } elseif (! 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; elseif ($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 ); } public function getActiveFinder($with) { return new CActiveFinder ( $this, $with ); } public function onBeforeCount($event) { $this->raiseEvent ( 'onBeforeCount', $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 ); $this->onBeforeFind ( $event ); } } protected function beforeCount() { if ($this->hasEventHandler ( 'onBeforeCount' )) $this->onBeforeCount ( new CEvent ( $this ) ); } 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 ); elseif (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 (($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}; elseif (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; elseif (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, $this->getTableAlias () ); return $all ? $this->populateRecords ( $command->queryAll (), true, $criteria->index ) : $this->populateRecord ( $command->queryRow () ); } else { $finder = $this->getActiveFinder ( $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 (); } elseif (is_array ( $v )) { $scope = key ( $v ); $params = current ( $v ); } } elseif (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->resetScope ( false ); } } 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->resetScope ( false ); $finder = $this->getActiveFinder ( $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->resetScope ( false ); $finder = $this->getActiveFinder ( $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 (); $this->beforeCount (); $criteria = $builder->createCriteria ( $condition, $params ); $this->applyScopes ( $criteria ); if (empty ( $criteria->with )) return $builder->createCountCommand ( $this->getTableSchema (), $criteria )->queryScalar (); else { $finder = $this->getActiveFinder ( $criteria->with ); return $finder->count ( $criteria ); } } public function countByAttributes($attributes, $condition = '', $params = array()) { $prefix = $this->getTableAlias ( true ) . '.'; $builder = $this->getCommandBuilder (); $this->beforeCount (); $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 = $this->getActiveFinder ( $criteria->with ); return $finder->count ( $criteria ); } } public function countBySql($sql, $params = array()) { $this->beforeCount (); 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, $this->getTableAlias ( false, false ) )->queryRow () !== false; else { $criteria->select = '*'; $finder = $this->getActiveFinder ( $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; elseif (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']; elseif ($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']; elseif ($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']; elseif ($criteria ['order'] !== '') $this->order = $criteria ['order'] . ', ' . $this->order; } if (isset ( $criteria ['group'] ) && $this->group !== $criteria ['group']) { if ($this->group === '') $this->group = $criteria ['group']; elseif ($criteria ['group'] !== '') $this->group .= ', ' . $criteria ['group']; } if (isset ( $criteria ['join'] ) && $this->join !== $criteria ['join']) { if ($this->join === '') $this->join = $criteria ['join']; elseif ($criteria ['join'] !== '') $this->join .= ' ' . $criteria ['join']; } if (isset ( $criteria ['having'] ) && $this->having !== $criteria ['having']) { if ($this->having === '') $this->having = $criteria ['having']; elseif ($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 $through; 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']; elseif ($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']; elseif ($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 { } class CHasManyRelation extends CActiveRelation { public $limit = - 1; public $offset = - 1; public $index; 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 { private $_junctionTableName = null; private $_junctionForeignKeys = null; public function getJunctionTableName() { if ($this->_junctionTableName === null) $this->initJunctionData (); return $this->_junctionTableName; } public function getJunctionForeignKeys() { if ($this->_junctionForeignKeys === null) $this->initJunctionData (); return $this->_junctionForeignKeys; } private function initJunctionData() { if (! preg_match ( '/^\s*(.*?)\((.*)\)\s*$/', $this->foreignKey, $matches )) throw new CDbException ( Yii::t ( 'yii', 'The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key. The format of the foreign key must be "joinTable(fk1,fk2,...)".', array ( '{class}' => $this->className, '{relation}' => $this->name ) ) ); $this->_junctionTableName = $matches [1]; $this->_junctionForeignKeys = preg_split ( '/\s*,\s*/', $matches [2], - 1, PREG_SPLIT_NO_EMPTY ); } } class CActiveRecordMetaData { public $tableSchema; public $columns; public $relations = array (); public $attributeDefaults = array (); private $_modelClassName; public function __construct($model) { $this->_modelClassName = get_class ( $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}' => $this->_modelClassName, '{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; elseif (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}' => $this->_modelClassName, '{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 ( '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 ( 'CDbConnection failed to open the DB connection: ' . $e->getMessage (), ( int ) $e->getCode (), $e->errorInfo ); } else { Yii::log ( $e->getMessage (), CLogger::LEVEL_ERROR, 'exception.CDbException' ); throw new CDbException ( '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') $pdoClass = 'CMssqlPdoAdapter'; elseif ($driver === 'sqlsrv') $pdoClass = 'CMssqlSqlsrvPdoAdapter'; } if (! class_exists ( $pdoClass )) throw new CDbException ( Yii::t ( 'yii', 'CDbConnection is unable to find PDO class "{className}". Make sure PDO is installed correctly.', array ( '{className}' => $pdoClass ) ) ); @$instance = new $pdoClass ( $this->connectionString, $this->username, $this->password, $this->_attributes ); if (! $instance) throw new CDbException ( Yii::t ( 'yii', 'CDbConnection failed to open the DB connection.' ) ); return $instance; } 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, 'resource' => PDO::PARAM_LOB, '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]; elseif (($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 ); } public function addPrimaryKey($name, $table, $columns) { if (is_string ( $columns )) $columns = preg_split ( '/\s*,\s*/', $columns, - 1, PREG_SPLIT_NO_EMPTY ); foreach ( $columns as $i => $col ) $columns [$i] = $this->quoteColumnName ( $col ); return 'ALTER TABLE ' . $this->quoteTableName ( $table ) . ' ADD CONSTRAINT ' . $this->quoteColumnName ( $name ) . ' PRIMARY KEY (' . implode ( ', ', $columns ) . ' )'; } public function dropPrimaryKey($name, $table) { return 'ALTER TABLE ' . $this->quoteTableName ( $table ) . ' DROP CONSTRAINT ' . $this->quoteColumnName ( $name ); } } 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) return; if ($value !== null) $value = ( int ) ($value) - 1; else $value = ( int ) $this->getDbConnection ()->createCommand ( "SELECT MAX(`{$table->primaryKey}`) FROM {$table->rawName}" )->queryScalar (); try { // it's possible that '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 = '') { $this->getDbConnection ()->createCommand ( 'PRAGMA foreign_keys=' . ( int ) $check )->execute (); } 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; elseif (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->comment = null; // SQLite does not support column comments at all $c->init ( strtolower ( $column ['type'] ), $column ['dflt_value'] ); return $c; } public function renameTable($table, $newName) { return 'ALTER TABLE ' . $this->quoteTableName ( $table ) . ' RENAME TO ' . $this->quoteTableName ( $newName ); } 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 ); } public function addPrimaryKey($name, $table, $columns) { throw new CDbException ( Yii::t ( 'yii', 'Adding a primary key after table has been created is not supported by SQLite.' ) ); } public function dropPrimaryKey($name, $table) { throw new CDbException ( Yii::t ( 'yii', 'Removing a primary key after table has been created is not supported by SQLite.' ) ); } } 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 ) ) ); elseif ($length === null) $this->_statement->bindParam ( $name, $value, $dataType ); elseif ($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 () . $par . ')', '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 () . $par . ')', 'system.db.CDbCommand.execute' ); return $n; } catch ( Exception $e ) { if ($this->_connection->enableProfiling) Yii::endProfile ( 'system.db.CDbCommand.execute(' . $this->getText () . $par . ')', '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', array ( PDO::FETCH_COLUMN, 0 ), $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 [0]; } } 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; call_user_func_array ( array ( $this->_statement, 'setFetchMode' ), $mode ); $result = $this->_statement->$method (); $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, array ( $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 = ! empty ( $query ['distinct'] ) ? 'SELECT DISTINCT' : 'SELECT'; $sql .= ' ' . (! empty ( $query ['select'] ) ? $query ['select'] : '*'); if (! empty ( $query ['from'] )) $sql .= "\nFROM " . $query ['from']; else throw new CDbException ( Yii::t ( 'yii', 'The DB query must contain the "from" portion.' ) ); if (! empty ( $query ['join'] )) $sql .= "\n" . (is_array ( $query ['join'] ) ? implode ( "\n", $query ['join'] ) : $query ['join']); if (! empty ( $query ['where'] )) $sql .= "\nWHERE " . $query ['where']; if (! empty ( $query ['group'] )) $sql .= "\nGROUP BY " . $query ['group']; if (! empty ( $query ['having'] )) $sql .= "\nHAVING " . $query ['having']; if (! empty ( $query ['union'] )) $sql .= "\nUNION (\n" . (is_array ( $query ['union'] ) ? implode ( "\n) UNION (\n", $query ['union'] ) : $query ['union']) . ')'; if (! empty ( $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 ); 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; elseif (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 andWhere($conditions, $params = array()) { if (isset ( $this->_query ['where'] )) $this->_query ['where'] = $this->processConditions ( array ( 'AND', $this->_query ['where'], $conditions ) ); else $this->_query ['where'] = $this->processConditions ( $conditions ); foreach ( $params as $name => $value ) $this->params [$name] = $value; return $this; } public function orWhere($conditions, $params = array()) { if (isset ( $this->_query ['where'] )) $this->_query ['where'] = $this->processConditions ( array ( 'OR', $this->_query ['where'], $conditions ) ); else $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; elseif (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; elseif (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; elseif ($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; } public function addPrimaryKey($name, $table, $columns) { return $this->setText ( $this->getConnection ()->getSchema ()->addPrimaryKey ( $name, $table, $columns ) )->execute (); } public function dropPrimaryKey($name, $table) { return $this->setText ( $this->getConnection ()->getSchema ()->dropPrimaryKey ( $name, $table ) )->execute (); } } 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 $comment = ''; 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'; elseif (stripos ( $dbType, 'bool' ) !== false) $this->type = 'boolean'; elseif (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->dbType === 'timestamp' && $defaultValue === 'CURRENT_TIMESTAMP') $this->defaultValue = null; else $this->defaultValue = $this->typecast ( strcasecmp ( $defaultValue, 'null' ) ? $defaultValue : null ); if ($this->type === 'string' && $this->defaultValue !== null) // PHP 5.2.6 adds single quotes while 5.2.0 doesn't $this->defaultValue = trim ( $this->defaultValue, "'\"" ); } } 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 $except; 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 (isset ( $params ['except'] )) { if (is_array ( $params ['except'] )) $except = $params ['except']; else $except = preg_split ( '/[\s,]+/', $params ['except'], - 1, PREG_SPLIT_NO_EMPTY ); } else $except = 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 ); $validator->except = empty ( $except ) ? array () : array_combine ( $except, $except ); 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) { if (isset ( $this->except [$scenario] )) return false; 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 (is_array ( $value )) { // https://github.com/yiisoft/yii/issues/1955 $this->addError ( $object, $attribute, Yii::t ( 'yii', '{attribute} is invalid.' ) ); 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(jQuery.trim(value)!='') { $js } "; } return $js; } } class CRequiredValidator extends CValidator { public $requiredValue; public $strict = false; public $trim = true; 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 ); } } elseif ($this->isEmpty ( $value, $this->trim )) { $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 ) ) ); if ($this->trim) $emptyCondition = "jQuery.trim(value)==''"; else $emptyCondition = "value==''"; return " if({$emptyCondition}) { 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 (! is_numeric ( $value )) { // https://github.com/yiisoft/yii/issues/1955 // https://github.com/yiisoft/yii/issues/1669 $message = $this->message !== null ? $this->message : Yii::t ( 'yii', '{attribute} must be a number.' ); $this->addError ( $object, $attribute, $message ); 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(jQuery.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()); public function loginRequired(); } 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(); } interface ILogFilter { public function filter(&$logs); } ?>