Browse Source
* master: (117 commits) More Model tests Better validation rules validity check Some tests for Model A bit more friendly behavior for unsetting a model attribute User WIP. Fixed Model::getFirstErrors() Finished AccessControl. Finished HttpCache. User WIP line ending fix. refactoring cache and db references. Fixed session bug. Finishes flash feature. refactored url creation shortcut method. HttpCache WIP. Finished AccessControl and HttpCache. Finished PageCache. finished fragment caching. fragment cache WIP bug fixes. ...tags/2.0.0-beta
Carsten Brandt
12 years ago
214 changed files with 12582 additions and 7160 deletions
@ -0,0 +1,19 @@
|
||||
Yii2 class loader |
||||
================= |
||||
|
||||
Yii 2 class loader is PSR-0 compliant. That means it can handle most of the PHP |
||||
libraries and frameworks out there. |
||||
|
||||
In order to autoload a library you need to set a root alias for it. |
||||
|
||||
PEAR-style libraries |
||||
-------------------- |
||||
|
||||
```php |
||||
\Yii::setAlias('@Twig', '@app/vendors/Twig'); |
||||
``` |
||||
|
||||
References |
||||
---------- |
||||
|
||||
- YiiBase::autoload |
@ -0,0 +1,90 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class ActionFilter extends Behavior |
||||
{ |
||||
/** |
||||
* @var array list of action IDs that this filter should apply to. If this property is not set, |
||||
* then the filter applies to all actions, unless they are listed in [[except]]. |
||||
*/ |
||||
public $only; |
||||
/** |
||||
* @var array list of action IDs that this filter should not apply to. |
||||
*/ |
||||
public $except = array(); |
||||
|
||||
/** |
||||
* Declares event handlers for the [[owner]]'s events. |
||||
* @return array events (array keys) and the corresponding event handler methods (array values). |
||||
*/ |
||||
public function events() |
||||
{ |
||||
return array( |
||||
'beforeAction' => 'beforeFilter', |
||||
'afterAction' => 'afterFilter', |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* @param ActionEvent $event |
||||
* @return boolean |
||||
*/ |
||||
public function beforeFilter($event) |
||||
{ |
||||
if ($this->isActive($event->action)) { |
||||
$event->isValid = $this->beforeAction($event->action); |
||||
} |
||||
return $event->isValid; |
||||
} |
||||
|
||||
/** |
||||
* @param ActionEvent $event |
||||
* @return boolean |
||||
*/ |
||||
public function afterFilter($event) |
||||
{ |
||||
if ($this->isActive($event->action)) { |
||||
$this->afterAction($event->action); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method is invoked right before an action is to be executed (after all possible filters.) |
||||
* You may override this method to do last-minute preparation for the action. |
||||
* @param Action $action the action to be executed. |
||||
* @return boolean whether the action should continue to be executed. |
||||
*/ |
||||
public function beforeAction($action) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* This method is invoked right after an action is executed. |
||||
* You may override this method to do some postprocessing for the action. |
||||
* @param Action $action the action just executed. |
||||
*/ |
||||
public function afterAction($action) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether the filer is active for the given action. |
||||
* @param Action $action the action being filtered |
||||
* @return boolean whether the filer is active for the given action. |
||||
*/ |
||||
protected function isActive($action) |
||||
{ |
||||
return !in_array($action->id, $this->except, true) && (empty($this->only) || in_array($action->id, $this->only, true)); |
||||
} |
||||
} |
@ -0,0 +1,81 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* ErrorException represents a PHP error. |
||||
* |
||||
* @author Alexander Makarov <sam@rmcreative.ru> |
||||
* @since 2.0 |
||||
*/ |
||||
class ErrorException extends Exception |
||||
{ |
||||
protected $severity; |
||||
|
||||
/** |
||||
* Constructs the exception |
||||
* @link http://php.net/manual/en/errorexception.construct.php |
||||
* @param $message [optional] |
||||
* @param $code [optional] |
||||
* @param $severity [optional] |
||||
* @param $filename [optional] |
||||
* @param $lineno [optional] |
||||
* @param $previous [optional] |
||||
*/ |
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null) |
||||
{ |
||||
parent::__construct($message, $code, $previous); |
||||
$this->severity = $severity; |
||||
$this->file = $filename; |
||||
$this->line = $lineno; |
||||
} |
||||
|
||||
/** |
||||
* Gets the exception severity |
||||
* @link http://php.net/manual/en/errorexception.getseverity.php |
||||
* @return int the severity level of the exception. |
||||
*/ |
||||
final public function getSeverity() |
||||
{ |
||||
return $this->severity; |
||||
} |
||||
|
||||
/** |
||||
* Returns if error is one of fatal type |
||||
* |
||||
* @param array $error error got from error_get_last() |
||||
* @return bool if error is one of fatal type |
||||
*/ |
||||
public static function isFatalErorr($error) |
||||
{ |
||||
return isset($error['type']) && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING)); |
||||
} |
||||
|
||||
/** |
||||
* @return string the user-friendly name of this exception |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
$names = array( |
||||
E_ERROR => \Yii::t('yii|Fatal Error'), |
||||
E_PARSE => \Yii::t('yii|Parse Error'), |
||||
E_CORE_ERROR => \Yii::t('yii|Core Error'), |
||||
E_COMPILE_ERROR => \Yii::t('yii|Compile Error'), |
||||
E_USER_ERROR => \Yii::t('yii|User Error'), |
||||
E_WARNING => \Yii::t('yii|Warning'), |
||||
E_CORE_WARNING => \Yii::t('yii|Core Warning'), |
||||
E_COMPILE_WARNING => \Yii::t('yii|Compile Warning'), |
||||
E_USER_WARNING => \Yii::t('yii|User Warning'), |
||||
E_STRICT => \Yii::t('yii|Strict'), |
||||
E_NOTICE => \Yii::t('yii|Notice'), |
||||
E_RECOVERABLE_ERROR => \Yii::t('yii|Recoverable Error'), |
||||
E_DEPRECATED => \Yii::t('yii|Deprecated'), |
||||
); |
||||
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : \Yii::t('yii|Error'); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* InvalidParamException represents an exception caused by invalid parameters passed to a method. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class InvalidParamException extends Exception |
||||
{ |
||||
/** |
||||
* @return string the user-friendly name of this exception |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return \Yii::t('yii|Invalid Parameter'); |
||||
} |
||||
} |
||||
|
@ -1,290 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* SecurityManager class file. |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* SecurityManager provides private keys, hashing and encryption functions. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class SecurityManager extends Component |
||||
{ |
||||
const STATE_VALIDATION_KEY = 'Yii.SecurityManager.validationkey'; |
||||
const STATE_ENCRYPTION_KEY = 'Yii.SecurityManager.encryptionkey'; |
||||
|
||||
/** |
||||
* @var string the name of the hashing algorithm to be used by {@link computeHMAC}. |
||||
* See {@link http://php.net/manual/en/function.hash-algos.php hash-algos} for the list of possible |
||||
* hash algorithms. Note that if you are using PHP 5.1.1 or below, you can only use 'sha1' or 'md5'. |
||||
* |
||||
* Defaults to 'sha1', meaning using SHA1 hash algorithm. |
||||
*/ |
||||
public $hashAlgorithm = 'sha1'; |
||||
/** |
||||
* @var mixed the name of the crypt algorithm to be used by {@link encrypt} and {@link decrypt}. |
||||
* This will be passed as the first parameter to {@link http://php.net/manual/en/function.mcrypt-module-open.php mcrypt_module_open}. |
||||
* |
||||
* This property can also be configured as an array. In this case, the array elements will be passed in order |
||||
* as parameters to mcrypt_module_open. For example, <code>array('rijndael-256', '', 'ofb', '')</code>. |
||||
* |
||||
* Defaults to 'des', meaning using DES crypt algorithm. |
||||
*/ |
||||
public $cryptAlgorithm = 'des'; |
||||
|
||||
private $_validationKey; |
||||
private $_encryptionKey; |
||||
|
||||
/** |
||||
* @return string a randomly generated private key |
||||
*/ |
||||
protected function generateRandomKey() |
||||
{ |
||||
return sprintf('%08x%08x%08x%08x', mt_rand(), mt_rand(), mt_rand(), mt_rand()); |
||||
} |
||||
|
||||
/** |
||||
* @return string the private key used to generate HMAC. |
||||
* If the key is not explicitly set, a random one is generated and returned. |
||||
*/ |
||||
public function getValidationKey() |
||||
{ |
||||
if ($this->_validationKey !== null) { |
||||
return $this->_validationKey; |
||||
} else { |
||||
if (($key = \Yii::$application->getGlobalState(self::STATE_VALIDATION_KEY)) !== null) { |
||||
$this->setValidationKey($key); |
||||
} else { |
||||
$key = $this->generateRandomKey(); |
||||
$this->setValidationKey($key); |
||||
\Yii::$application->setGlobalState(self::STATE_VALIDATION_KEY, $key); |
||||
} |
||||
return $this->_validationKey; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param string $value the key used to generate HMAC |
||||
* @throws CException if the key is empty |
||||
*/ |
||||
public function setValidationKey($value) |
||||
{ |
||||
if (!empty($value)) { |
||||
$this->_validationKey = $value; |
||||
} else { |
||||
throw new CException(Yii::t('yii', 'SecurityManager.validationKey cannot be empty.')); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return string the private key used to encrypt/decrypt data. |
||||
* If the key is not explicitly set, a random one is generated and returned. |
||||
*/ |
||||
public function getEncryptionKey() |
||||
{ |
||||
if ($this->_encryptionKey !== null) { |
||||
return $this->_encryptionKey; |
||||
} else { |
||||
if (($key = \Yii::$application->getGlobalState(self::STATE_ENCRYPTION_KEY)) !== null) { |
||||
$this->setEncryptionKey($key); |
||||
} else { |
||||
$key = $this->generateRandomKey(); |
||||
$this->setEncryptionKey($key); |
||||
\Yii::$application->setGlobalState(self::STATE_ENCRYPTION_KEY, $key); |
||||
} |
||||
return $this->_encryptionKey; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param string $value the key used to encrypt/decrypt data. |
||||
* @throws CException if the key is empty |
||||
*/ |
||||
public function setEncryptionKey($value) |
||||
{ |
||||
if (!empty($value)) { |
||||
$this->_encryptionKey = $value; |
||||
} else { |
||||
throw new CException(Yii::t('yii', 'SecurityManager.encryptionKey cannot be empty.')); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method has been deprecated since version 1.1.3. |
||||
* Please use {@link hashAlgorithm} instead. |
||||
* @return string |
||||
*/ |
||||
public function getValidation() |
||||
{ |
||||
return $this->hashAlgorithm; |
||||
} |
||||
|
||||
/** |
||||
* This method has been deprecated since version 1.1.3. |
||||
* Please use {@link hashAlgorithm} instead. |
||||
* @param string $value - |
||||
*/ |
||||
public function setValidation($value) |
||||
{ |
||||
$this->hashAlgorithm = $value; |
||||
} |
||||
|
||||
/** |
||||
* Encrypts data. |
||||
* @param string $data data to be encrypted. |
||||
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}. |
||||
* @return string the encrypted data |
||||
* @throws CException if PHP Mcrypt extension is not loaded |
||||
*/ |
||||
public function encrypt($data, $key = null) |
||||
{ |
||||
$module = $this->openCryptModule(); |
||||
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module)); |
||||
srand(); |
||||
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); |
||||
mcrypt_generic_init($module, $key, $iv); |
||||
$encrypted = $iv . mcrypt_generic($module, $data); |
||||
mcrypt_generic_deinit($module); |
||||
mcrypt_module_close($module); |
||||
return $encrypted; |
||||
} |
||||
|
||||
/** |
||||
* Decrypts data |
||||
* @param string $data data to be decrypted. |
||||
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}. |
||||
* @return string the decrypted data |
||||
* @throws CException if PHP Mcrypt extension is not loaded |
||||
*/ |
||||
public function decrypt($data, $key = null) |
||||
{ |
||||
$module = $this->openCryptModule(); |
||||
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module)); |
||||
$ivSize = mcrypt_enc_get_iv_size($module); |
||||
$iv = $this->substr($data, 0, $ivSize); |
||||
mcrypt_generic_init($module, $key, $iv); |
||||
$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data))); |
||||
mcrypt_generic_deinit($module); |
||||
mcrypt_module_close($module); |
||||
return rtrim($decrypted, "\0"); |
||||
} |
||||
|
||||
/** |
||||
* Opens the mcrypt module with the configuration specified in {@link cryptAlgorithm}. |
||||
* @return resource the mycrypt module handle. |
||||
* @since 1.1.3 |
||||
*/ |
||||
protected function openCryptModule() |
||||
{ |
||||
if (extension_loaded('mcrypt')) { |
||||
if (is_array($this->cryptAlgorithm)) { |
||||
$module = @call_user_func_array('mcrypt_module_open', $this->cryptAlgorithm); |
||||
} else { |
||||
$module = @mcrypt_module_open($this->cryptAlgorithm, '', MCRYPT_MODE_CBC, ''); |
||||
} |
||||
|
||||
if ($module === false) { |
||||
throw new CException(Yii::t('yii', 'Failed to initialize the mcrypt module.')); |
||||
} |
||||
|
||||
return $module; |
||||
} else { |
||||
throw new CException(Yii::t('yii', 'SecurityManager requires PHP mcrypt extension to be loaded in order to use data encryption feature.')); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Prefixes data with an HMAC. |
||||
* @param string $data data to be hashed. |
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}. |
||||
* @return string data prefixed with HMAC |
||||
*/ |
||||
public function hashData($data, $key = null) |
||||
{ |
||||
return $this->computeHMAC($data, $key) . $data; |
||||
} |
||||
|
||||
/** |
||||
* Validates if data is tampered. |
||||
* @param string $data data to be validated. The data must be previously |
||||
* generated using {@link hashData()}. |
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}. |
||||
* @return string the real data with HMAC stripped off. False if the data |
||||
* is tampered. |
||||
*/ |
||||
public function validateData($data, $key = null) |
||||
{ |
||||
$len = $this->strlen($this->computeHMAC('test')); |
||||
if ($this->strlen($data) >= $len) { |
||||
$hmac = $this->substr($data, 0, $len); |
||||
$data2 = $this->substr($data, $len, $this->strlen($data)); |
||||
return $hmac === $this->computeHMAC($data2, $key) ? $data2 : false; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Computes the HMAC for the data with {@link getValidationKey ValidationKey}. |
||||
* @param string $data data to be generated HMAC |
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}. |
||||
* @return string the HMAC for the data |
||||
*/ |
||||
protected function computeHMAC($data, $key = null) |
||||
{ |
||||
if ($key === null) { |
||||
$key = $this->getValidationKey(); |
||||
} |
||||
|
||||
if (function_exists('hash_hmac')) { |
||||
return hash_hmac($this->hashAlgorithm, $data, $key); |
||||
} |
||||
|
||||
if (!strcasecmp($this->hashAlgorithm, 'sha1')) { |
||||
$pack = 'H40'; |
||||
$func = 'sha1'; |
||||
} else { |
||||
$pack = 'H32'; |
||||
$func = 'md5'; |
||||
} |
||||
if ($this->strlen($key) > 64) { |
||||
$key = pack($pack, $func($key)); |
||||
} |
||||
if ($this->strlen($key) < 64) { |
||||
$key = str_pad($key, 64, chr(0)); |
||||
} |
||||
$key = $this->substr($key, 0, 64); |
||||
return $func((str_repeat(chr(0x5C), 64) ^ $key) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ $key) . $data))); |
||||
} |
||||
|
||||
/** |
||||
* Returns the length of the given string. |
||||
* If available uses the multibyte string function mb_strlen. |
||||
* @param string $string the string being measured for length |
||||
* @return int the length of the string |
||||
*/ |
||||
private function strlen($string) |
||||
{ |
||||
return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string); |
||||
} |
||||
|
||||
/** |
||||
* Returns the portion of string specified by the start and length parameters. |
||||
* If available uses the multibyte string function mb_substr |
||||
* @param string $string the input string. Must be one character or longer. |
||||
* @param int $start the starting position |
||||
* @param int $length the desired portion length |
||||
* @return string the extracted part of string, or FALSE on failure or an empty string. |
||||
*/ |
||||
private function substr($string, $start, $length) |
||||
{ |
||||
return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length); |
||||
} |
||||
} |
@ -1,837 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* UrlManager class file |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
use \yii\base\Component; |
||||
|
||||
/** |
||||
* UrlManager manages the URLs of Yii applications. |
||||
* |
||||
* It provides URL construction ({@link createUrl()}) as well as parsing ({@link parseUrl()}) functionality. |
||||
* |
||||
* URLs managed via UrlManager can be in one of the following two formats, |
||||
* by setting {@link setUrlFormat urlFormat} property: |
||||
* <ul> |
||||
* <li>'path' format: /path/to/EntryScript.php/name1/value1/name2/value2...</li> |
||||
* <li>'get' format: /path/to/EntryScript.php?name1=value1&name2=value2...</li> |
||||
* </ul> |
||||
* |
||||
* When using 'path' format, UrlManager uses a set of {@link setRules rules} to: |
||||
* <ul> |
||||
* <li>parse the requested URL into a route ('ControllerID/ActionID') and GET parameters;</li> |
||||
* <li>create URLs based on the given route and GET parameters.</li> |
||||
* </ul> |
||||
* |
||||
* A rule consists of a route and a pattern. The latter is used by UrlManager to determine |
||||
* which rule is used for parsing/creating URLs. A pattern is meant to match the path info |
||||
* part of a URL. It may contain named parameters using the syntax '<ParamName:RegExp>'. |
||||
* |
||||
* When parsing a URL, a matching rule will extract the named parameters from the path info |
||||
* and put them into the $_GET variable; when creating a URL, a matching rule will extract |
||||
* the named parameters from $_GET and put them into the path info part of the created URL. |
||||
* |
||||
* If a pattern ends with '/*', it means additional GET parameters may be appended to the path |
||||
* info part of the URL; otherwise, the GET parameters can only appear in the query string part. |
||||
* |
||||
* To specify URL rules, set the {@link setRules rules} property as an array of rules (pattern=>route). |
||||
* For example, |
||||
* <pre> |
||||
* array( |
||||
* 'articles'=>'article/list', |
||||
* 'article/<id:\d+>/*'=>'article/read', |
||||
* ) |
||||
* </pre> |
||||
* Two rules are specified in the above: |
||||
* <ul> |
||||
* <li>The first rule says that if the user requests the URL '/path/to/index.php/articles', |
||||
* it should be treated as '/path/to/index.php/article/list'; and vice versa applies |
||||
* when constructing such a URL.</li> |
||||
* <li>The second rule contains a named parameter 'id' which is specified using |
||||
* the <ParamName:RegExp> syntax. It says that if the user requests the URL |
||||
* '/path/to/index.php/article/13', it should be treated as '/path/to/index.php/article/read?id=13'; |
||||
* and vice versa applies when constructing such a URL.</li> |
||||
* </ul> |
||||
* |
||||
* The route part may contain references to named parameters defined in the pattern part. |
||||
* This allows a rule to be applied to different routes based on matching criteria. |
||||
* For example, |
||||
* <pre> |
||||
* array( |
||||
* '<_c:(post|comment)>/<id:\d+>/<_a:(create|update|delete)>'=>'<_c>/<_a>', |
||||
* '<_c:(post|comment)>/<id:\d+>'=>'<_c>/view', |
||||
* '<_c:(post|comment)>s/*'=>'<_c>/list', |
||||
* ) |
||||
* </pre> |
||||
* In the above, we use two named parameters '<_c>' and '<_a>' in the route part. The '<_c>' |
||||
* parameter matches either 'post' or 'comment', while the '<_a>' parameter matches an action ID. |
||||
* |
||||
* Like normal rules, these rules can be used for both parsing and creating URLs. |
||||
* For example, using the rules above, the URL '/index.php/post/123/create' |
||||
* would be parsed as the route 'post/create' with GET parameter 'id' being 123. |
||||
* And given the route 'post/list' and GET parameter 'page' being 2, we should get a URL |
||||
* '/index.php/posts/page/2'. |
||||
* |
||||
* It is also possible to include hostname into the rules for parsing and creating URLs. |
||||
* One may extract part of the hostname to be a GET parameter. |
||||
* For example, the URL <code>http://admin.example.com/en/profile</code> may be parsed into GET parameters |
||||
* <code>user=admin</code> and <code>lang=en</code>. On the other hand, rules with hostname may also be used to |
||||
* create URLs with parameterized hostnames. |
||||
* |
||||
* In order to use parameterized hostnames, simply declare URL rules with host info, e.g.: |
||||
* <pre> |
||||
* array( |
||||
* 'http://<user:\w+>.example.com/<lang:\w+>/profile' => 'user/profile', |
||||
* ) |
||||
* </pre> |
||||
* |
||||
* If you want to customize URL generation and parsing you can write custom |
||||
* URL rule classes and use them for one or several URL rules. For example, |
||||
* <pre> |
||||
* array( |
||||
* // a standard rule |
||||
* '<action:(login|logout)>' => 'site/<action>', |
||||
* // a custom rule using data in DB |
||||
* array( |
||||
* 'class' => '\application\components\MyUrlRule', |
||||
* 'connectionID' => 'db', |
||||
* ), |
||||
* ) |
||||
* </pre> |
||||
* Please note that the custom URL rule class should extend from {@link BaseUrlRule} and |
||||
* implement the following two methods, |
||||
* <ul> |
||||
* <li>{@link BaseUrlRule::createUrl()}</li> |
||||
* <li>{@link BaseUrlRule::parseUrl()}</li> |
||||
* </ul> |
||||
* |
||||
* UrlManager is a default application component that may be accessed via |
||||
* {@link \Yii::$application->urlManager}. |
||||
* |
||||
* @property string $baseUrl The base URL of the application (the part after host name and before query string). |
||||
* If {@link showScriptName} is true, it will include the script name part. |
||||
* Otherwise, it will not, and the ending slashes are stripped off. |
||||
* @property string $urlFormat The URL format. Defaults to 'path'. Valid values include 'path' and 'get'. |
||||
* Please refer to the guide for more details about the difference between these two formats. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class UrlManager extends Component |
||||
{ |
||||
const CACHE_KEY='Yii.UrlManager.rules'; |
||||
const GET_FORMAT='get'; |
||||
const PATH_FORMAT='path'; |
||||
|
||||
/** |
||||
* @var array the URL rules (pattern=>route). |
||||
*/ |
||||
public $rules=array(); |
||||
/** |
||||
* @var string the URL suffix used when in 'path' format. |
||||
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page. Defaults to empty. |
||||
*/ |
||||
public $urlSuffix=''; |
||||
/** |
||||
* @var boolean whether to show entry script name in the constructed URL. Defaults to true. |
||||
*/ |
||||
public $showScriptName=true; |
||||
/** |
||||
* @var boolean whether to append GET parameters to the path info part. Defaults to true. |
||||
* This property is only effective when {@link urlFormat} is 'path' and is mainly used when |
||||
* creating URLs. When it is true, GET parameters will be appended to the path info and |
||||
* separate from each other using slashes. If this is false, GET parameters will be in query part. |
||||
*/ |
||||
public $appendParams=true; |
||||
/** |
||||
* @var string the GET variable name for route. Defaults to 'r'. |
||||
*/ |
||||
public $routeVar='r'; |
||||
/** |
||||
* @var boolean whether routes are case-sensitive. Defaults to true. By setting this to false, |
||||
* the route in the incoming request will be turned to lower case first before further processing. |
||||
* As a result, you should follow the convention that you use lower case when specifying |
||||
* controller mapping ({@link CWebApplication::controllerMap}) and action mapping |
||||
* ({@link CController::actions}). Also, the directory names for organizing controllers should |
||||
* be in lower case. |
||||
*/ |
||||
public $caseSensitive=true; |
||||
/** |
||||
* @var boolean whether the GET parameter values should match the corresponding |
||||
* sub-patterns in a rule before using it to create a URL. Defaults to false, meaning |
||||
* a rule will be used for creating a URL only if its route and parameter names match the given ones. |
||||
* If this property is set true, then the given parameter values must also match the corresponding |
||||
* parameter sub-patterns. Note that setting this property to true will degrade performance. |
||||
* @since 1.1.0 |
||||
*/ |
||||
public $matchValue=false; |
||||
/** |
||||
* @var string the ID of the cache application component that is used to cache the parsed URL rules. |
||||
* Defaults to 'cache' which refers to the primary cache application component. |
||||
* Set this property to false if you want to disable caching URL rules. |
||||
*/ |
||||
public $cacheID='cache'; |
||||
/** |
||||
* @var boolean whether to enable strict URL parsing. |
||||
* This property is only effective when {@link urlFormat} is 'path'. |
||||
* If it is set true, then an incoming URL must match one of the {@link rules URL rules}. |
||||
* Otherwise, it will be treated as an invalid request and trigger a 404 HTTP exception. |
||||
* Defaults to false. |
||||
*/ |
||||
public $useStrictParsing=false; |
||||
/** |
||||
* @var string the class name or path alias for the URL rule instances. Defaults to 'CUrlRule'. |
||||
* If you change this to something else, please make sure that the new class must extend from |
||||
* {@link CBaseUrlRule} and have the same constructor signature as {@link CUrlRule}. |
||||
* It must also be serializable and autoloadable. |
||||
*/ |
||||
public $urlRuleClass='UrlRule'; |
||||
|
||||
private $_urlFormat=self::GET_FORMAT; |
||||
private $_rules=array(); |
||||
private $_baseUrl; |
||||
|
||||
|
||||
/** |
||||
* Initializes the application component. |
||||
*/ |
||||
public function init() |
||||
{ |
||||
parent::init(); |
||||
$this->processRules(); |
||||
} |
||||
|
||||
/** |
||||
* Processes the URL rules. |
||||
*/ |
||||
protected function processRules() |
||||
{ |
||||
if(empty($this->rules) || $this->getUrlFormat()===self::GET_FORMAT) |
||||
return; |
||||
if($this->cacheID!==false && ($cache=\Yii::$application->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)); |
||||
} |
||||
|
||||
/** |
||||
* Adds new URL rules. |
||||
* In order to make the new rules effective, this method must be called BEFORE |
||||
* {@link CWebApplication::processRequest}. |
||||
* @param array $rules new URL rules (pattern=>route). |
||||
* @param boolean $append whether the new URL rules should be appended to the existing ones. If false, |
||||
* they will be inserted at the beginning. |
||||
*/ |
||||
public function addRules($rules, $append=true) |
||||
{ |
||||
if ($append) |
||||
{ |
||||
foreach($rules as $pattern=>$route) |
||||
$this->_rules[]=$this->createUrlRule($route,$pattern); |
||||
} |
||||
else |
||||
{ |
||||
foreach($rules as $pattern=>$route) |
||||
array_unshift($this->_rules, $this->createUrlRule($route,$pattern)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL rule instance. |
||||
* The default implementation returns a CUrlRule object. |
||||
* @param mixed $route the route part of the rule. This could be a string or an array |
||||
* @param string $pattern the pattern part of the rule |
||||
* @return CUrlRule the URL rule instance |
||||
*/ |
||||
protected function createUrlRule($route,$pattern) |
||||
{ |
||||
if(is_array($route) && isset($route['class'])) |
||||
return $route; |
||||
else |
||||
return new $this->urlRuleClass($route,$pattern); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a URL. |
||||
* @param string $route the controller and the action (e.g. article/read) |
||||
* @param array $params list of GET parameters (name=>value). Both the name and value will be URL-encoded. |
||||
* If the name is '#', the corresponding value will be treated as an anchor |
||||
* and will be appended at the end of the URL. |
||||
* @param string $ampersand the token separating name-value pairs in the URL. Defaults to '&'. |
||||
* @return string the constructed URL |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL based on default settings. |
||||
* @param string $route the controller and the action (e.g. article/read) |
||||
* @param array $params list of GET parameters |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return string the constructed URL |
||||
*/ |
||||
protected function createUrlDefault($route,$params,$ampersand) |
||||
{ |
||||
if($this->getUrlFormat()===self::PATH_FORMAT) |
||||
{ |
||||
$url=rtrim($this->getBaseUrl().'/'.$route,'/'); |
||||
if($this->appendParams) |
||||
{ |
||||
$url=rtrim($url.'/'.$this->createPathInfo($params,'/','/'),'/'); |
||||
return $route==='' ? $url : $url.$this->urlSuffix; |
||||
} |
||||
else |
||||
{ |
||||
if($route!=='') |
||||
$url.=$this->urlSuffix; |
||||
$query=$this->createPathInfo($params,'=',$ampersand); |
||||
return $query==='' ? $url : $url.'?'.$query; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
$url=$this->getBaseUrl(); |
||||
if(!$this->showScriptName) |
||||
$url.='/'; |
||||
if($route!=='') |
||||
{ |
||||
$url.='?'.$this->routeVar.'='.$route; |
||||
if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') |
||||
$url.=$ampersand.$query; |
||||
} |
||||
else if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') |
||||
$url.='?'.$query; |
||||
return $url; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parses the user request. |
||||
* @param HttpRequest $request the request application component |
||||
* @return string the route (controllerID/actionID) and perhaps GET parameters in path format. |
||||
*/ |
||||
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 HttpException(404,Yii::t('yii','Unable to resolve the request "{route}".', |
||||
array('{route}'=>$pathInfo))); |
||||
else |
||||
return $pathInfo; |
||||
} |
||||
else if(isset($_GET[$this->routeVar])) |
||||
return $_GET[$this->routeVar]; |
||||
else if(isset($_POST[$this->routeVar])) |
||||
return $_POST[$this->routeVar]; |
||||
else |
||||
return ''; |
||||
} |
||||
|
||||
/** |
||||
* Parses a path info into URL segments and saves them to $_GET and $_REQUEST. |
||||
* @param string $pathInfo path info |
||||
*/ |
||||
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; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a path info based on the given parameters. |
||||
* @param array $params list of GET parameters |
||||
* @param string $equal the separator between name and value |
||||
* @param string $ampersand the separator between name-value pairs |
||||
* @param string $key this is used internally. |
||||
* @return string the created path info |
||||
*/ |
||||
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); |
||||
} |
||||
|
||||
/** |
||||
* Removes the URL suffix from path info. |
||||
* @param string $pathInfo path info part in the URL |
||||
* @param string $urlSuffix the URL suffix to be removed |
||||
* @return string path info with URL suffix removed. |
||||
*/ |
||||
public function removeUrlSuffix($pathInfo,$urlSuffix) |
||||
{ |
||||
if($urlSuffix!=='' && substr($pathInfo,-strlen($urlSuffix))===$urlSuffix) |
||||
return substr($pathInfo,0,-strlen($urlSuffix)); |
||||
else |
||||
return $pathInfo; |
||||
} |
||||
|
||||
/** |
||||
* Returns the base URL of the application. |
||||
* @return string the base URL of the application (the part after host name and before query string). |
||||
* If {@link showScriptName} is true, it will include the script name part. |
||||
* Otherwise, it will not, and the ending slashes are stripped off. |
||||
*/ |
||||
public function getBaseUrl() |
||||
{ |
||||
if($this->_baseUrl!==null) |
||||
return $this->_baseUrl; |
||||
else |
||||
{ |
||||
if($this->showScriptName) |
||||
$this->_baseUrl=\Yii::$application->getRequest()->getScriptUrl(); |
||||
else |
||||
$this->_baseUrl=\Yii::$application->getRequest()->getBaseUrl(); |
||||
return $this->_baseUrl; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the base URL of the application (the part after host name and before query string). |
||||
* This method is provided in case the {@link baseUrl} cannot be determined automatically. |
||||
* The ending slashes should be stripped off. And you are also responsible to remove the script name |
||||
* if you set {@link showScriptName} to be false. |
||||
* @param string $value the base URL of the application |
||||
*/ |
||||
public function setBaseUrl($value) |
||||
{ |
||||
$this->_baseUrl=$value; |
||||
} |
||||
|
||||
/** |
||||
* Returns the URL format. |
||||
* @return string the URL format. Defaults to 'path'. Valid values include 'path' and 'get'. |
||||
* Please refer to the guide for more details about the difference between these two formats. |
||||
*/ |
||||
public function getUrlFormat() |
||||
{ |
||||
return $this->_urlFormat; |
||||
} |
||||
|
||||
/** |
||||
* Sets the URL format. |
||||
* @param string $value the URL format. It must be either 'path' or 'get'. |
||||
*/ |
||||
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".')); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* CBaseUrlRule is the base class for a URL rule class. |
||||
* |
||||
* Custom URL rule classes should extend from this class and implement two methods: |
||||
* {@link createUrl} and {@link parseUrl}. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
*/ |
||||
abstract class CBaseUrlRule extends CComponent |
||||
{ |
||||
/** |
||||
* @var boolean whether this rule will also parse the host info part. Defaults to false. |
||||
*/ |
||||
public $hasHostInfo=false; |
||||
/** |
||||
* Creates a URL based on this rule. |
||||
* @param CUrlManager $manager the manager |
||||
* @param string $route the route |
||||
* @param array $params list of parameters (name=>value) associated with the route |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return mixed the constructed URL. False if this rule does not apply. |
||||
*/ |
||||
abstract public function createUrl($manager,$route,$params,$ampersand); |
||||
/** |
||||
* Parses a URL based on this rule. |
||||
* @param UrlManager $manager the URL manager |
||||
* @param HttpRequest $request the request object |
||||
* @param string $pathInfo path info part of the URL (URL suffix is already removed based on {@link CUrlManager::urlSuffix}) |
||||
* @param string $rawPathInfo path info that contains the potential URL suffix |
||||
* @return mixed the route that consists of the controller ID and action ID. False if this rule does not apply. |
||||
*/ |
||||
abstract public function parseUrl($manager,$request,$pathInfo,$rawPathInfo); |
||||
} |
||||
|
||||
/** |
||||
* CUrlRule represents a URL formatting/parsing rule. |
||||
* |
||||
* It mainly consists of two parts: route and pattern. The former classifies |
||||
* the rule so that it only applies to specific controller-action route. |
||||
* The latter performs the actual formatting and parsing role. The pattern |
||||
* may have a set of named parameters. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
*/ |
||||
class CUrlRule extends CBaseUrlRule |
||||
{ |
||||
/** |
||||
* @var string the URL suffix used for this rule. |
||||
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page. |
||||
* Defaults to null, meaning using the value of {@link CUrlManager::urlSuffix}. |
||||
*/ |
||||
public $urlSuffix; |
||||
/** |
||||
* @var boolean whether the rule is case sensitive. Defaults to null, meaning |
||||
* using the value of {@link CUrlManager::caseSensitive}. |
||||
*/ |
||||
public $caseSensitive; |
||||
/** |
||||
* @var array the default GET parameters (name=>value) that this rule provides. |
||||
* When this rule is used to parse the incoming request, the values declared in this property |
||||
* will be injected into $_GET. |
||||
*/ |
||||
public $defaultParams=array(); |
||||
/** |
||||
* @var boolean whether the GET parameter values should match the corresponding |
||||
* sub-patterns in the rule when creating a URL. Defaults to null, meaning using the value |
||||
* of {@link CUrlManager::matchValue}. When this property is false, it means |
||||
* a rule will be used for creating a URL if its route and parameter names match the given ones. |
||||
* If this property is set true, then the given parameter values must also match the corresponding |
||||
* parameter sub-patterns. Note that setting this property to true will degrade performance. |
||||
*/ |
||||
public $matchValue; |
||||
/** |
||||
* @var string the HTTP verb (e.g. GET, POST, DELETE) that this rule should match. |
||||
* If this rule can match multiple verbs, please separate them with commas. |
||||
* If this property is not set, the rule can match any verb. |
||||
* Note that this property is only used when parsing a request. It is ignored for URL creation. |
||||
*/ |
||||
public $verb; |
||||
/** |
||||
* @var boolean whether this rule is only used for request parsing. |
||||
* Defaults to false, meaning the rule is used for both URL parsing and creation. |
||||
*/ |
||||
public $parsingOnly=false; |
||||
/** |
||||
* @var string the controller/action pair |
||||
*/ |
||||
public $route; |
||||
/** |
||||
* @var array the mapping from route param name to token name (e.g. _r1=><1>) |
||||
*/ |
||||
public $references=array(); |
||||
/** |
||||
* @var string the pattern used to match route |
||||
*/ |
||||
public $routePattern; |
||||
/** |
||||
* @var string regular expression used to parse a URL |
||||
*/ |
||||
public $pattern; |
||||
/** |
||||
* @var string template used to construct a URL |
||||
*/ |
||||
public $template; |
||||
/** |
||||
* @var array list of parameters (name=>regular expression) |
||||
*/ |
||||
public $params=array(); |
||||
/** |
||||
* @var boolean whether the URL allows additional parameters at the end of the path info. |
||||
*/ |
||||
public $append; |
||||
/** |
||||
* @var boolean whether host info should be considered for this rule |
||||
*/ |
||||
public $hasHostInfo; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string $route the route of the URL (controller/action) |
||||
* @param string $pattern the pattern for matching the URL |
||||
*/ |
||||
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))); |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL based on this rule. |
||||
* @param CUrlManager $manager the manager |
||||
* @param string $route the route |
||||
* @param array $params list of parameters |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return mixed the constructed URL or false on error |
||||
*/ |
||||
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::$application->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; |
||||
} |
||||
|
||||
/** |
||||
* Parses a URL based on this rule. |
||||
* @param UrlManager $manager the URL manager |
||||
* @param HttpRequest $request the request object |
||||
* @param string $pathInfo path info part of the URL |
||||
* @param string $rawPathInfo path info that contains the potential URL suffix |
||||
* @return mixed the route that consists of the controller ID and action ID or false on error |
||||
*/ |
||||
public function parseUrl($manager,$request,$pathInfo,$rawPathInfo) |
||||
{ |
||||
if($this->verb!==null && !in_array($request->getRequestType(), $this->verb, true)) |
||||
return false; |
||||
|
||||
if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive) |
||||
$case=''; |
||||
else |
||||
$case='i'; |
||||
|
||||
if($this->urlSuffix!==null) |
||||
$pathInfo=$manager->removeUrlSuffix($rawPathInfo,$this->urlSuffix); |
||||
|
||||
// URL suffix required, but not found in the requested URL |
||||
if($manager->useStrictParsing && $pathInfo===$rawPathInfo) |
||||
{ |
||||
$urlSuffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix; |
||||
if($urlSuffix!='' && $urlSuffix!=='/') |
||||
return false; |
||||
} |
||||
|
||||
if($this->hasHostInfo) |
||||
$pathInfo=strtolower($request->getHostInfo()).rtrim('/'.$pathInfo,'/'); |
||||
|
||||
$pathInfo.='/'; |
||||
|
||||
if(preg_match($this->pattern.$case,$pathInfo,$matches)) |
||||
{ |
||||
foreach($this->defaultParams as $name=>$value) |
||||
{ |
||||
if(!isset($_GET[$name])) |
||||
$_REQUEST[$name]=$_GET[$name]=$value; |
||||
} |
||||
$tr=array(); |
||||
foreach($matches as $key=>$value) |
||||
{ |
||||
if(isset($this->references[$key])) |
||||
$tr[$this->references[$key]]=$value; |
||||
else if(isset($this->params[$key])) |
||||
$_REQUEST[$key]=$_GET[$key]=$value; |
||||
} |
||||
if($pathInfo!==$matches[0]) // there're additional GET params |
||||
$manager->parsePathInfo(ltrim(substr($pathInfo,strlen($matches[0])),'/')); |
||||
if($this->routePattern!==null) |
||||
return strtr($this->route,$tr); |
||||
else |
||||
return $this->route; |
||||
} |
||||
else |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* UserException is the base class for exceptions that are meant to be shown to end users. |
||||
* Such exceptions are often caused by mistakes of end users. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class UserException extends Exception |
||||
{ |
||||
} |
@ -0,0 +1,28 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\console; |
||||
|
||||
use yii\base\UserException; |
||||
|
||||
/** |
||||
* Exception represents an exception caused by incorrect usage of a console command. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Exception extends UserException |
||||
{ |
||||
/** |
||||
* @return string the user-friendly name of this exception |
||||
*/ |
||||
public function getName() |
||||
{ |
||||
return \Yii::t('yii|Error'); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,47 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\console\controllers; |
||||
|
||||
use yii\console\Controller; |
||||
use yii\console\Exception; |
||||
use yii\caching\Cache; |
||||
|
||||
/** |
||||
* This command allows you to flush cache. |
||||
* |
||||
* @author Alexander Makarov <sam@rmcreative.ru> |
||||
* @since 2.0 |
||||
*/ |
||||
class CacheController extends Controller |
||||
{ |
||||
public function actionIndex() |
||||
{ |
||||
$this->forward('help/index', array('-args' => array('cache/flush'))); |
||||
} |
||||
|
||||
/** |
||||
* Flushes cache. |
||||
* @param string $component Name of the cache application component to use. |
||||
* |
||||
* @throws \yii\console\Exception |
||||
*/ |
||||
public function actionFlush($component = 'cache') |
||||
{ |
||||
/** @var $cache Cache */ |
||||
$cache = \Yii::$app->getComponent($component); |
||||
if(!$cache || !$cache instanceof Cache) { |
||||
throw new Exception('Application component "'.$component.'" is not defined or not a cache.'); |
||||
} |
||||
|
||||
if(!$cache->flush()) { |
||||
throw new Exception('Unable to flush cache.'); |
||||
} |
||||
|
||||
echo "\nDone.\n"; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
<?php |
||||
/** @var $controller \yii\console\controllers\CreateController */ |
||||
/** @var $controller \yii\console\controllers\AppController */ |
||||
$controller = $this; |
||||
|
||||
return array( |
@ -0,0 +1,981 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers; |
||||
|
||||
use Yii; |
||||
use yii\base\InvalidParamException; |
||||
|
||||
/** |
||||
* Html provides a set of static methods for generating commonly used HTML tags. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Html |
||||
{ |
||||
/** |
||||
* @var boolean whether to close void (empty) elements. Defaults to true. |
||||
* @see voidElements |
||||
*/ |
||||
public static $closeVoidElements = true; |
||||
/** |
||||
* @var array list of void elements (element name => 1) |
||||
* @see closeVoidElements |
||||
* @see http://www.w3.org/TR/html-markup/syntax.html#void-element |
||||
*/ |
||||
public static $voidElements = array( |
||||
'area' => 1, |
||||
'base' => 1, |
||||
'br' => 1, |
||||
'col' => 1, |
||||
'command' => 1, |
||||
'embed' => 1, |
||||
'hr' => 1, |
||||
'img' => 1, |
||||
'input' => 1, |
||||
'keygen' => 1, |
||||
'link' => 1, |
||||
'meta' => 1, |
||||
'param' => 1, |
||||
'source' => 1, |
||||
'track' => 1, |
||||
'wbr' => 1, |
||||
); |
||||
/** |
||||
* @var boolean whether to show the values of boolean attributes in element tags. |
||||
* If false, only the attribute names will be generated. |
||||
* @see booleanAttributes |
||||
*/ |
||||
public static $showBooleanAttributeValues = true; |
||||
/** |
||||
* @var array list of boolean attributes. The presence of a boolean attribute on |
||||
* an element represents the true value, and the absence of the attribute represents the false value. |
||||
* @see showBooleanAttributeValues |
||||
* @see http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes |
||||
*/ |
||||
public static $booleanAttributes = 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, |
||||
); |
||||
/** |
||||
* @var array the preferred order of attributes in a tag. This mainly affects the order of the attributes |
||||
* that are rendered by [[renderAttributes()]]. |
||||
*/ |
||||
public static $attributeOrder = array( |
||||
'type', |
||||
'id', |
||||
'class', |
||||
'name', |
||||
'value', |
||||
|
||||
'href', |
||||
'src', |
||||
'action', |
||||
'method', |
||||
|
||||
'selected', |
||||
'checked', |
||||
'readonly', |
||||
'disabled', |
||||
'multiple', |
||||
|
||||
'size', |
||||
'maxlength', |
||||
'width', |
||||
'height', |
||||
'rows', |
||||
'cols', |
||||
|
||||
'alt', |
||||
'title', |
||||
'rel', |
||||
'media', |
||||
); |
||||
|
||||
/** |
||||
* Encodes special characters into HTML entities. |
||||
* The [[yii\base\Application::charset|application charset]] will be used for encoding. |
||||
* @param string $content the content to be encoded |
||||
* @return string the encoded content |
||||
* @see decode |
||||
* @see http://www.php.net/manual/en/function.htmlspecialchars.php |
||||
*/ |
||||
public static function encode($content) |
||||
{ |
||||
return htmlspecialchars($content, ENT_QUOTES, Yii::$app->charset); |
||||
} |
||||
|
||||
/** |
||||
* Decodes special HTML entities back to the corresponding characters. |
||||
* This is the opposite of [[encode()]]. |
||||
* @param string $content the content to be decoded |
||||
* @return string the decoded content |
||||
* @see encode |
||||
* @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php |
||||
*/ |
||||
public static function decode($content) |
||||
{ |
||||
return htmlspecialchars_decode($content, ENT_QUOTES); |
||||
} |
||||
|
||||
/** |
||||
* Generates a complete HTML tag. |
||||
* @param string $name the tag name |
||||
* @param string $content the content to be enclosed between the start and end tags. It will not be HTML-encoded. |
||||
* If this is coming from end users, you should consider [[encode()]] it to prevent XSS attacks. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated HTML tag |
||||
* @see beginTag |
||||
* @see endTag |
||||
*/ |
||||
public static function tag($name, $content = '', $options = array()) |
||||
{ |
||||
$html = '<' . $name . static::renderTagAttributes($options); |
||||
if (isset(static::$voidElements[strtolower($name)])) { |
||||
return $html . (static::$closeVoidElements ? ' />' : '>'); |
||||
} else { |
||||
return $html . ">$content</$name>"; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Generates a start tag. |
||||
* @param string $name the tag name |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated start tag |
||||
* @see endTag |
||||
* @see tag |
||||
*/ |
||||
public static function beginTag($name, $options = array()) |
||||
{ |
||||
return '<' . $name . static::renderTagAttributes($options) . '>'; |
||||
} |
||||
|
||||
/** |
||||
* Generates an end tag. |
||||
* @param string $name the tag name |
||||
* @return string the generated end tag |
||||
* @see beginTag |
||||
* @see tag |
||||
*/ |
||||
public static function endTag($name) |
||||
{ |
||||
return "</$name>"; |
||||
} |
||||
|
||||
/** |
||||
* Encloses the given content within a CDATA tag. |
||||
* @param string $content the content to be enclosed within the CDATA tag |
||||
* @return string the CDATA tag with the enclosed content. |
||||
*/ |
||||
public static function cdata($content) |
||||
{ |
||||
return '<![CDATA[' . $content . ']]>'; |
||||
} |
||||
|
||||
/** |
||||
* Generates a style tag. |
||||
* @param string $content the style content |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* If the options does not contain "type", a "type" attribute with value "text/css" will be used. |
||||
* @return string the generated style tag |
||||
*/ |
||||
public static function style($content, $options = array()) |
||||
{ |
||||
if (!isset($options['type'])) { |
||||
$options['type'] = 'text/css'; |
||||
} |
||||
return static::tag('style', "/*<![CDATA[*/\n{$content}\n/*]]>*/", $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a script tag. |
||||
* @param string $content the script content |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* If the options does not contain "type", a "type" attribute with value "text/javascript" will be rendered. |
||||
* @return string the generated script tag |
||||
*/ |
||||
public static function script($content, $options = array()) |
||||
{ |
||||
if (!isset($options['type'])) { |
||||
$options['type'] = 'text/javascript'; |
||||
} |
||||
return static::tag('script', "/*<![CDATA[*/\n{$content}\n/*]]>*/", $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a link tag that refers to an external CSS file. |
||||
* @param array|string $url the URL of the external CSS file. This parameter will be processed by [[url()]]. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated link tag |
||||
* @see url |
||||
*/ |
||||
public static function cssFile($url, $options = array()) |
||||
{ |
||||
$options['rel'] = 'stylesheet'; |
||||
$options['type'] = 'text/css'; |
||||
$options['href'] = static::url($url); |
||||
return static::tag('link', '', $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a script tag that refers to an external JavaScript file. |
||||
* @param string $url the URL of the external JavaScript file. This parameter will be processed by [[url()]]. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated script tag |
||||
* @see url |
||||
*/ |
||||
public static function jsFile($url, $options = array()) |
||||
{ |
||||
$options['type'] = 'text/javascript'; |
||||
$options['src'] = static::url($url); |
||||
return static::tag('script', '', $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a form start tag. |
||||
* @param array|string $action the form action URL. This parameter will be processed by [[url()]]. |
||||
* @param string $method the form submission method, either "post" or "get" (case-insensitive) |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated form start tag. |
||||
* @see endForm |
||||
*/ |
||||
public static function beginForm($action = '', $method = 'post', $options = array()) |
||||
{ |
||||
$action = static::url($action); |
||||
|
||||
// query parameters in the action are ignored for GET method |
||||
// we use hidden fields to add them back |
||||
$hiddens = array(); |
||||
if (!strcasecmp($method, 'get') && ($pos = strpos($action, '?')) !== false) { |
||||
foreach (explode('&', substr($action, $pos + 1)) as $pair) { |
||||
if (($pos1 = strpos($pair, '=')) !== false) { |
||||
$hiddens[] = static::hiddenInput(urldecode(substr($pair, 0, $pos1)), urldecode(substr($pair, $pos1 + 1))); |
||||
} else { |
||||
$hiddens[] = static::hiddenInput(urldecode($pair), ''); |
||||
} |
||||
} |
||||
$action = substr($action, 0, $pos); |
||||
} |
||||
|
||||
$options['action'] = $action; |
||||
$options['method'] = $method; |
||||
$form = static::beginTag('form', $options); |
||||
if ($hiddens !== array()) { |
||||
$form .= "\n" . implode("\n", $hiddens); |
||||
} |
||||
|
||||
return $form; |
||||
} |
||||
|
||||
/** |
||||
* Generates a form end tag. |
||||
* @return string the generated tag |
||||
* @see beginForm |
||||
*/ |
||||
public static function endForm() |
||||
{ |
||||
return '</form>'; |
||||
} |
||||
|
||||
/** |
||||
* Generates a hyperlink tag. |
||||
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code |
||||
* such as an image tag. If this is is coming from end users, you should consider [[encode()]] |
||||
* it to prevent XSS attacks. |
||||
* @param array|string|null $url the URL for the hyperlink tag. This parameter will be processed by [[url()]] |
||||
* and will be used for the "href" attribute of the tag. If this parameter is null, the "href" attribute |
||||
* will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated hyperlink |
||||
* @see url |
||||
*/ |
||||
public static function a($text, $url = null, $options = array()) |
||||
{ |
||||
if ($url !== null) { |
||||
$options['href'] = static::url($url); |
||||
} |
||||
return static::tag('a', $text, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a mailto hyperlink. |
||||
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code |
||||
* such as an image tag. If this is is coming from end users, you should consider [[encode()]] |
||||
* it to prevent XSS attacks. |
||||
* @param string $email email address. If this is null, the first parameter (link body) will be treated |
||||
* as the email address and used. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated mailto link |
||||
*/ |
||||
public static function mailto($text, $email = null, $options = array()) |
||||
{ |
||||
return static::a($text, 'mailto:' . ($email === null ? $text : $email), $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates an image tag. |
||||
* @param string $src the image URL. This parameter will be processed by [[url()]]. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated image tag |
||||
*/ |
||||
public static function img($src, $options = array()) |
||||
{ |
||||
$options['src'] = static::url($src); |
||||
if (!isset($options['alt'])) { |
||||
$options['alt'] = ''; |
||||
} |
||||
return static::tag('img', null, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a label tag. |
||||
* @param string $content label text. It will NOT be HTML-encoded. Therefore you can pass in HTML code |
||||
* such as an image tag. If this is is coming from end users, you should consider [[encode()]] |
||||
* it to prevent XSS attacks. |
||||
* @param string $for the ID of the HTML element that this label is associated with. |
||||
* If this is null, the "for" attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated label tag |
||||
*/ |
||||
public static function label($content, $for = null, $options = array()) |
||||
{ |
||||
$options['for'] = $for; |
||||
return static::tag('label', $content, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a button tag. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. |
||||
* Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, |
||||
* you should consider [[encode()]] it to prevent XSS attacks. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* If the options does not contain "type", a "type" attribute with value "button" will be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function button($name = null, $value = null, $content = 'Button', $options = array()) |
||||
{ |
||||
$options['name'] = $name; |
||||
$options['value'] = $value; |
||||
if (!isset($options['type'])) { |
||||
$options['type'] = 'button'; |
||||
} |
||||
return static::tag('button', $content, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a submit button tag. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. |
||||
* Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, |
||||
* you should consider [[encode()]] it to prevent XSS attacks. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated submit button tag |
||||
*/ |
||||
public static function submitButton($name = null, $value = null, $content = 'Submit', $options = array()) |
||||
{ |
||||
$options['type'] = 'submit'; |
||||
return static::button($name, $value, $content, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a reset button tag. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. |
||||
* Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, |
||||
* you should consider [[encode()]] it to prevent XSS attacks. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated reset button tag |
||||
*/ |
||||
public static function resetButton($name = null, $value = null, $content = 'Reset', $options = array()) |
||||
{ |
||||
$options['type'] = 'reset'; |
||||
return static::button($name, $value, $content, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates an input type of the given type. |
||||
* @param string $type the type attribute. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated input tag |
||||
*/ |
||||
public static function input($type, $name = null, $value = null, $options = array()) |
||||
{ |
||||
$options['type'] = $type; |
||||
$options['name'] = $name; |
||||
$options['value'] = $value; |
||||
return static::tag('input', null, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates an input button. |
||||
* @param string $name the name attribute. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function buttonInput($name, $value = 'Button', $options = array()) |
||||
{ |
||||
return static::input('button', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a submit input button. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function submitInput($name = null, $value = 'Submit', $options = array()) |
||||
{ |
||||
return static::input('submit', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a reset input button. |
||||
* @param string $name the name attribute. If it is null, the name attribute will not be generated. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the attributes of the button tag. The values will be HTML-encoded using [[encode()]]. |
||||
* Attributes whose value is null will be ignored and not put in the tag returned. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function resetInput($name = null, $value = 'Reset', $options = array()) |
||||
{ |
||||
return static::input('reset', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a text input field. |
||||
* @param string $name the name attribute. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function textInput($name, $value = null, $options = array()) |
||||
{ |
||||
return static::input('text', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a hidden input field. |
||||
* @param string $name the name attribute. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function hiddenInput($name, $value = null, $options = array()) |
||||
{ |
||||
return static::input('hidden', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a password input field. |
||||
* @param string $name the name attribute. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function passwordInput($name, $value = null, $options = array()) |
||||
{ |
||||
return static::input('password', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a file input field. |
||||
* To use a file input field, you should set the enclosing form's "enctype" attribute to |
||||
* be "multipart/form-data". After the form is submitted, the uploaded file information |
||||
* can be obtained via $_FILES[$name] (see PHP documentation). |
||||
* @param string $name the name attribute. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be generated. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated button tag |
||||
*/ |
||||
public static function fileInput($name, $value = null, $options = array()) |
||||
{ |
||||
return static::input('file', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a text area input. |
||||
* @param string $name the input name |
||||
* @param string $value the input value. Note that it will be encoded using [[encode()]]. |
||||
* @param array $options the tag options in terms of name-value pairs. These will be rendered as |
||||
* the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. |
||||
* If a value is null, the corresponding attribute will not be rendered. |
||||
* @return string the generated text area tag |
||||
*/ |
||||
public static function textarea($name, $value = '', $options = array()) |
||||
{ |
||||
$options['name'] = $name; |
||||
return static::tag('textarea', static::encode($value), $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a radio button input. |
||||
* @param string $name the name attribute. |
||||
* @param boolean $checked whether the radio button should be checked. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be rendered. |
||||
* @param array $options the tag options in terms of name-value pairs. The following options are supported: |
||||
* |
||||
* - uncheck: string, the value associated with the uncheck state of the radio button. When this attribute |
||||
* is present, a hidden input will be generated so that if the radio button is not checked and is submitted, |
||||
* the value of this attribute will still be submitted to the server via the hidden input. |
||||
* |
||||
* The rest of the options will be rendered as the attributes of the resulting tag. The values will |
||||
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. |
||||
* |
||||
* @return string the generated radio button tag |
||||
*/ |
||||
public static function radio($name, $checked = false, $value = '1', $options = array()) |
||||
{ |
||||
$options['checked'] = $checked; |
||||
$options['value'] = $value; |
||||
if (isset($options['uncheck'])) { |
||||
// add a hidden field so that if the radio button is not selected, it still submits a value |
||||
$hidden = static::hiddenInput($name, $options['uncheck']); |
||||
unset($options['uncheck']); |
||||
} else { |
||||
$hidden = ''; |
||||
} |
||||
return $hidden . static::input('radio', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a checkbox input. |
||||
* @param string $name the name attribute. |
||||
* @param boolean $checked whether the checkbox should be checked. |
||||
* @param string $value the value attribute. If it is null, the value attribute will not be rendered. |
||||
* @param array $options the tag options in terms of name-value pairs. The following options are supported: |
||||
* |
||||
* - uncheck: string, the value associated with the uncheck state of the checkbox. When this attribute |
||||
* is present, a hidden input will be generated so that if the checkbox is not checked and is submitted, |
||||
* the value of this attribute will still be submitted to the server via the hidden input. |
||||
* |
||||
* The rest of the options will be rendered as the attributes of the resulting tag. The values will |
||||
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. |
||||
* |
||||
* @return string the generated checkbox tag |
||||
*/ |
||||
public static function checkbox($name, $checked = false, $value = '1', $options = array()) |
||||
{ |
||||
$options['checked'] = $checked; |
||||
$options['value'] = $value; |
||||
if (isset($options['uncheck'])) { |
||||
// add a hidden field so that if the checkbox is not selected, it still submits a value |
||||
$hidden = static::hiddenInput($name, $options['uncheck']); |
||||
unset($options['uncheck']); |
||||
} else { |
||||
$hidden = ''; |
||||
} |
||||
return $hidden . static::input('checkbox', $name, $value, $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a drop-down list. |
||||
* @param string $name the input name |
||||
* @param string $selection the selected value |
||||
* @param array $items the option data items. The array keys are option values, and the array values |
||||
* are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). |
||||
* For each sub-array, an option group will be generated whose label is the key associated with the sub-array. |
||||
* If you have a list of data models, you may convert them into the format described above using |
||||
* [[\yii\helpers\ArrayHelper::map()]]. |
||||
* |
||||
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in |
||||
* the labels will also be HTML-encoded. |
||||
* @param array $options the tag options in terms of name-value pairs. The following options are supported: |
||||
* |
||||
* - prompt: string, a prompt text to be displayed as the first option; |
||||
* - options: array, the attributes for the select option tags. The array keys must be valid option values, |
||||
* and the array values are the extra attributes for the corresponding option tags. For example, |
||||
* |
||||
* ~~~ |
||||
* array( |
||||
* 'value1' => array('disabled' => true), |
||||
* 'value2' => array('label' => 'value 2'), |
||||
* ); |
||||
* ~~~ |
||||
* |
||||
* - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', |
||||
* except that the array keys represent the optgroup labels specified in $items. |
||||
* |
||||
* The rest of the options will be rendered as the attributes of the resulting tag. The values will |
||||
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. |
||||
* |
||||
* @return string the generated drop-down list tag |
||||
*/ |
||||
public static function dropDownList($name, $selection = null, $items = array(), $options = array()) |
||||
{ |
||||
$options['name'] = $name; |
||||
$selectOptions = static::renderSelectOptions($selection, $items, $options); |
||||
return static::tag('select', "\n" . $selectOptions . "\n", $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a list box. |
||||
* @param string $name the input name |
||||
* @param string|array $selection the selected value(s) |
||||
* @param array $items the option data items. The array keys are option values, and the array values |
||||
* are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). |
||||
* For each sub-array, an option group will be generated whose label is the key associated with the sub-array. |
||||
* If you have a list of data models, you may convert them into the format described above using |
||||
* [[\yii\helpers\ArrayHelper::map()]]. |
||||
* |
||||
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in |
||||
* the labels will also be HTML-encoded. |
||||
* @param array $options the tag options in terms of name-value pairs. The following options are supported: |
||||
* |
||||
* - prompt: string, a prompt text to be displayed as the first option; |
||||
* - options: array, the attributes for the select option tags. The array keys must be valid option values, |
||||
* and the array values are the extra attributes for the corresponding option tags. For example, |
||||
* |
||||
* ~~~ |
||||
* array( |
||||
* 'value1' => array('disabled' => true), |
||||
* 'value2' => array('label' => 'value 2'), |
||||
* ); |
||||
* ~~~ |
||||
* |
||||
* - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', |
||||
* except that the array keys represent the optgroup labels specified in $items. |
||||
* - unselect: string, the value that will be submitted when no option is selected. |
||||
* When this attribute is set, a hidden field will be generated so that if no option is selected in multiple |
||||
* mode, we can still obtain the posted unselect value. |
||||
* |
||||
* The rest of the options will be rendered as the attributes of the resulting tag. The values will |
||||
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. |
||||
* |
||||
* @return string the generated list box tag |
||||
*/ |
||||
public static function listBox($name, $selection = null, $items = array(), $options = array()) |
||||
{ |
||||
if (!isset($options['size'])) { |
||||
$options['size'] = 4; |
||||
} |
||||
if (isset($options['multiple']) && $options['multiple'] && substr($name, -2) !== '[]') { |
||||
$name .= '[]'; |
||||
} |
||||
$options['name'] = $name; |
||||
if (isset($options['unselect'])) { |
||||
// add a hidden field so that if the list box has no option being selected, it still submits a value |
||||
if (substr($name, -2) === '[]') { |
||||
$name = substr($name, 0, -2); |
||||
} |
||||
$hidden = static::hiddenInput($name, $options['unselect']); |
||||
unset($options['unselect']); |
||||
} else { |
||||
$hidden = ''; |
||||
} |
||||
$selectOptions = static::renderSelectOptions($selection, $items, $options); |
||||
return $hidden . static::tag('select', "\n" . $selectOptions . "\n", $options); |
||||
} |
||||
|
||||
/** |
||||
* Generates a list of checkboxes. |
||||
* A checkbox list allows multiple selection, like [[listBox()]]. |
||||
* As a result, the corresponding submitted value is an array. |
||||
* @param string $name the name attribute of each checkbox. |
||||
* @param string|array $selection the selected value(s). |
||||
* @param array $items the data item used to generate the checkboxes. |
||||
* The array keys are the labels, while the array values are the corresponding checkbox values. |
||||
* Note that the labels will NOT be HTML-encoded, while the values will. |
||||
* @param array $options options (name => config) for the checkbox list. The following options are supported: |
||||
* |
||||
* - unselect: string, the value that should be submitted when none of the checkboxes is selected. |
||||
* By setting this option, a hidden input will be generated. |
||||
* - separator: string, the HTML code that separates items. |
||||
* - item: callable, a callback that can be used to customize the generation of the HTML code |
||||
* corresponding to a single item in $items. The signature of this callback must be: |
||||
* |
||||
* ~~~ |
||||
* function ($index, $label, $name, $checked, $value) |
||||
* ~~~ |
||||
* |
||||
* where $index is the zero-based index of the checkbox in the whole list; $label |
||||
* is the label for the checkbox; and $name, $value and $checked represent the name, |
||||
* value and the checked status of the checkbox input. |
||||
* @return string the generated checkbox list |
||||
*/ |
||||
public static function checkboxList($name, $selection = null, $items = array(), $options = array()) |
||||
{ |
||||
if (substr($name, -2) !== '[]') { |
||||
$name .= '[]'; |
||||
} |
||||
|
||||
$formatter = isset($options['item']) ? $options['item'] : null; |
||||
$lines = array(); |
||||
$index = 0; |
||||
foreach ($items as $value => $label) { |
||||
$checked = $selection !== null && |
||||
(!is_array($selection) && !strcmp($value, $selection) |
||||
|| is_array($selection) && in_array($value, $selection)); |
||||
if ($formatter !== null) { |
||||
$lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); |
||||
} else { |
||||
$lines[] = static::label(static::checkbox($name, $checked, $value) . ' ' . $label); |
||||
} |
||||
$index++; |
||||
} |
||||
|
||||
if (isset($options['unselect'])) { |
||||
// add a hidden field so that if the list box has no option being selected, it still submits a value |
||||
$name2 = substr($name, -2) === '[]' ? substr($name, 0, -2) : $name; |
||||
$hidden = static::hiddenInput($name2, $options['unselect']); |
||||
} else { |
||||
$hidden = ''; |
||||
} |
||||
$separator = isset($options['separator']) ? $options['separator'] : "\n"; |
||||
|
||||
return $hidden . implode($separator, $lines); |
||||
} |
||||
|
||||
/** |
||||
* Generates a list of radio buttons. |
||||
* A radio button list is like a checkbox list, except that it only allows single selection. |
||||
* @param string $name the name attribute of each radio button. |
||||
* @param string|array $selection the selected value(s). |
||||
* @param array $items the data item used to generate the radio buttons. |
||||
* The array keys are the labels, while the array values are the corresponding radio button values. |
||||
* Note that the labels will NOT be HTML-encoded, while the values will. |
||||
* @param array $options options (name => config) for the radio button list. The following options are supported: |
||||
* |
||||
* - unselect: string, the value that should be submitted when none of the radio buttons is selected. |
||||
* By setting this option, a hidden input will be generated. |
||||
* - separator: string, the HTML code that separates items. |
||||
* - item: callable, a callback that can be used to customize the generation of the HTML code |
||||
* corresponding to a single item in $items. The signature of this callback must be: |
||||
* |
||||
* ~~~ |
||||
* function ($index, $label, $name, $checked, $value) |
||||
* ~~~ |
||||
* |
||||
* where $index is the zero-based index of the radio button in the whole list; $label |
||||
* is the label for the radio button; and $name, $value and $checked represent the name, |
||||
* value and the checked status of the radio button input. |
||||
* @return string the generated radio button list |
||||
*/ |
||||
public static function radioList($name, $selection = null, $items = array(), $options = array()) |
||||
{ |
||||
$formatter = isset($options['item']) ? $options['item'] : null; |
||||
$lines = array(); |
||||
$index = 0; |
||||
foreach ($items as $value => $label) { |
||||
$checked = $selection !== null && |
||||
(!is_array($selection) && !strcmp($value, $selection) |
||||
|| is_array($selection) && in_array($value, $selection)); |
||||
if ($formatter !== null) { |
||||
$lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); |
||||
} else { |
||||
$lines[] = static::label(static::radio($name, $checked, $value) . ' ' . $label); |
||||
} |
||||
$index++; |
||||
} |
||||
|
||||
$separator = isset($options['separator']) ? $options['separator'] : "\n"; |
||||
if (isset($options['unselect'])) { |
||||
// add a hidden field so that if the list box has no option being selected, it still submits a value |
||||
$hidden = static::hiddenInput($name, $options['unselect']); |
||||
} else { |
||||
$hidden = ''; |
||||
} |
||||
|
||||
return $hidden . implode($separator, $lines); |
||||
} |
||||
|
||||
/** |
||||
* Renders the option tags that can be used by [[dropDownList()]] and [[listBox()]]. |
||||
* @param string|array $selection the selected value(s). This can be either a string for single selection |
||||
* or an array for multiple selections. |
||||
* @param array $items the option data items. The array keys are option values, and the array values |
||||
* are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). |
||||
* For each sub-array, an option group will be generated whose label is the key associated with the sub-array. |
||||
* If you have a list of data models, you may convert them into the format described above using |
||||
* [[\yii\helpers\ArrayHelper::map()]]. |
||||
* |
||||
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in |
||||
* the labels will also be HTML-encoded. |
||||
* @param array $tagOptions the $options parameter that is passed to the [[dropDownList()]] or [[listBox()]] call. |
||||
* This method will take out these elements, if any: "prompt", "options" and "groups". See more details |
||||
* in [[dropDownList()]] for the explanation of these elements. |
||||
* |
||||
* @return string the generated list options |
||||
*/ |
||||
public static function renderSelectOptions($selection, $items, &$tagOptions = array()) |
||||
{ |
||||
$lines = array(); |
||||
if (isset($tagOptions['prompt'])) { |
||||
$prompt = str_replace(' ', ' ', static::encode($tagOptions['prompt'])); |
||||
$lines[] = static::tag('option', $prompt, array('value' => '')); |
||||
} |
||||
|
||||
$options = isset($tagOptions['options']) ? $tagOptions['options'] : array(); |
||||
$groups = isset($tagOptions['groups']) ? $tagOptions['groups'] : array(); |
||||
unset($tagOptions['prompt'], $tagOptions['options'], $tagOptions['groups']); |
||||
|
||||
foreach ($items as $key => $value) { |
||||
if (is_array($value)) { |
||||
$groupAttrs = isset($groups[$key]) ? $groups[$key] : array(); |
||||
$groupAttrs['label'] = $key; |
||||
$attrs = array('options' => $options, 'groups' => $groups); |
||||
$content = static::renderSelectOptions($selection, $value, $attrs); |
||||
$lines[] = static::tag('optgroup', "\n" . $content . "\n", $groupAttrs); |
||||
} else { |
||||
$attrs = isset($options[$key]) ? $options[$key] : array(); |
||||
$attrs['value'] = $key; |
||||
$attrs['selected'] = $selection !== null && |
||||
(!is_array($selection) && !strcmp($key, $selection) |
||||
|| is_array($selection) && in_array($key, $selection)); |
||||
$lines[] = static::tag('option', str_replace(' ', ' ', static::encode($value)), $attrs); |
||||
} |
||||
} |
||||
|
||||
return implode("\n", $lines); |
||||
} |
||||
|
||||
/** |
||||
* Renders the HTML tag attributes. |
||||
* Boolean attributes such as s 'checked', 'disabled', 'readonly', will be handled specially |
||||
* according to [[booleanAttributes]] and [[showBooleanAttributeValues]]. |
||||
* @param array $attributes attributes to be rendered. The attribute values will be HTML-encoded using [[encode()]]. |
||||
* Attributes whose value is null will be ignored and not put in the rendering result. |
||||
* @return string the rendering result. If the attributes are not empty, they will be rendered |
||||
* into a string with a leading white space (such that it can be directly appended to the tag name |
||||
* in a tag. If there is no attribute, an empty string will be returned. |
||||
*/ |
||||
public static function renderTagAttributes($attributes) |
||||
{ |
||||
if (count($attributes) > 1) { |
||||
$sorted = array(); |
||||
foreach (static::$attributeOrder as $name) { |
||||
if (isset($attributes[$name])) { |
||||
$sorted[$name] = $attributes[$name]; |
||||
} |
||||
} |
||||
$attributes = array_merge($sorted, $attributes); |
||||
} |
||||
|
||||
$html = ''; |
||||
foreach ($attributes as $name => $value) { |
||||
if (isset(static::$booleanAttributes[strtolower($name)])) { |
||||
if ($value || strcasecmp($name, $value) === 0) { |
||||
$html .= static::$showBooleanAttributeValues ? " $name=\"$name\"" : " $name"; |
||||
} |
||||
} elseif ($value !== null) { |
||||
$html .= " $name=\"" . static::encode($value) . '"'; |
||||
} |
||||
} |
||||
return $html; |
||||
} |
||||
|
||||
/** |
||||
* Normalizes the input parameter to be a valid URL. |
||||
* |
||||
* If the input parameter |
||||
* |
||||
* - is an empty string: the currently requested URL will be returned; |
||||
* - is a non-empty string: it will be processed by [[Yii::getAlias()]] and returned; |
||||
* - is an array: the first array element is considered a route, while the rest of the name-value |
||||
* pairs are treated as the parameters to be used for URL creation using [[\yii\web\Controller::createUrl()]]. |
||||
* For example: `array('post/index', 'page' => 2)`, `array('index')`. |
||||
* |
||||
* @param array|string $url the parameter to be used to generate a valid URL |
||||
* @return string the normalized URL |
||||
* @throws InvalidParamException if the parameter is invalid. |
||||
*/ |
||||
public static function url($url) |
||||
{ |
||||
if (is_array($url)) { |
||||
if (isset($url[0])) { |
||||
$route = $url[0]; |
||||
$params = array_splice($url, 1); |
||||
if (Yii::$app->controller !== null) { |
||||
return Yii::$app->controller->createUrl($route, $params); |
||||
} else { |
||||
return Yii::$app->getUrlManager()->createUrl($route, $params); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('The array specifying a URL must contain at least one element.'); |
||||
} |
||||
} elseif ($url === '') { |
||||
return Yii::$app->getRequest()->getUrl(); |
||||
} else { |
||||
return Yii::getAlias($url); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,272 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers; |
||||
|
||||
use Yii; |
||||
use yii\base\Exception; |
||||
use yii\base\InvalidConfigException; |
||||
use yii\base\InvalidParamException; |
||||
|
||||
/** |
||||
* SecurityHelper provides a set of methods to handle common security-related tasks. |
||||
* |
||||
* In particular, SecurityHelper supports the following features: |
||||
* |
||||
* - Encryption/decryption: [[encrypt()]] and [[decrypt()]] |
||||
* - Data tampering prevention: [[hashData()]] and [[validateData()]] |
||||
* - Password validation: [[generatePasswordHash()]] and [[validatePassword()]] |
||||
* |
||||
* Additionally, SecurityHelper provides [[getSecretKey()]] to support generating |
||||
* named secret keys. These secret keys, once generated, will be stored in a file |
||||
* and made available in future requests. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @author Tom Worster <fsb@thefsb.org> |
||||
* @since 2.0 |
||||
*/ |
||||
class SecurityHelper |
||||
{ |
||||
/** |
||||
* Encrypts data. |
||||
* @param string $data data to be encrypted. |
||||
* @param string $key the encryption secret key |
||||
* @return string the encrypted data |
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized |
||||
* @see decrypt() |
||||
*/ |
||||
public static function encrypt($data, $key) |
||||
{ |
||||
$module = static::openCryptModule(); |
||||
$key = StringHelper::substr($key, 0, mcrypt_enc_get_key_size($module)); |
||||
srand(); |
||||
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); |
||||
mcrypt_generic_init($module, $key, $iv); |
||||
$encrypted = $iv . mcrypt_generic($module, $data); |
||||
mcrypt_generic_deinit($module); |
||||
mcrypt_module_close($module); |
||||
return $encrypted; |
||||
} |
||||
|
||||
/** |
||||
* Decrypts data |
||||
* @param string $data data to be decrypted. |
||||
* @param string $key the decryption secret key |
||||
* @return string the decrypted data |
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized |
||||
* @see encrypt() |
||||
*/ |
||||
public static function decrypt($data, $key) |
||||
{ |
||||
$module = static::openCryptModule(); |
||||
$key = StringHelper::substr($key, 0, mcrypt_enc_get_key_size($module)); |
||||
$ivSize = mcrypt_enc_get_iv_size($module); |
||||
$iv = StringHelper::substr($data, 0, $ivSize); |
||||
mcrypt_generic_init($module, $key, $iv); |
||||
$decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data))); |
||||
mcrypt_generic_deinit($module); |
||||
mcrypt_module_close($module); |
||||
return rtrim($decrypted, "\0"); |
||||
} |
||||
|
||||
/** |
||||
* Prefixes data with a keyed hash value so that it can later be detected if it is tampered. |
||||
* @param string $data the data to be protected |
||||
* @param string $key the secret key to be used for generating hash |
||||
* @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()" |
||||
* function to see the supported hashing algorithms on your system. |
||||
* @return string the data prefixed with the keyed hash |
||||
* @see validateData() |
||||
* @see getSecretKey() |
||||
*/ |
||||
public static function hashData($data, $key, $algorithm = 'sha256') |
||||
{ |
||||
return hash_hmac($algorithm, $data, $key) . $data; |
||||
} |
||||
|
||||
/** |
||||
* Validates if the given data is tampered. |
||||
* @param string $data the data to be validated. The data must be previously |
||||
* generated by [[hashData()]]. |
||||
* @param string $key the secret key that was previously used to generate the hash for the data in [[hashData()]]. |
||||
* @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()" |
||||
* function to see the supported hashing algorithms on your system. This must be the same |
||||
* as the value passed to [[hashData()]] when generating the hash for the data. |
||||
* @return string the real data with the hash stripped off. False if the data is tampered. |
||||
* @see hashData() |
||||
*/ |
||||
public static function validateData($data, $key, $algorithm = 'sha256') |
||||
{ |
||||
$hashSize = StringHelper::strlen(hash_hmac($algorithm, 'test', $key)); |
||||
$n = StringHelper::strlen($data); |
||||
if ($n >= $hashSize) { |
||||
$hash = StringHelper::substr($data, 0, $hashSize); |
||||
$data2 = StringHelper::substr($data, $hashSize, $n - $hashSize); |
||||
return $hash === hash_hmac($algorithm, $data2, $key) ? $data2 : false; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a secret key associated with the specified name. |
||||
* If the secret key does not exist, a random key will be generated |
||||
* and saved in the file "keys.php" under the application's runtime directory |
||||
* so that the same secret key can be returned in future requests. |
||||
* @param string $name the name that is associated with the secret key |
||||
* @param integer $length the length of the key that should be generated if not exists |
||||
* @return string the secret key associated with the specified name |
||||
*/ |
||||
public static function getSecretKey($name, $length = 32) |
||||
{ |
||||
static $keys; |
||||
$keyFile = Yii::$app->getRuntimePath() . '/keys.php'; |
||||
if ($keys === null) { |
||||
$keys = is_file($keyFile) ? require($keyFile) : array(); |
||||
} |
||||
if (!isset($keys[$name])) { |
||||
// generate a 32-char random key |
||||
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
||||
$keys[$name] = substr(str_shuffle(str_repeat($chars, 5)), 0, $length); |
||||
file_put_contents($keyFile, "<?php\nreturn " . var_export($keys, true) . ";\n");
|
||||
} |
||||
return $keys[$name]; |
||||
} |
||||
|
||||
/** |
||||
* Opens the mcrypt module. |
||||
* @return resource the mcrypt module handle. |
||||
* @throws InvalidConfigException if mcrypt extension is not installed |
||||
* @throws Exception if mcrypt initialization fails |
||||
*/ |
||||
protected static function openCryptModule() |
||||
{ |
||||
if (!extension_loaded('mcrypt')) { |
||||
throw new InvalidConfigException('The mcrypt PHP extension is not installed.'); |
||||
} |
||||
$module = @mcrypt_module_open('rijndael-256', '', MCRYPT_MODE_CBC, ''); |
||||
if ($module === false) { |
||||
throw new Exception('Failed to initialize the mcrypt module.'); |
||||
} |
||||
return $module; |
||||
} |
||||
|
||||
/** |
||||
* Generates a secure hash from a password and a random salt. |
||||
* |
||||
* The generated hash can be stored in database (e.g. `CHAR(64) CHARACTER SET latin1` on MySQL). |
||||
* Later when a password needs to be validated, the hash can be fetched and passed |
||||
* to [[validatePassword()]]. For example, |
||||
* |
||||
* ~~~ |
||||
* // generates the hash (usually done during user registration or when the password is changed) |
||||
* $hash = SecurityHelper::hashPassword($password); |
||||
* // ...save $hash in database... |
||||
* |
||||
* // during login, validate if the password entered is correct using $hash fetched from database |
||||
* if (PasswordHelper::verifyPassword($password, $hash) { |
||||
* // password is good |
||||
* } else { |
||||
* // password is bad |
||||
* } |
||||
* ~~~ |
||||
* |
||||
* @param string $password The password to be hashed. |
||||
* @param integer $cost Cost parameter used by the Blowfish hash algorithm. |
||||
* The higher the value of cost, |
||||
* the longer it takes to generate the hash and to verify a password against it. Higher cost |
||||
* therefore slows down a brute-force attack. For best protection against brute for attacks, |
||||
* set it to the highest value that is tolerable on production servers. The time taken to |
||||
* compute the hash doubles for every increment by one of $cost. So, for example, if the |
||||
* hash takes 1 second to compute when $cost is 14 then then the compute time varies as |
||||
* 2^($cost - 14) seconds. |
||||
* @throws Exception on bad password parameter or cost parameter |
||||
* @return string The password hash string, ASCII and not longer than 64 characters. |
||||
* @see validatePassword() |
||||
*/ |
||||
public static function generatePasswordHash($password, $cost = 13) |
||||
{ |
||||
$salt = static::generateSalt($cost); |
||||
$hash = crypt($password, $salt); |
||||
|
||||
if (!is_string($hash) || strlen($hash) < 32) { |
||||
throw new Exception('Unknown error occurred while generating hash.'); |
||||
} |
||||
|
||||
return $hash; |
||||
} |
||||
|
||||
/** |
||||
* Verifies a password against a hash. |
||||
* @param string $password The password to verify. |
||||
* @param string $hash The hash to verify the password against. |
||||
* @return boolean whether the password is correct. |
||||
* @throws InvalidParamException on bad password or hash parameters or if crypt() with Blowfish hash is not available. |
||||
* @see generatePasswordHash() |
||||
*/ |
||||
public static function validatePassword($password, $hash) |
||||
{ |
||||
if (!is_string($password) || $password === '') { |
||||
throw new InvalidParamException('Password must be a string and cannot be empty.'); |
||||
} |
||||
|
||||
if (!preg_match('/^\$2[axy]\$(\d\d)\$[\./0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] < 4 || $matches[1] > 30) { |
||||
throw new InvalidParamException('Hash is invalid.'); |
||||
} |
||||
|
||||
$test = crypt($password, $hash); |
||||
$n = strlen($test); |
||||
if (strlen($test) < 32 || $n !== strlen($hash)) { |
||||
return false; |
||||
} |
||||
|
||||
// Use a for-loop to compare two strings to prevent timing attacks. See: |
||||
// http://codereview.stackexchange.com/questions/13512 |
||||
$check = 0; |
||||
for ($i = 0; $i < $n; ++$i) { |
||||
$check |= (ord($test[$i]) ^ ord($hash[$i])); |
||||
} |
||||
|
||||
return $check === 0; |
||||
} |
||||
|
||||
/** |
||||
* Generates a salt that can be used to generate a password hash. |
||||
* |
||||
* The PHP [crypt()](http://php.net/manual/en/function.crypt.php) built-in function |
||||
* requires, for the Blowfish hash algorithm, a salt string in a specific format: |
||||
* "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters |
||||
* from the alphabet "./0-9A-Za-z". |
||||
* |
||||
* @param integer $cost the cost parameter |
||||
* @return string the random salt value. |
||||
* @throws InvalidParamException if the cost parameter is not between 4 and 30 |
||||
*/ |
||||
protected static function generateSalt($cost = 13) |
||||
{ |
||||
$cost = (int)$cost; |
||||
if ($cost < 4 || $cost > 30) { |
||||
throw new InvalidParamException('Cost must be between 4 and 31.'); |
||||
} |
||||
|
||||
// Get 20 * 8bits of pseudo-random entropy from mt_rand(). |
||||
$rand = ''; |
||||
for ($i = 0; $i < 20; ++$i) { |
||||
$rand .= chr(mt_rand(0, 255)); |
||||
} |
||||
|
||||
// Add the microtime for a little more entropy. |
||||
$rand .= microtime(); |
||||
// Mix the bits cryptographically into a 20-byte binary string. |
||||
$rand = sha1($rand, true); |
||||
// Form the prefix that specifies Blowfish algorithm and cost parameter. |
||||
$salt = sprintf("$2y$%02d$", $cost); |
||||
// Append the random salt data in the required base64 format. |
||||
$salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22)); |
||||
return $salt; |
||||
} |
||||
} |
@ -0,0 +1,134 @@
|
||||
<?php |
||||
/** |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008-2011 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\helpers; |
||||
|
||||
/** |
||||
* VarDumper is intended to replace the buggy PHP function var_dump and print_r. |
||||
* It can correctly identify the recursively referenced objects in a complex |
||||
* object structure. It also has a recursive depth control to avoid indefinite |
||||
* recursive display of some peculiar variables. |
||||
* |
||||
* VarDumper can be used as follows, |
||||
* |
||||
* ~~~ |
||||
* VarDumper::dump($var); |
||||
* ~~~ |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class CVarDumper |
||||
{ |
||||
private static $_objects; |
||||
private static $_output; |
||||
private static $_depth; |
||||
|
||||
/** |
||||
* Displays a variable. |
||||
* This method achieves the similar functionality as var_dump and print_r |
||||
* but is more robust when handling complex objects such as Yii controllers. |
||||
* @param mixed $var variable to be dumped |
||||
* @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10. |
||||
* @param boolean $highlight whether the result should be syntax-highlighted |
||||
*/ |
||||
public static function dump($var, $depth = 10, $highlight = false) |
||||
{ |
||||
echo self::dumpAsString($var, $depth, $highlight); |
||||
} |
||||
|
||||
/** |
||||
* Dumps a variable in terms of a string. |
||||
* This method achieves the similar functionality as var_dump and print_r |
||||
* but is more robust when handling complex objects such as Yii controllers. |
||||
* @param mixed $var variable to be dumped |
||||
* @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10. |
||||
* @param boolean $highlight whether the result should be syntax-highlighted |
||||
* @return string the string representation of the variable |
||||
*/ |
||||
public static function dumpAsString($var, $depth = 10, $highlight = false) |
||||
{ |
||||
self::$_output = ''; |
||||
self::$_objects = array(); |
||||
self::$_depth = $depth; |
||||
self::dumpInternal($var, 0); |
||||
if ($highlight) { |
||||
$result = highlight_string("<?php\n" . self::$_output, true);
|
||||
self::$_output = preg_replace('/<\\?php<br \\/>/', '', $result, 1); |
||||
} |
||||
return self::$_output; |
||||
} |
||||
|
||||
/* |
||||
* @param mixed $var variable to be dumped |
||||
* @param integer $level depth level |
||||
*/ |
||||
private static function dumpInternal($var, $level) |
||||
{ |
||||
switch (gettype($var)) { |
||||
case 'boolean': |
||||
self::$_output .= $var ? 'true' : 'false'; |
||||
break; |
||||
case 'integer': |
||||
self::$_output .= "$var"; |
||||
break; |
||||
case 'double': |
||||
self::$_output .= "$var"; |
||||
break; |
||||
case 'string': |
||||
self::$_output .= "'" . addslashes($var) . "'"; |
||||
break; |
||||
case 'resource': |
||||
self::$_output .= '{resource}'; |
||||
break; |
||||
case 'NULL': |
||||
self::$_output .= "null"; |
||||
break; |
||||
case 'unknown type': |
||||
self::$_output .= '{unknown}'; |
||||
break; |
||||
case 'array': |
||||
if (self::$_depth <= $level) { |
||||
self::$_output .= 'array(...)'; |
||||
} elseif (empty($var)) { |
||||
self::$_output .= 'array()'; |
||||
} else { |
||||
$keys = array_keys($var); |
||||
$spaces = str_repeat(' ', $level * 4); |
||||
self::$_output .= "array\n" . $spaces . '('; |
||||
foreach ($keys as $key) { |
||||
self::$_output .= "\n" . $spaces . ' '; |
||||
self::dumpInternal($key, 0); |
||||
self::$_output .= ' => '; |
||||
self::dumpInternal($var[$key], $level + 1); |
||||
} |
||||
self::$_output .= "\n" . $spaces . ')'; |
||||
} |
||||
break; |
||||
case 'object': |
||||
if (($id = array_search($var, self::$_objects, true)) !== false) { |
||||
self::$_output .= get_class($var) . '#' . ($id + 1) . '(...)'; |
||||
} elseif (self::$_depth <= $level) { |
||||
self::$_output .= get_class($var) . '(...)'; |
||||
} else { |
||||
$id = self::$_objects[] = $var; |
||||
$className = get_class($var); |
||||
$members = (array)$var; |
||||
$spaces = str_repeat(' ', $level * 4); |
||||
self::$_output .= "$className#$id\n" . $spaces . '('; |
||||
foreach ($members as $key => $value) { |
||||
$keyDisplay = strtr(trim($key), array("\0" => ':')); |
||||
self::$_output .= "\n" . $spaces . " [$keyDisplay] => "; |
||||
self::dumpInternal($value, $level + 1); |
||||
} |
||||
self::$_output .= "\n" . $spaces . ')'; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,119 @@
|
||||
<?php |
||||
|
||||
namespace yii\i18n; |
||||
|
||||
use Yii; |
||||
use yii\base\Component; |
||||
use yii\base\InvalidConfigException; |
||||
|
||||
class I18N extends Component |
||||
{ |
||||
/** |
||||
* @var array list of [[MessageSource]] configurations or objects. The array keys are message |
||||
* categories, and the array values are the corresponding [[MessageSource]] objects or the configurations |
||||
* for creating the [[MessageSource]] objects. The message categories can contain the wildcard '*' at the end |
||||
* to match multiple categories with the same prefix. For example, 'app\*' matches both 'app\cat1' and 'app\cat2'. |
||||
*/ |
||||
public $translations; |
||||
|
||||
public function init() |
||||
{ |
||||
if (!isset($this->translations['yii'])) { |
||||
$this->translations['yii'] = array( |
||||
'class' => 'yii\i18n\PhpMessageSource', |
||||
'sourceLanguage' => 'en_US', |
||||
'basePath' => '@yii/messages', |
||||
); |
||||
} |
||||
if (!isset($this->translations['app'])) { |
||||
$this->translations['app'] = array( |
||||
'class' => 'yii\i18n\PhpMessageSource', |
||||
'sourceLanguage' => 'en_US', |
||||
'basePath' => '@app/messages', |
||||
); |
||||
} |
||||
} |
||||
|
||||
public function translate($message, $params = array(), $language = null) |
||||
{ |
||||
if ($language === null) { |
||||
$language = Yii::$app->language; |
||||
} |
||||
|
||||
// allow chars for category: word chars, ".", "-", "/","\" |
||||
if (strpos($message, '|') !== false && preg_match('/^([\w\-\\/\.\\\\]+)\|(.*)/', $message, $matches)) { |
||||
$category = $matches[1]; |
||||
$message = $matches[2]; |
||||
} else { |
||||
$category = 'app'; |
||||
} |
||||
|
||||
$message = $this->getMessageSource($category)->translate($category, $message, $language); |
||||
|
||||
if (!is_array($params)) { |
||||
$params = array($params); |
||||
} |
||||
|
||||
if (isset($params[0])) { |
||||
$message = $this->getPluralForm($message, $params[0], $language); |
||||
if (!isset($params['{n}'])) { |
||||
$params['{n}'] = $params[0]; |
||||
} |
||||
unset($params[0]); |
||||
} |
||||
|
||||
return $params === array() ? $message : strtr($message, $params); |
||||
} |
||||
|
||||
public function getMessageSource($category) |
||||
{ |
||||
if (isset($this->translations[$category])) { |
||||
$source = $this->translations[$category]; |
||||
} else { |
||||
// try wildcard matching |
||||
foreach ($this->translations as $pattern => $config) { |
||||
if (substr($pattern, -1) === '*' && strpos($category, rtrim($pattern, '*')) === 0) { |
||||
$source = $config; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (isset($source)) { |
||||
return $source instanceof MessageSource ? $source : Yii::createObject($source); |
||||
} else { |
||||
throw new InvalidConfigException("Unable to locate message source for category '$category'."); |
||||
} |
||||
} |
||||
|
||||
public function getLocale($language) |
||||
{ |
||||
|
||||
} |
||||
|
||||
protected function getPluralForm($message, $number, $language) |
||||
{ |
||||
if (strpos($message, '|') === false) { |
||||
return $message; |
||||
} |
||||
$chunks = explode('|', $message); |
||||
$rules = $this->getLocale($language)->getPluralRules(); |
||||
foreach ($rules as $i => $rule) { |
||||
if (isset($chunks[$i]) && $this->evaluate($rule, $number)) { |
||||
return $chunks[$i]; |
||||
} |
||||
} |
||||
$n = count($rules); |
||||
return isset($chunks[$n]) ? $chunks[$n] : $chunks[0]; |
||||
} |
||||
|
||||
/** |
||||
* Evaluates a PHP expression with the given number value. |
||||
* @param string $expression the PHP expression |
||||
* @param mixed $n the number value |
||||
* @return boolean the expression result |
||||
*/ |
||||
protected function evaluate($expression, $n) |
||||
{ |
||||
return @eval("return $expression;"); |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue