Note: If controller name or action name contains camelCased words, internal route will use dashes i.e. for
+`DateTimeController::actionFastForward` route will be `date-time/fast-forward`.
+
### Defaults
If user isn't specifying any route i.e. using URL like `http://example.com/`, Yii assumes that default route should be
diff --git a/docs/guide/installation.md b/docs/guide/installation.md
index 1873d47..5447635 100644
--- a/docs/guide/installation.md
+++ b/docs/guide/installation.md
@@ -1,7 +1,23 @@
Installation
============
-Installation of Yii mainly involves the following two steps:
+Installing via Composer
+-----------------------
+
+The recommended way of installing Yii is by using Composer package manager.
+
+There are two application templates available:
+
+- [basic](https://github.com/yiisoft/yii2-app-basic) that is just a basic frontend application template.
+- [advanced](https://github.com/yiisoft/yii2-app-advanced) that is a set of frontend, backend, console, common
+ (shared code) and environments support.
+
+Please refer to installation instructions on these pages.
+
+Installing from zip
+-------------------
+
+Installation from zip mainly involves the following two steps:
1. Download Yii Framework from [yiiframework.com](http://www.yiiframework.com/).
2. Unpack the Yii release file to a Web-accessible directory.
@@ -12,7 +28,6 @@ needs to be exposed to Web users. Other PHP scripts, including those from
Yii, should be protected from Web access; otherwise they might be exploited
by hackers.
-
Requirements
------------
diff --git a/docs/guide/overview.md b/docs/guide/overview.md
index 9e54fd4..c7eeb42 100644
--- a/docs/guide/overview.md
+++ b/docs/guide/overview.md
@@ -31,6 +31,10 @@ management systems (CMS), e-commerce systems, etc.
How does Yii Compare with Other Frameworks?
-------------------------------------------
-Like most PHP frameworks, Yii is an MVC (Model-View-Controller) framework.
-
-TBD
\ No newline at end of file
+- Like most PHP frameworks, Yii is an MVC (Model-View-Controller) framework.
+- It is a fullstack framework providing many solutions and components such as logging, session management, caching etc.
+- It has a good balance of simplicity and features.
+- Syntax and overall development usability are taken seriously.
+- Performance is one of the key goals.
+- We are constantly watching other web frameworks out there and getting the best ideas in. Initial Yii release was heavily
+ influenced by Ruby on Rails. Still, we aren't blindly copying anyhting.
\ No newline at end of file
diff --git a/docs/guide/performance.md b/docs/guide/performance.md
index 1fa3529..3f83dae 100644
--- a/docs/guide/performance.md
+++ b/docs/guide/performance.md
@@ -100,6 +100,8 @@ You can use `CacheSession` to store sessions using cache. Note that some
cache storage such as memcached has no guarantee that session data will not
be lost leading to unexpected logouts.
+If you have [Redis](http://redis.io/) on your server, it's highly recommended as session storage.
+
Improving application
---------------------
diff --git a/docs/guide/security.md b/docs/guide/security.md
index e69de29..0a3a14e 100644
--- a/docs/guide/security.md
+++ b/docs/guide/security.md
@@ -0,0 +1,81 @@
+Security
+========
+
+Hashing and verifyig passwords
+------------------------------
+
+It is important not to store passwords in plain text but, contrary to popular belief, just using `md5` or `sha1` to
+compute and verify hashes isn't a good way either. Modern hardware allows to brute force these very fast.
+
+In order to truly secure user passwords even in case your database is leaked you need to use a function that is resistant
+to brute-force such as bcrypt. In PHP it can be achieved by using [crypt function](http://php.net/manual/en/function.crypt.php)
+but since usage isn't trivial and one can easily misuse it, Yii provides two helper functions for generating hash from
+password and verifying existing hash.
+
+When user sets his password we're taking password string from POST and then getting a hash:
+
+```php
+$hash = \yii\helpers\Security::generatePasswordHash($password);
+```
+
+The hash we've got is persisted to database to be used later.
+
+Then when user is trying to log in we're verifying the password he entered against a hash that we've previously persisted:
+
+```php
+if(Security::validatePassword($password, $hash)) {
+ // all good, logging user in
+}
+else {
+ // wrong password
+}
+```
+
+
+Random data
+-----------
+
+Random data is useful in many cases. For example, when resetting a password via email you need to generate a token,
+save it to database and send it via email to end user so he's able to prove that email belongs to him. It is very
+important for this token to be truly unique else there will be a possibility to predict a value and reset another user's
+password.
+
+Yii security helper makes it as simple as:
+
+```php
+$key = \yii\helpers\Security::generateRandomKey();
+```
+
+Encryption and decryption
+-------------------------
+
+In order to encrypt data so only person knowing a secret passphrase or having a secret key will be able to decrypt it.
+For example, we need to store some information in our database but we need to make sure only user knowing a secret code
+can view it (even if database is leaked):
+
+
+```php
+// $data and $secretWord are from the form
+$encryptedData = \yii\helpers\Security::encrypt($data, $secretWord);
+// store $encryptedData to database
+```
+
+Then when user want to read it:
+
+```php
+// $secretWord is from the form, $encryptedData is from database
+$data = \yii\helpers\Security::decrypt($encryptedData, $secretWord);
+```
+
+Making sure data wasn't modified
+--------------------------------
+
+hashData()
+validateData()
+
+
+Securing Cookies
+----------------
+
+- validation
+- httpOnly
\ No newline at end of file
diff --git a/extensions/twig/composer.json b/extensions/twig/composer.json
index 0ff7437..e613807 100644
--- a/extensions/twig/composer.json
+++ b/extensions/twig/composer.json
@@ -20,7 +20,7 @@
"minimum-stability": "dev",
"require": {
"yiisoft/yii2": "*",
- "twig/twig": "v1.13.0"
+ "twig/twig": "v1.13.2"
},
"autoload": {
"psr-0": { "yii\\twig": "" }
diff --git a/framework/yii/assets.php b/framework/yii/assets.php
index dd657f3..c52bca6 100644
--- a/framework/yii/assets.php
+++ b/framework/yii/assets.php
@@ -6,6 +6,6 @@ return array(
yii\validators\PunycodeAsset::className(),
yii\validators\ValidationAsset::className(),
yii\widgets\ActiveFormAsset::className(),
- yii\widgets\CaptchaAsset::className(),
+ yii\captcha\CaptchaAsset::className(),
yii\widgets\MaskedInputAsset::className(),
);
diff --git a/framework/yii/assets/yii.captcha.js b/framework/yii/assets/yii.captcha.js
index 7dfe3cc..af14faa 100644
--- a/framework/yii/assets/yii.captcha.js
+++ b/framework/yii/assets/yii.captcha.js
@@ -1,7 +1,7 @@
/**
* Yii Captcha widget.
*
- * This is the JavaScript widget used by the yii\widgets\Captcha widget.
+ * This is the JavaScript widget used by the yii\captcha\Captcha widget.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php
index 0381e16..687f1a3 100644
--- a/framework/yii/base/Application.php
+++ b/framework/yii/base/Application.php
@@ -180,6 +180,16 @@ abstract class Application extends Module
}
/**
+ * Returns an ID that uniquely identifies this module among all modules within the current application.
+ * Since this is an application instance, it will always return an empty string.
+ * @return string the unique ID of the module.
+ */
+ public function getUniqueId()
+ {
+ return '';
+ }
+
+ /**
* Runs the application.
* This is the main entrance of an application.
* @return integer the exit status (0 means normal, non-zero values mean abnormal)
@@ -475,6 +485,8 @@ abstract class Application extends Module
*/
public function handleFatalError()
{
+ unset($this->_memoryReserve);
+
// load ErrorException manually here because autoloading them will not work
// when error occurs while autoloading a class
if (!class_exists('\\yii\\base\\Exception', false)) {
@@ -487,7 +499,6 @@ abstract class Application extends Module
$error = error_get_last();
if (ErrorException::isFatalError($error)) {
- unset($this->_memoryReserve);
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
// use error_log because it's too late to use Yii log
error_log($exception);
diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php
index 8e75835..5ff8ae4 100644
--- a/framework/yii/base/Component.php
+++ b/framework/yii/base/Component.php
@@ -220,19 +220,19 @@ class Component extends Object
*
* - the class has a getter or setter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
- * - an attached behavior has a property of the given name (when `$checkBehavior` is true).
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
+ * - an attached behavior has a property of the given name (when `$checkBehaviors` is true).
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
- * @param boolean $checkBehavior whether to treat behaviors' properties as properties of this component
+ * @param boolean $checkVars whether to treat member variables as properties
+ * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component
* @return boolean whether the property is defined
* @see canGetProperty
* @see canSetProperty
*/
- public function hasProperty($name, $checkVar = true, $checkBehavior = true)
+ public function hasProperty($name, $checkVars = true, $checkBehaviors = true)
{
- return $this->canGetProperty($name, $checkVar, $checkBehavior) || $this->canSetProperty($name, $checkVar, $checkBehavior);
+ return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors);
}
/**
@@ -241,23 +241,23 @@ class Component extends Object
*
* - the class has a getter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
- * - an attached behavior has a readable property of the given name (when `$checkBehavior` is true).
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
+ * - an attached behavior has a readable property of the given name (when `$checkBehaviors` is true).
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
- * @param boolean $checkBehavior whether to treat behaviors' properties as properties of this component
+ * @param boolean $checkVars whether to treat member variables as properties
+ * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component
* @return boolean whether the property can be read
* @see canSetProperty
*/
- public function canGetProperty($name, $checkVar = true, $checkBehavior = true)
+ public function canGetProperty($name, $checkVars = true, $checkBehaviors = true)
{
- if (method_exists($this, 'get' . $name) || $checkVar && property_exists($this, $name)) {
+ if (method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name)) {
return true;
- } else {
+ } elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
- if ($behavior->canGetProperty($name, $checkVar)) {
+ if ($behavior->canGetProperty($name, $checkVars)) {
return true;
}
}
@@ -271,23 +271,23 @@ class Component extends Object
*
* - the class has a setter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
- * - an attached behavior has a writable property of the given name (when `$checkBehavior` is true).
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
+ * - an attached behavior has a writable property of the given name (when `$checkBehaviors` is true).
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
- * @param boolean $checkBehavior whether to treat behaviors' properties as properties of this component
+ * @param boolean $checkVars whether to treat member variables as properties
+ * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component
* @return boolean whether the property can be written
* @see canGetProperty
*/
- public function canSetProperty($name, $checkVar = true, $checkBehavior = true)
+ public function canSetProperty($name, $checkVars = true, $checkBehaviors = true)
{
- if (method_exists($this, 'set' . $name) || $checkVar && property_exists($this, $name)) {
+ if (method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name)) {
return true;
- } else {
+ } elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
- if ($behavior->canSetProperty($name, $checkVar)) {
+ if ($behavior->canSetProperty($name, $checkVars)) {
return true;
}
}
diff --git a/framework/yii/base/ErrorHandler.php b/framework/yii/base/ErrorHandler.php
index 39c87b0..99428fc 100644
--- a/framework/yii/base/ErrorHandler.php
+++ b/framework/yii/base/ErrorHandler.php
@@ -192,11 +192,16 @@ class ErrorHandler extends Component
*/
public function renderFile($_file_, $_params_)
{
- ob_start();
- ob_implicit_flush(false);
- extract($_params_, EXTR_OVERWRITE);
- require(Yii::getAlias($_file_));
- return ob_get_clean();
+ $_params_['handler'] = $this;
+ if ($this->exception instanceof ErrorException) {
+ ob_start();
+ ob_implicit_flush(false);
+ extract($_params_, EXTR_OVERWRITE);
+ require(Yii::getAlias($_file_));
+ return ob_get_clean();
+ } else {
+ return Yii::$app->getView()->renderFile($_file_, $_params_, $this);
+ }
}
/**
diff --git a/framework/yii/base/Formatter.php b/framework/yii/base/Formatter.php
index 5326ed8..d9b5778 100644
--- a/framework/yii/base/Formatter.php
+++ b/framework/yii/base/Formatter.php
@@ -71,22 +71,36 @@ class Formatter extends Component
}
/**
- * Formats the value based on the given type.
+ * Formats the value based on the given format type.
* This method will call one of the "as" methods available in this class to do the formatting.
- * For type "xyz", the method "asXyz" will be used. For example, if the type is "html",
- * then [[asHtml()]] will be used. Type names are case insensitive.
+ * For type "xyz", the method "asXyz" will be used. For example, if the format is "html",
+ * then [[asHtml()]] will be used. Format names are case insensitive.
* @param mixed $value the value to be formatted
- * @param string $type the type of the value, e.g., "html", "text".
+ * @param string|array $format the format of the value, e.g., "html", "text". To specify additional
+ * parameters of the formatting method, you may use an array. The first element of the array
+ * specifies the format name, while the rest of the elements will be used as the parameters to the formatting
+ * method. For example, a format of `array('date', 'Y-m-d')` will cause the invocation of `asDate($value, 'Y-m-d')`.
* @return string the formatting result
* @throws InvalidParamException if the type is not supported by this class.
*/
- public function format($value, $type)
+ public function format($value, $format)
{
- $method = 'as' . $type;
+ if (is_array($format)) {
+ if (!isset($format[0])) {
+ throw new InvalidParamException('The $format array must contain at least one element.');
+ }
+ $f = $format[0];
+ $format[0] = $value;
+ $params = $format;
+ $format = $f;
+ } else {
+ $params = array($value);
+ }
+ $method = 'as' . $format;
if (method_exists($this, $method)) {
- return $this->$method($value);
+ return call_user_func_array(array($this, $method), $params);
} else {
- throw new InvalidParamException("Unknown type: $type");
+ throw new InvalidParamException("Unknown type: $format");
}
}
diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php
index d2c8aa5..bb0f4b1 100644
--- a/framework/yii/base/Model.php
+++ b/framework/yii/base/Model.php
@@ -117,8 +117,8 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
* array('password', 'compare', 'compareAttribute' => 'password2', 'on' => 'register'),
* // an inline validator defined via the "authenticate()" method in the model class
* array('password', 'authenticate', 'on' => 'login'),
- * // a validator of class "CaptchaValidator"
- * array('captcha', 'CaptchaValidator'),
+ * // a validator of class "DateRangeValidator"
+ * array('dateRange', 'DateRangeValidator'),
* );
* ~~~
*
diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php
index 2bc42e3..a85385b 100644
--- a/framework/yii/base/Module.php
+++ b/framework/yii/base/Module.php
@@ -192,13 +192,7 @@ abstract class Module extends Component
*/
public function getUniqueId()
{
- if ($this instanceof Application) {
- return '';
- } elseif ($this->module) {
- return ltrim($this->module->getUniqueId() . '/' . $this->id, '/');
- } else {
- return $this->id;
- }
+ return $this->module ? ltrim($this->module->getUniqueId() . '/' . $this->id, '/') : $this->id;
}
/**
diff --git a/framework/yii/base/Object.php b/framework/yii/base/Object.php
index 7724008..50ad9e9 100644
--- a/framework/yii/base/Object.php
+++ b/framework/yii/base/Object.php
@@ -170,17 +170,17 @@ class Object implements Arrayable
*
* - the class has a getter or setter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
+ * @param boolean $checkVars whether to treat member variables as properties
* @return boolean whether the property is defined
* @see canGetProperty
* @see canSetProperty
*/
- public function hasProperty($name, $checkVar = true)
+ public function hasProperty($name, $checkVars = true)
{
- return $this->canGetProperty($name, $checkVar) || $this->canSetProperty($name, false);
+ return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
}
/**
@@ -189,16 +189,16 @@ class Object implements Arrayable
*
* - the class has a getter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
+ * @param boolean $checkVars whether to treat member variables as properties
* @return boolean whether the property can be read
* @see canSetProperty
*/
- public function canGetProperty($name, $checkVar = true)
+ public function canGetProperty($name, $checkVars = true)
{
- return method_exists($this, 'get' . $name) || $checkVar && property_exists($this, $name);
+ return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
}
/**
@@ -207,16 +207,16 @@ class Object implements Arrayable
*
* - the class has a setter method associated with the specified name
* (in this case, property name is case-insensitive);
- * - the class has a member variable with the specified name (when `$checkVar` is true);
+ * - the class has a member variable with the specified name (when `$checkVars` is true);
*
* @param string $name the property name
- * @param boolean $checkVar whether to treat member variables as properties
+ * @param boolean $checkVars whether to treat member variables as properties
* @return boolean whether the property can be written
* @see canGetProperty
*/
- public function canSetProperty($name, $checkVar = true)
+ public function canSetProperty($name, $checkVars = true)
{
- return method_exists($this, 'set' . $name) || $checkVar && property_exists($this, $name);
+ return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
}
/**
diff --git a/framework/yii/bootstrap/Carousel.php b/framework/yii/bootstrap/Carousel.php
index c2c68a7..ec9a0c9 100644
--- a/framework/yii/bootstrap/Carousel.php
+++ b/framework/yii/bootstrap/Carousel.php
@@ -55,7 +55,7 @@ class Carousel extends Widget
* // required, slide content (HTML), such as an image tag
* 'content' => '
',
* // optional, the caption (HTML) of the slide
- * 'caption'=> '
This is title
This is the caption text
',
+ * 'caption' => '
This is title
This is the caption text
',
* // optional the HTML attributes of the slide container
* 'options' => array(),
* )
diff --git a/framework/yii/bootstrap/Collapse.php b/framework/yii/bootstrap/Collapse.php
index 8aed0b1..77fdde7 100644
--- a/framework/yii/bootstrap/Collapse.php
+++ b/framework/yii/bootstrap/Collapse.php
@@ -23,7 +23,7 @@ use yii\helpers\Html;
* 'Collapsible Group Item #1' => array(
* 'content' => 'Anim pariatur cliche...',
* // open its content by default
- * 'contentOptions' => array('class'=>'in')
+ * 'contentOptions' => array('class' => 'in')
* ),
* // another group item
* 'Collapsible Group Item #2' => array(
@@ -51,9 +51,9 @@ class Collapse extends Widget
* // required, the content (HTML) of the group
* 'content' => 'Anim pariatur cliche...',
* // optional the HTML attributes of the content group
- * 'contentOptions'=> array(),
+ * 'contentOptions' => array(),
* // optional the HTML attributes of the group
- * 'options'=> array(),
+ * 'options' => array(),
* )
* ```
*/
diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php
index cea83d8..5b5d40b 100644
--- a/framework/yii/bootstrap/Nav.php
+++ b/framework/yii/bootstrap/Nav.php
@@ -136,6 +136,7 @@ class Nav extends Widget
if (is_array($items)) {
$items = Dropdown::widget(array(
'items' => $items,
+ 'encodeLabels' => $this->encodeLabels,
'clientOptions' => false,
));
}
diff --git a/framework/yii/bootstrap/NavBar.php b/framework/yii/bootstrap/NavBar.php
index f801df5..52804c4 100644
--- a/framework/yii/bootstrap/NavBar.php
+++ b/framework/yii/bootstrap/NavBar.php
@@ -87,7 +87,7 @@ class NavBar extends Widget
* // optional, the menu item class type of the widget to render. Defaults to "Nav" widget.
* 'class' => 'Menu item class type',
* // required, the configuration options of the widget.
- * 'options'=> array(...),
+ * 'options' => array(...),
* ),
* // optionally, you can pass a string
* '
EOD;
}
diff --git a/framework/yii/debug/panels/RequestPanel.php b/framework/yii/debug/panels/RequestPanel.php
index e709de6..e655f2d 100644
--- a/framework/yii/debug/panels/RequestPanel.php
+++ b/framework/yii/debug/panels/RequestPanel.php
@@ -12,6 +12,7 @@ use yii\base\InlineAction;
use yii\bootstrap\Tabs;
use yii\debug\Panel;
use yii\helpers\Html;
+use yii\web\Response;
/**
* Debugger panel that collects and displays request data.
@@ -29,9 +30,24 @@ class RequestPanel extends Panel
public function getSummary()
{
$url = $this->getUrl();
+ $statusCode = $this->data['statusCode'];
+ if ($statusCode === null) {
+ $statusCode = 200;
+ }
+ if ($statusCode >= 200 && $statusCode < 300) {
+ $class = 'label-success';
+ } elseif ($statusCode >= 100 && $statusCode < 200) {
+ $class = 'label-info';
+ } else {
+ $class = 'label-important';
+ }
+ $statusText = Html::encode(isset(Response::$httpStatuses[$statusCode]) ? Response::$httpStatuses[$statusCode] : '');
return <<