Browse Source

Merge remote-tracking branch 'upstream/master' into 364-toAscii

* upstream/master: (91 commits)
  fixed init.bat paths
  renamed backstage → backend
  Fixed test break.
  Response WIP
  coding style fix.
  [1] Redone missing code. [2] Added empty line at the end of file [3] Removed exception.
  Updated code style. braces on the same line for control statements.
  Removed unused columsn from find constraint sql. Fixed typo. Added extra schema check for when a foreign table is not in the same schema. Updated indentation to conform to other classes.
  Multilevel Items
  Fixes issue #514.
  Removed the config setting that should not have been commited.
  Removed false exception catching.
  Removed custom pgsql PDO and added defaultSchema as public property.
  CS fixes.
  Minor refactoring of DbMessageSource.
  Response WIP
  Minor refactoring of t().
  Added Jsonable support.
  Fixes #13. Implement DB message source.
  Yii::t() minor fix.
  ...
tags/2.0.0-beta
Antonio Ramirez 12 years ago
parent
commit
0aab6ded42
  1. 3
      .travis.yml
  2. 27
      apps/advanced/README.md
  3. 0
      apps/advanced/backend/assets/.gitkeep
  4. 0
      apps/advanced/backend/config/.gitignore
  5. 0
      apps/advanced/backend/config/assets.php
  6. 2
      apps/advanced/backend/config/main.php
  7. 0
      apps/advanced/backend/config/params.php
  8. 2
      apps/advanced/backend/controllers/SiteController.php
  9. 0
      apps/advanced/backend/models/.gitkeep
  10. 0
      apps/advanced/backend/runtime/.gitignore
  11. 0
      apps/advanced/backend/views/layouts/main.php
  12. 0
      apps/advanced/backend/views/site/index.php
  13. 0
      apps/advanced/backend/views/site/login.php
  14. 0
      apps/advanced/backend/www/.gitignore
  15. 0
      apps/advanced/backend/www/assets/.gitignore
  16. 0
      apps/advanced/backend/www/css/site.css
  17. 9
      apps/advanced/composer.json
  18. 10
      apps/advanced/composer.lock
  19. 4
      apps/advanced/init.bat
  20. 15
      apps/basic/README.md
  21. 5
      apps/basic/composer.json
  22. 10
      apps/basic/composer.lock
  23. 1
      apps/basic/config/main.php
  24. 1
      apps/basic/controllers/SiteController.php
  25. 2
      extensions/composer/yii/composer/InstallHandler.php
  26. 4
      extensions/smarty/yii/smarty/ViewRenderer.php
  27. 2
      extensions/twig/yii/twig/ViewRenderer.php
  28. 27
      framework/yii/YiiBase.php
  29. 76
      framework/yii/base/Application.php
  30. 13
      framework/yii/base/ErrorHandler.php
  31. 17
      framework/yii/base/Formatter.php
  32. 63
      framework/yii/base/HttpException.php
  33. 1
      framework/yii/base/InvalidCallException.php
  34. 1
      framework/yii/base/InvalidConfigException.php
  35. 1
      framework/yii/base/InvalidParamException.php
  36. 1
      framework/yii/base/InvalidRouteException.php
  37. 22
      framework/yii/base/Jsonable.php
  38. 13
      framework/yii/base/Model.php
  39. 23
      framework/yii/base/Module.php
  40. 1
      framework/yii/base/NotSupportedException.php
  41. 19
      framework/yii/base/Object.php
  42. 13
      framework/yii/base/Response.php
  43. 1
      framework/yii/base/UnknownClassException.php
  44. 1
      framework/yii/base/UnknownMethodException.php
  45. 1
      framework/yii/base/UnknownPropertyException.php
  46. 3
      framework/yii/bootstrap/Button.php
  47. 2
      framework/yii/bootstrap/ButtonDropdown.php
  48. 1
      framework/yii/bootstrap/ButtonGroup.php
  49. 1
      framework/yii/bootstrap/Dropdown.php
  50. 24
      framework/yii/bootstrap/Nav.php
  51. 1
      framework/yii/bootstrap/Progress.php
  52. 1
      framework/yii/bootstrap/Widget.php
  53. 3
      framework/yii/caching/FileCache.php
  54. 1
      framework/yii/caching/XCache.php
  55. 1
      framework/yii/console/Exception.php
  56. 17
      framework/yii/console/Response.php
  57. 67
      framework/yii/console/controllers/AssetController.php
  58. 3
      framework/yii/console/controllers/MessageController.php
  59. 5
      framework/yii/data/Pagination.php
  60. 5
      framework/yii/data/Sort.php
  61. 8
      framework/yii/db/ActiveRecord.php
  62. 3
      framework/yii/db/Connection.php
  63. 10
      framework/yii/db/QueryBuilder.php
  64. 2
      framework/yii/db/mssql/QueryBuilder.php
  65. 2
      framework/yii/db/mysql/QueryBuilder.php
  66. 6
      framework/yii/db/mysql/Schema.php
  67. 41
      framework/yii/db/pgsql/QueryBuilder.php
  68. 288
      framework/yii/db/pgsql/Schema.php
  69. 4
      framework/yii/db/sqlite/QueryBuilder.php
  70. 1
      framework/yii/helpers/Json.php
  71. 1
      framework/yii/helpers/base/Console.php
  72. 1
      framework/yii/helpers/base/Html.php
  73. 2
      framework/yii/helpers/base/Inflector.php
  74. 6
      framework/yii/helpers/base/Json.php
  75. 21
      framework/yii/helpers/base/SecurityHelper.php
  76. 158
      framework/yii/i18n/DbMessageSource.php
  77. 58
      framework/yii/i18n/Formatter.php
  78. 9
      framework/yii/i18n/I18N.php
  79. 1
      framework/yii/i18n/MessageSource.php
  80. 2
      framework/yii/jui/Accordion.php
  81. 1
      framework/yii/jui/Menu.php
  82. 1
      framework/yii/jui/Widget.php
  83. 2
      framework/yii/logging/ProfileTarget.php
  84. 2
      framework/yii/logging/Target.php
  85. 3
      framework/yii/rbac/DbManager.php
  86. 1
      framework/yii/validators/CaptchaValidator.php
  87. 2
      framework/yii/validators/CompareValidator.php
  88. 3
      framework/yii/validators/DateValidator.php
  89. 1
      framework/yii/validators/DefaultValueValidator.php
  90. 1
      framework/yii/validators/ExistValidator.php
  91. 1
      framework/yii/validators/FilterValidator.php
  92. 1
      framework/yii/validators/StringValidator.php
  93. 2
      framework/yii/web/AccessRule.php
  94. 28
      framework/yii/web/CaptchaAction.php
  95. 2
      framework/yii/web/Cookie.php
  96. 111
      framework/yii/web/CookieCollection.php
  97. 201
      framework/yii/web/HeaderCollection.php
  98. 16
      framework/yii/web/HttpCache.php
  99. 94
      framework/yii/web/Request.php
  100. 371
      framework/yii/web/Response.php
  101. Some files were not shown because too many files have changed in this diff Show More

3
.travis.yml

@ -10,5 +10,6 @@ env:
before_script:
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS yiitest;'; fi"
- psql -U postgres -c 'drop database if exists yiitest;';
- psql -U postgres -c 'create database yiitest;';
script: phpunit

27
apps/advanced/README.md

@ -10,7 +10,7 @@ if you have a project to be deployed for production soon.
Thank you for using Yii 2 Advanced Application Template - an application template
that works out-of-box and can be easily customized to fit for your needs.
Yii 2 Advanced Application Template is best suitable for large projects requiring frontend and backstage separation,
Yii 2 Advanced Application Template is best suitable for large projects requiring frontend and backend separation,
deployment in different environments, configuration nesting etc.
@ -20,18 +20,18 @@ DIRECTORY STRUCTURE
```
common
config/ contains shared configurations
models/ contains model classes used in both backstage and frontend
models/ contains model classes used in both backend and frontend
console
config/ contains console configurations
controllers/ contains console controllers (commands)
migrations/ contains database migrations
models/ contains console-specific model classes
runtime/ contains files generated during runtime
backstage
backend
assets/ contains application assets such as JavaScript and CSS
config/ contains backstage configurations
config/ contains backend configurations
controllers/ contains Web controller classes
models/ contains backstage-specific model classes
models/ contains backend-specific model classes
runtime/ contains files generated during runtime
views/ contains view files for the Web application
www/ contains the entry script and Web resources
@ -79,6 +79,21 @@ php composer.phar create-project --stability=dev yiisoft/yii2-app-advanced yii-a
This is not currently available. We will provide it when Yii 2 is formally released.
### Install from development repository
If you've cloned the [Yii 2 framework main development repository](https://github.com/yiisoft/yii2) you
can bootstrap your application with:
~~~
cd yii2/apps/advanced
php composer.phar create-project
~~~
*Note: If the above command fails with `[RuntimeException] Not enough arguments.` run
`php composer.phar self-update` to obtain an updated version of composer which supports creating projects
from local packages.*
GETTING STARTED
---------------
@ -92,7 +107,7 @@ the installed application. You only need to do these once for all.
Now you should be able to access:
- the frontend using the URL `http://localhost/yii-advanced/frontend/www/`
- the backstage using the URL `http://localhost/yii-advanced/backstage/www/`
- the backend using the URL `http://localhost/yii-advanced/backend/www/`
assuming `yii-advanced` is directly under the document root of your Web server.

0
apps/advanced/backstage/assets/.gitkeep → apps/advanced/backend/assets/.gitkeep

0
apps/advanced/backstage/config/.gitignore → apps/advanced/backend/config/.gitignore vendored

0
apps/advanced/backstage/config/assets.php → apps/advanced/backend/config/assets.php

2
apps/advanced/backstage/config/main.php → apps/advanced/backend/config/main.php

@ -13,7 +13,7 @@ return array(
'basePath' => dirname(__DIR__),
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'preload' => array('log'),
'controllerNamespace' => 'backstage\controllers',
'controllerNamespace' => 'backend\controllers',
'modules' => array(
),
'components' => array(

0
apps/advanced/backstage/config/params.php → apps/advanced/backend/config/params.php

2
apps/advanced/backstage/controllers/SiteController.php → apps/advanced/backend/controllers/SiteController.php

@ -1,6 +1,6 @@
<?php
namespace backstage\controllers;
namespace backend\controllers;
use Yii;
use yii\web\Controller;

0
apps/advanced/backstage/models/.gitkeep → apps/advanced/backend/models/.gitkeep

0
apps/advanced/backstage/runtime/.gitignore → apps/advanced/backend/runtime/.gitignore vendored

0
apps/advanced/backstage/views/layouts/main.php → apps/advanced/backend/views/layouts/main.php

0
apps/advanced/backstage/views/site/index.php → apps/advanced/backend/views/site/index.php

0
apps/advanced/backstage/views/site/login.php → apps/advanced/backend/views/site/login.php

0
apps/advanced/backstage/www/.gitignore → apps/advanced/backend/www/.gitignore vendored

0
apps/advanced/backstage/www/assets/.gitignore → apps/advanced/backend/www/assets/.gitignore vendored

0
apps/advanced/backstage/www/css/site.css → apps/advanced/backend/www/css/site.css

9
apps/advanced/composer.json

@ -19,17 +19,14 @@
"yiisoft/yii2-composer": "dev-master"
},
"scripts": {
"post-install-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
],
"post-update-cmd": [
"post-create-project-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
]
},
"extra": {
"yii-install-writable": [
"backstage/runtime",
"backstage/www/assets",
"backend/runtime",
"backend/www/assets",
"console/runtime",
"console/migrations",

10
apps/advanced/composer.lock generated

@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "05f7bcd0e99931b52415eaeb62d54daf",
"hash": "2d1053fbaaf2044054f273a71d0ccde0",
"packages": [
{
"name": "yiisoft/yii2",
@ -11,12 +11,12 @@
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-framework.git",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d"
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"shasum": ""
},
"require": {
@ -97,7 +97,7 @@
"framework",
"yii"
],
"time": "2013-05-29 02:55:14"
"time": "2013-06-02 19:19:29"
},
{
"name": "yiisoft/yii2-composer",

4
apps/advanced/init.bat

@ -1,7 +1,7 @@
@echo off
rem -------------------------------------------------------------
rem Yii command line install script for Windows.
rem Yii command line init script for Windows.
rem
rem @author Qiang Xue <qiang.xue@gmail.com>
rem @link http://www.yiiframework.com/
@ -15,6 +15,6 @@ set YII_PATH=%~dp0
if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
"%PHP_COMMAND%" "%YII_PATH%install" %*
"%PHP_COMMAND%" "%YII_PATH%init" %*
@endlocal

15
apps/basic/README.md

@ -59,3 +59,18 @@ assuming `yii-basic` is directly under the document root of your Web server.
### Install from an Archive File
This is not currently available. We will provide it when Yii 2 is formally released.
### Install from development repository
If you've cloned the [Yii 2 framework main development repository](https://github.com/yiisoft/yii2) you
can bootstrap your application with:
~~~
cd yii2/apps/basic
php composer.phar create-project
~~~
*Note: If the above command fails with `[RuntimeException] Not enough arguments.` run
`php composer.phar self-update` to obtain an updated version of composer which supports creating projects
from local packages.*

5
apps/basic/composer.json

@ -19,10 +19,7 @@
"yiisoft/yii2-composer": "dev-master"
},
"scripts": {
"post-install-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
],
"post-update-cmd": [
"post-create-project-cmd": [
"yii\\composer\\InstallHandler::setPermissions"
]
},

10
apps/basic/composer.lock generated

@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "0411dbbd774aa1c89256c77c68023940",
"hash": "91ba258de768b93025f86071f3bb4b84",
"packages": [
{
"name": "yiisoft/yii2",
@ -11,12 +11,12 @@
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-framework.git",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d"
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"reference": "2d93f20ba6044ac3f1957300c4ae85fd98ecf47d",
"url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"reference": "3ad6334be076a80df3b2ea0b57f38bd0c6901989",
"shasum": ""
},
"require": {
@ -97,7 +97,7 @@
"framework",
"yii"
],
"time": "2013-05-29 02:55:14"
"time": "2013-06-02 19:19:29"
},
{
"name": "yiisoft/yii2-composer",

1
apps/basic/config/main.php

@ -4,7 +4,6 @@ return array(
'id' => 'bootstrap',
'basePath' => dirname(__DIR__),
'preload' => array('log'),
'controllerNamespace' => 'app\controllers',
'modules' => array(
// 'debug' => array(
// 'class' => 'yii\debug\Module',

1
apps/basic/controllers/SiteController.php

@ -20,6 +20,7 @@ class SiteController extends Controller
public function actionIndex()
{
Yii::$app->end(0, false);
echo $this->render('index');
}

2
extensions/composer/yii/composer/InstallHandler.php

@ -82,7 +82,7 @@ class InstallHandler
throw new Exception("Config file does not exist: $configFile");
}
require(__DIR__ . '/../../../yii2/yii/Yii.php');
require_once(__DIR__ . '/../../../yii2/yii/Yii.php');
$application = new Application(require($configFile));
$request = $application->getRequest();

4
extensions/smarty/yii/smarty/ViewRenderer.php

@ -26,12 +26,12 @@ class ViewRenderer extends BaseViewRenderer
/**
* @var string the directory or path alias pointing to where Smarty cache will be stored.
*/
public $cachePath = '@app/runtime/Smarty/cache';
public $cachePath = '@runtime/Smarty/cache';
/**
* @var string the directory or path alias pointing to where Smarty compiled templates will be stored.
*/
public $compilePath = '@app/runtime/Smarty/compile';
public $compilePath = '@runtime/Smarty/compile';
/**
* @var Smarty

2
extensions/twig/yii/twig/ViewRenderer.php

@ -25,7 +25,7 @@ class ViewRenderer extends BaseViewRenderer
/**
* @var string the directory or path alias pointing to where Twig cache will be stored.
*/
public $cachePath = '@app/runtime/Twig/cache';
public $cachePath = '@runtime/Twig/cache';
/**
* @var array Twig options

27
framework/yii/YiiBase.php

@ -606,11 +606,36 @@ class YiiBase
public static function t($category, $message, $params = array(), $language = null)
{
if (self::$app !== null) {
return self::$app->getI18N()->translate($category, $message, $params, $language);
return self::$app->getI18N()->translate($category, $message, $params, $language ?: self::$app->language);
} else {
return is_array($params) ? strtr($message, $params) : $message;
}
}
/**
* Configures an object with the initial property values.
* @param object $object the object to be configured
* @param array $properties the property initial values given in terms of name-value pairs.
*/
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
}
/**
* Returns the public member variables of an object.
* This method is provided such that we can get the public member variables of an object.
* It is different from "get_object_vars()" because the latter will return private
* and protected variables if it is called within the object itself.
* @param object $object the object to be handled
* @return array the public member variables of the object
*/
public static function getObjectVars($object)
{
return get_object_vars($object);
}
}
YiiBase::$aliases = array(

76
framework/yii/base/Application.php

@ -72,30 +72,51 @@ class Application extends Module
public function __construct($config = array())
{
Yii::$app = $this;
if (!isset($config['id'])) {
throw new InvalidConfigException('The "id" configuration is required.');
}
if (isset($config['basePath'])) {
$this->setBasePath($config['basePath']);
Yii::setAlias('@app', $this->getBasePath());
unset($config['basePath']);
} else {
throw new InvalidConfigException('The "basePath" configuration is required.');
}
$this->preInit($config);
$this->registerErrorHandlers();
$this->registerCoreComponents();
Component::__construct($config);
}
/**
* Pre-initializes the application.
* This method is called at the beginning of the application constructor.
* @param array $config the application configuration
*/
public function preInit(&$config)
{
if (isset($config['vendorPath'])) {
$this->setVendorPath($config['vendorPath']);
unset($config['vendorPath']);
} else {
// set "@vendor"
$this->getVendorPath();
}
if (isset($config['runtimePath'])) {
$this->setRuntimePath($config['runtimePath']);
unset($config['runtimePath']);
} else {
// set "@runtime"
$this->getRuntimePath();
}
if (isset($config['timeZone'])) {
$this->setTimeZone($config['timeZone']);
unset($config['timeZone']);
} elseif (!ini_get('date.timezone')) {
$this->setTimeZone('UTC');
}
$this->registerErrorHandlers();
$this->registerCoreComponents();
Component::__construct($config);
}
/**
@ -107,6 +128,11 @@ class Application extends Module
ini_set('display_errors', 0);
set_exception_handler(array($this, 'handleException'));
set_error_handler(array($this, 'handleError'), error_reporting());
// Allocating twice more than required to display memory exhausted error
// in case of trying to allocate last 1 byte while all memory is taken.
$this->_memoryReserve = str_repeat('x', 1024 * 256);
register_shutdown_function(array($this, 'end'), 0, false);
register_shutdown_function(array($this, 'handleFatalError'));
}
}
@ -121,11 +147,10 @@ class Application extends Module
{
if (!$this->_ended) {
$this->_ended = true;
$this->getResponse()->end();
$this->afterRequest();
}
$this->handleFatalError();
if ($exit) {
exit($status);
}
@ -139,11 +164,10 @@ class Application extends Module
public function run()
{
$this->beforeRequest();
// Allocating twice more than required to display memory exhausted error
// in case of trying to allocate last 1 byte while all memory is taken.
$this->_memoryReserve = str_repeat('x', 1024 * 256);
register_shutdown_function(array($this, 'end'), 0, false);
$response = $this->getResponse();
$response->begin();
$status = $this->processRequest();
$response->end();
$this->afterRequest();
return $status;
}
@ -178,7 +202,8 @@ class Application extends Module
/**
* Returns the directory that stores runtime files.
* @return string the directory that stores runtime files. Defaults to 'protected/runtime'.
* @return string the directory that stores runtime files.
* Defaults to the "runtime" subdirectory under [[basePath]].
*/
public function getRuntimePath()
{
@ -191,16 +216,11 @@ class Application extends Module
/**
* Sets the directory that stores runtime files.
* @param string $path the directory that stores runtime files.
* @throws InvalidConfigException if the directory does not exist or is not writable
*/
public function setRuntimePath($path)
{
$path = Yii::getAlias($path);
if (is_dir($path) && is_writable($path)) {
$this->_runtimePath = $path;
} else {
throw new InvalidConfigException("Runtime path must be a directory writable by the Web server process: $path");
}
$this->_runtimePath = Yii::getAlias($path);
Yii::setAlias('@runtime', $this->_runtimePath);
}
private $_vendorPath;
@ -208,7 +228,7 @@ class Application extends Module
/**
* Returns the directory that stores vendor files.
* @return string the directory that stores vendor files.
* Defaults to 'vendor' directory under applications [[basePath]].
* Defaults to "vendor" directory under [[basePath]].
*/
public function getVendorPath()
{
@ -225,6 +245,7 @@ class Application extends Module
public function setVendorPath($path)
{
$this->_vendorPath = Yii::getAlias($path);
Yii::setAlias('@vendor', $this->_vendorPath);
}
/**
@ -297,6 +318,15 @@ class Application extends Module
}
/**
* Returns the response component.
* @return \yii\web\Response|\yii\console\Response the response component
*/
public function getResponse()
{
return $this->getComponent('response');
}
/**
* Returns the view object.
* @return View the view object that is used to render various view files.
*/

13
framework/yii/base/ErrorHandler.php

@ -82,11 +82,12 @@ class ErrorHandler extends Component
} elseif (!(Yii::$app instanceof \yii\web\Application)) {
Yii::$app->renderException($exception);
} else {
$response = Yii::$app->getResponse();
if (!headers_sent()) {
if ($exception instanceof HttpException) {
header('HTTP/1.0 ' . $exception->statusCode . ' ' . $exception->getName());
$response->setStatusCode($exception->statusCode);
} else {
header('HTTP/1.0 500 ' . get_class($exception));
$response->setStatusCode(500);
}
}
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
@ -100,13 +101,13 @@ class ErrorHandler extends Component
$view = new View();
$request = '';
foreach (array('GET', 'POST', 'SERVER', 'FILES', 'COOKIE', 'SESSION', 'ENV') as $name) {
if (!empty($GLOBALS['_' . $name])) {
$request .= '$_' . $name . ' = ' . var_export($GLOBALS['_' . $name], true) . ";\n\n";
foreach (array('_GET', '_POST', '_SERVER', '_FILES', '_COOKIE', '_SESSION', '_ENV') as $name) {
if (!empty($GLOBALS[$name])) {
$request .= '$' . $name . ' = ' . var_export($GLOBALS[$name], true) . ";\n\n";
}
}
$request = rtrim($request, "\n\n");
echo $view->renderFile($this->mainView, array(
$response->content = $view->renderFile($this->mainView, array(
'exception' => $exception,
'request' => $request,
), $this);

17
framework/yii/base/Formatter.php

@ -12,7 +12,6 @@ use DateTime;
use yii\helpers\HtmlPurifier;
use yii\helpers\Html;
/**
* Formatter provides a set of commonly used data formatting methods.
*
@ -39,17 +38,19 @@ class Formatter extends Component
public $datetimeFormat = 'Y/m/d h:i:s A';
/**
* @var array the text to be displayed when formatting a boolean value. The first element corresponds
* to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
* to the text display for false, the second element for true. Defaults to `array('No', 'Yes')`.
*/
public $booleanFormat;
/**
* @var string the character displayed as the decimal point when formatting a number.
* If not set, "." will be used.
*/
public $decimalSeparator = '.';
public $decimalSeparator;
/**
* @var string the character displayed as the thousands separator character when formatting a number.
* If not set, "," will be used.
*/
public $thousandSeparator = ',';
public $thousandSeparator;
/**
@ -273,8 +274,12 @@ class Formatter extends Component
*/
public function asDouble($value, $decimals = 2)
{
if ($this->decimalSeparator === null) {
return sprintf("%.{$decimals}f", $value);
} else {
return str_replace('.', $this->decimalSeparator, sprintf("%.{$decimals}f", $value));
}
}
/**
* Formats the value as a number with decimal and thousand separators.
@ -287,6 +292,8 @@ class Formatter extends Component
*/
public function asNumber($value, $decimals = 0)
{
return number_format($value, $decimals, $this->decimalSeparator, $this->thousandSeparator);
$ds = isset($this->decimalSeparator) ? $this->decimalSeparator: '.';
$ts = isset($this->thousandSeparator) ? $this->thousandSeparator: ',';
return number_format($value, $decimals, $ds, $ts);
}
}

63
framework/yii/base/HttpException.php

@ -7,6 +7,7 @@
namespace yii\base;
/**
* HttpException represents an exception caused by an improper request of the end-user.
*
@ -42,66 +43,8 @@ class HttpException extends UserException
*/
public function getName()
{
static $httpCodes = array(
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
118 => 'Connection timed out',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
210 => 'Content Different',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
310 => 'Too many Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested range unsatisfiable',
417 => 'Expectation failed',
418 => 'I’m a teapot',
422 => 'Unprocessable entity',
423 => 'Locked',
424 => 'Method failure',
425 => 'Unordered Collection',
426 => 'Upgrade Required',
449 => 'Retry With',
450 => 'Blocked by Windows Parental Controls',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway ou Proxy Error',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
507 => 'Insufficient storage',
509 => 'Bandwidth Limit Exceeded',
);
if (isset($httpCodes[$this->statusCode])) {
return $httpCodes[$this->statusCode];
if (isset(\yii\web\Response::$statusTexts[$this->statusCode])) {
return \yii\web\Response::$statusTexts[$this->statusCode];
} else {
return 'Error';
}

1
framework/yii/base/InvalidCallException.php

@ -23,4 +23,3 @@ class InvalidCallException extends Exception
return \Yii::t('yii', 'Invalid Call');
}
}

1
framework/yii/base/InvalidConfigException.php

@ -23,4 +23,3 @@ class InvalidConfigException extends Exception
return \Yii::t('yii', 'Invalid Configuration');
}
}

1
framework/yii/base/InvalidParamException.php

@ -23,4 +23,3 @@ class InvalidParamException extends Exception
return \Yii::t('yii', 'Invalid Parameter');
}
}

1
framework/yii/base/InvalidRouteException.php

@ -23,4 +23,3 @@ class InvalidRouteException extends UserException
return \Yii::t('yii', 'Invalid Route');
}
}

22
framework/yii/base/Jsonable.php

@ -0,0 +1,22 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* Jsonable should be implemented by classes that need to be represented in JSON format.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface Jsonable
{
/**
* @return string the JSON representation of this object
*/
public function toJson();
}

13
framework/yii/base/Model.php

@ -10,6 +10,7 @@ namespace yii\base;
use ArrayObject;
use ArrayIterator;
use yii\helpers\Inflector;
use yii\helpers\Json;
use yii\validators\RequiredValidator;
use yii\validators\Validator;
@ -41,7 +42,7 @@ use yii\validators\Validator;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Model extends Component implements \IteratorAggregate, \ArrayAccess
class Model extends Component implements \IteratorAggregate, \ArrayAccess, Jsonable
{
/**
* @event ModelEvent an event raised at the beginning of [[validate()]]. You may set
@ -638,6 +639,16 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Returns the JSON representation of this object.
* The default implementation will return [[attributes]].
* @return string the JSON representation of this object.
*/
public function toJson()
{
return Json::encode($this->getAttributes());
}
/**
* Returns an iterator for traversing the attributes in the model.
* This method is required by the interface IteratorAggregate.
* @return ArrayIterator an iterator for traversing the items in the list.

23
framework/yii/base/Module.php

@ -88,7 +88,11 @@ abstract class Module extends Component
*/
public $controllerMap = array();
/**
* @var string the namespace that controller classes are in. Default is to use global namespace.
* @var string the namespace that controller classes are in. If not set,
* it will use the "controllers" sub-namespace under the namespace of this module.
* For example, if the namespace of this module is "foo\bar", then the default
* controller namespace would be "foo\bar\controllers".
* If the module is an application, it will default to "app\controllers".
*/
public $controllerNamespace;
/**
@ -178,6 +182,16 @@ abstract class Module extends Component
public function init()
{
$this->preloadComponents();
if ($this->controllerNamespace === null) {
if ($this instanceof Application) {
$this->controllerNamespace = 'app\\controllers';
} else {
$class = get_class($this);
if (($pos = strrpos($class, '\\')) !== false) {
$this->controllerNamespace = substr($class, 0, $pos) . '\\controllers';
}
}
}
}
/**
@ -222,6 +236,9 @@ abstract class Module extends Component
$p = realpath($path);
if ($p !== false && is_dir($p)) {
$this->_basePath = $p;
if ($this instanceof Application) {
Yii::setAlias('@app', $p);
}
} else {
throw new InvalidParamException("The directory does not exist: $path");
}
@ -409,11 +426,11 @@ abstract class Module extends Component
* ~~~
* array(
* 'comment' => array(
* 'class' => 'app\modules\CommentModule',
* 'class' => 'app\modules\comment\CommentModule',
* 'db' => 'db',
* ),
* 'booking' => array(
* 'class' => 'app\modules\BookingModule',
* 'class' => 'app\modules\booking\BookingModule',
* ),
* )
* ~~~

1
framework/yii/base/NotSupportedException.php

@ -23,4 +23,3 @@ class NotSupportedException extends Exception
return \Yii::t('yii', 'Not Supported');
}
}

19
framework/yii/base/Object.php

@ -7,12 +7,15 @@
namespace yii\base;
use Yii;
use yii\helpers\Json;
/**
* @include @yii/base/Object.md
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Object
class Object implements Jsonable
{
/**
* @return string the fully qualified name of this class.
@ -38,8 +41,8 @@ class Object
*/
public function __construct($config = array())
{
foreach ($config as $name => $value) {
$this->$name = $value;
if (!empty($config)) {
Yii::configure($this, $config);
}
$this->init();
}
@ -216,4 +219,14 @@ class Object
{
return method_exists($this, 'set' . $name) || $checkVar && property_exists($this, $name);
}
/**
* Returns the JSON representation of this object.
* The default implementation will return all public member variables.
* @return string the JSON representation of this object.
*/
public function toJson()
{
return Json::encode(Yii::getObjectVars($this));
}
}

13
framework/yii/base/Response.php

@ -13,6 +13,9 @@ namespace yii\base;
*/
class Response extends Component
{
const EVENT_BEGIN_RESPONSE = 'beginResponse';
const EVENT_END_RESPONSE = 'endResponse';
/**
* Starts output buffering
*/
@ -56,4 +59,14 @@ class Response extends Component
ob_end_clean();
}
}
public function begin()
{
$this->trigger(self::EVENT_BEGIN_RESPONSE);
}
public function end()
{
$this->trigger(self::EVENT_END_RESPONSE);
}
}

1
framework/yii/base/UnknownClassException.php

@ -23,4 +23,3 @@ class UnknownClassException extends Exception
return \Yii::t('yii', 'Unknown Class');
}
}

1
framework/yii/base/UnknownMethodException.php

@ -23,4 +23,3 @@ class UnknownMethodException extends Exception
return \Yii::t('yii', 'Unknown Method');
}
}

1
framework/yii/base/UnknownPropertyException.php

@ -23,4 +23,3 @@ class UnknownPropertyException extends Exception
return \Yii::t('yii', 'Unknown Property');
}
}

3
framework/yii/bootstrap/Button.php

@ -6,9 +6,8 @@
*/
namespace yii\bootstrap;
use yii\base\InvalidConfigException;
use yii\helpers\Html;
use yii\helpers\Html;
/**
* Button renders a bootstrap button.

2
framework/yii/bootstrap/ButtonDropdown.php

@ -6,8 +6,8 @@
*/
namespace yii\bootstrap;
use yii\helpers\Html;
use yii\helpers\Html;
/**
* ButtonDropdown renders a group or split button dropdown bootstrap component.

1
framework/yii/bootstrap/ButtonGroup.php

@ -10,7 +10,6 @@ namespace yii\bootstrap;
use yii\helpers\base\ArrayHelper;
use yii\helpers\Html;
/**
* ButtonGroup renders a button group bootstrap component.
*

1
framework/yii/bootstrap/Dropdown.php

@ -11,7 +11,6 @@ use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* Dropdown renders a Bootstrap dropdown menu component.
*

24
framework/yii/bootstrap/Nav.php

@ -29,11 +29,17 @@ use yii\helpers\Html;
* 'label' => 'Dropdown',
* 'items' => array(
* array(
* 'label' => 'DropdownA',
* 'label' => 'Level 1 -DropdownA',
* 'url' => '#',
* 'items' => array(
* array(
* 'label' => 'Level 2 -DropdownA',
* 'url' => '#',
* ),
* ),
* ),
* array(
* 'label' => 'DropdownB',
* 'label' => 'Level 1 -DropdownB',
* 'url' => '#',
* ),
* ),
@ -114,7 +120,7 @@ class Nav extends Widget
}
$label = $this->encodeLabels ? Html::encode($item['label']) : $item['label'];
$options = ArrayHelper::getValue($item, 'options', array());
$dropdown = ArrayHelper::getValue($item, 'dropdown');
$items = ArrayHelper::getValue($item, 'items');
$url = Html::url(ArrayHelper::getValue($item, 'url', '#'));
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', array());
@ -122,17 +128,19 @@ class Nav extends Widget
$this->addCssClass($options, 'active');
}
if ($dropdown !== null) {
if ($items !== null) {
$linkOptions['data-toggle'] = 'dropdown';
$this->addCssClass($options, 'dropdown');
$this->addCssClass($urlOptions, 'dropdown-toggle');
$label .= ' ' . Html::tag('b', '', array('class' => 'caret'));
if (is_array($dropdown)) {
$dropdown['clientOptions'] = false;
$dropdown = Dropdown::widget($dropdown);
if (is_array($items)) {
$items = Dropdown::widget(array(
'items' => $items,
'clientOptions' => false,
));
}
}
return Html::tag('li', Html::a($label, $url, $linkOptions) . $dropdown, $options);
return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options);
}
}

1
framework/yii/bootstrap/Progress.php

@ -11,7 +11,6 @@ use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* Progress renders a bootstrap progress bar component.
*

1
framework/yii/bootstrap/Widget.php

@ -11,7 +11,6 @@ use Yii;
use yii\base\View;
use yii\helpers\Json;
/**
* \yii\bootstrap\Widget is the base class for all bootstrap widgets.
*

3
framework/yii/caching/FileCache.php

@ -25,8 +25,9 @@ class FileCache extends Cache
{
/**
* @var string the directory to store cache files. You may use path alias here.
* If not set, it will use the "cache" subdirectory under the application runtime path.
*/
public $cachePath = '@app/runtime/cache';
public $cachePath = '@runtime/cache';
/**
* @var string cache file suffix. Defaults to '.bin'.
*/

1
framework/yii/caching/XCache.php

@ -86,4 +86,3 @@ class XCache extends Cache
return true;
}
}

1
framework/yii/console/Exception.php

@ -25,4 +25,3 @@ class Exception extends UserException
return \Yii::t('yii', 'Error');
}
}

17
framework/yii/console/Response.php

@ -0,0 +1,17 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Response extends \yii\base\Response
{
}

67
framework/yii/console/controllers/AssetController.php

@ -14,6 +14,20 @@ use yii\console\Controller;
/**
* This command allows you to combine and compress your JavaScript and CSS files.
*
* Usage:
* 1. Create a configuration file using 'template' action:
* yii asset/template /path/to/myapp/config.php
* 2. Edit the created config file, adjusting it for your web application needs.
* 3. Run the 'compress' action, using created config:
* yii asset /path/to/myapp/config.php /path/to/myapp/config/assets_compressed.php
* 4. Adjust your web application config to use compressed assets.
*
* Note: in the console environment some path aliases like '@wwwroot' and '@www' may not exist,
* so corresponding paths inside the configuration should be specified directly.
*
* Note: by default this command relies on an external tools to perform actual files compression,
* check [[jsCompressor]] and [[cssCompressor]] for more details.
*
* @property array|\yii\web\AssetManager $assetManager asset manager, which will be used for assets processing.
*
* @author Qiang Xue <qiang.xue@gmail.com>
@ -43,7 +57,7 @@ class AssetController extends Controller
* ~~~
* 'all' => array(
* 'css' => 'all.css',
* 'js' => 'js.css',
* 'js' => 'all.js',
* 'depends' => array( ... ),
* )
* ~~~
@ -150,7 +164,6 @@ class AssetController extends Controller
protected function loadConfiguration($configFile)
{
echo "Loading configuration from '{$configFile}'...\n";
foreach (require($configFile) as $name => $value) {
if (property_exists($this, $name) || $this->canSetProperty($name)) {
$this->$name = $value;
@ -159,7 +172,7 @@ class AssetController extends Controller
}
}
$this->getAssetManager(); // check asset manager configuration
$this->getAssetManager(); // check if asset manager configuration is correct
}
/**
@ -207,7 +220,8 @@ class AssetController extends Controller
* @param array $result already loaded bundles list.
* @throws \yii\console\Exception on failure.
*/
protected function loadBundleDependency($name, $bundle, &$result) {
protected function loadBundleDependency($name, $bundle, &$result)
{
if (!empty($bundle->depends)) {
$assetManager = $this->getAssetManager();
foreach ($bundle->depends as $dependencyName) {
@ -308,7 +322,7 @@ class AssetController extends Controller
/**
* Builds output asset bundle.
* @param \yii\web\AssetBundle $target output asset bundle
* @param string $type either "js" or "css".
* @param string $type either 'js' or 'css'.
* @param \yii\web\AssetBundle[] $bundles source asset bundles.
* @param integer $timestamp current timestamp.
* @throws Exception on failure.
@ -420,17 +434,16 @@ class AssetController extends Controller
}
$array = var_export($array, true);
$version = date('Y-m-d H:i:s', time());
$bytesWritten = file_put_contents($bundleFile, <<<EOD
$bundleFileContent = <<<EOD
<?php
/**
* This file is generated by the "yii script" command.
* This file is generated by the "yii {$this->id}" command.
* DO NOT MODIFY THIS FILE DIRECTLY.
* @version $version
* @version {$version}
*/
return $array;
EOD
);
if ($bytesWritten <= 0) {
return {$array};
EOD;
if (!file_put_contents($bundleFile, $bundleFileContent)) {
throw new Exception("Unable to write output bundle configuration at '{$bundleFile}'.");
}
echo "Output bundle configuration created at '{$bundleFile}'.\n";
@ -498,6 +511,7 @@ EOD
* Combines JavaScript files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function combineJsFiles($inputFiles, $outputFile)
{
@ -507,13 +521,16 @@ EOD
. file_get_contents($file)
. "/*** END FILE: $file ***/\n";
}
file_put_contents($outputFile, $content);
if (!file_put_contents($outputFile, $content)) {
throw new Exception("Unable to write output JavaScript file '{$outputFile}'.");
}
}
/**
* Combines CSS files into a single one.
* @param array $inputFiles source file names.
* @param string $outputFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function combineCssFiles($inputFiles, $outputFile)
{
@ -523,7 +540,9 @@ EOD
. $this->adjustCssUrl(file_get_contents($file), dirname($file), dirname($outputFile))
. "/*** END FILE: $file ***/\n";
}
file_put_contents($outputFile, $content);
if (!file_put_contents($outputFile, $content)) {
throw new Exception("Unable to write output CSS file '{$outputFile}'.");
}
}
/**
@ -590,18 +609,23 @@ EOD
/**
* Creates template of configuration file for [[actionCompress]].
* @param string $configFile output file name.
* @throws \yii\console\Exception on failure.
*/
public function actionTemplate($configFile)
{
$template = <<<EOD
<?php
/**
* Configuration file for the "yii asset" console command.
* Note: in the console environment some path aliases like '@wwwroot' and '@www' may not exist,
* so corresponding paths should be specified directly.
*/
return array(
//
// The list of asset bundles to compress:
'bundles' => require('path/to/bundles.php'),
//
// The list of extensions to compress:
'extensions' => require('path/to/namespaces.php'),
//
// Asset bundle for compression output:
'targets' => array(
'all' => array(
'basePath' => __DIR__,
@ -610,7 +634,7 @@ return array(
'css' => 'all-{ts}.css',
),
),
// Asset manager configuration:
'assetManager' => array(
'basePath' => __DIR__,
'baseUrl' => '/test',
@ -622,9 +646,8 @@ EOD;
return;
}
}
$bytesWritten = file_put_contents($configFile, $template);
if ($bytesWritten<=0) {
echo "Error: unable to write file '{$configFile}'!\n\n";
if (!file_put_contents($configFile, $template)) {
throw new Exception("Unable to write template file '{$configFile}'.");
} else {
echo "Configuration file template created at '{$configFile}'.\n\n";
}

3
framework/yii/console/controllers/MessageController.php

@ -179,8 +179,7 @@ class MessageController extends Controller
}
ksort($translated);
foreach ($translated as $message => $translation) {
if (!isset($merged[$message]) && !isset($todo[$message]) && !$removeOld)
{
if (!isset($merged[$message]) && !isset($todo[$message]) && !$removeOld) {
if (substr($translation, 0, 2) === '@@' && substr($translation, -2) === '@@') {
$todo[$message]=$translation;
} else {

5
framework/yii/web/Pagination.php → framework/yii/data/Pagination.php

@ -5,9 +5,10 @@
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
namespace yii\data;
use Yii;
use yii\base\Object;
/**
* Pagination represents information relevant to pagination of data items.
@ -62,7 +63,7 @@ use Yii;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Pagination extends \yii\base\Object
class Pagination extends Object
{
/**
* @var string name of the parameter storing the current page index. Defaults to 'page'.

5
framework/yii/web/Sort.php → framework/yii/data/Sort.php

@ -5,9 +5,10 @@
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
namespace yii\data;
use Yii;
use yii\base\Object;
use yii\helpers\Html;
/**
@ -68,7 +69,7 @@ use yii\helpers\Html;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Sort extends \yii\base\Object
class Sort extends Object
{
/**
* Sort ascending

8
framework/yii/db/ActiveRecord.php

@ -275,10 +275,16 @@ class ActiveRecord extends Model
/**
* Returns the schema information of the DB table associated with this AR class.
* @return TableSchema the schema information of the DB table associated with this AR class.
* @throws InvalidConfigException if the table for the AR class does not exist.
*/
public static function getTableSchema()
{
return static::getDb()->getTableSchema(static::tableName());
$schema = static::getDb()->getTableSchema(static::tableName());
if ($schema !== null) {
return $schema;
} else {
throw new InvalidConfigException("The table does not exist: " . static::tableName());
}
}
/**

3
framework/yii/db/Connection.php

@ -305,8 +305,7 @@ class Connection extends Component
$this->pdo = $this->createPdoInstance();
$this->initConnection();
Yii::endProfile($token, __METHOD__);
}
catch (\PDOException $e) {
} catch (\PDOException $e) {
Yii::endProfile($token, __METHOD__);
Yii::error("Failed to open DB connection ({$this->dsn}): " . $e->getMessage(), __METHOD__);
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $e->getMessage() : 'Failed to open DB connection.';

10
framework/yii/db/QueryBuilder.php

@ -464,6 +464,12 @@ class QueryBuilder extends \yii\base\Object
* the first part will be converted, and the rest of the parts will be appended to the converted result.
* For example, 'string NOT NULL' is converted to 'varchar(255) NOT NULL'.
*
* For some of the abstract types you can also specify a length or precision constraint
* by prepending it in round brackets directly to the type.
* For example `string(32)` will be converted into "varchar(32)" on a MySQL database.
* If the underlying DBMS does not support these kind of constraints for a type it will
* be ignored.
*
* If a type cannot be found in [[typeMap]], it will be returned without any change.
* @param string $type abstract column type
* @return string physical column type.
@ -472,6 +478,10 @@ class QueryBuilder extends \yii\base\Object
{
if (isset($this->typeMap[$type])) {
return $this->typeMap[$type];
} elseif (preg_match('/^(\w+)\((.+?)\)(.*)$/', $type, $matches)) {
if (isset($this->typeMap[$matches[1]])) {
return preg_replace('/\(.+\)/', '(' . $matches[2] . ')', $this->typeMap[$matches[1]]) . $matches[3];
}
} elseif (preg_match('/^(\w+)\s+/', $type, $matches)) {
if (isset($this->typeMap[$matches[1]])) {
return preg_replace('/^\w+/', $this->typeMap[$matches[1]], $type);

2
framework/yii/db/mssql/QueryBuilder.php

@ -28,7 +28,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'int(11)',
Schema::TYPE_BIGINT => 'bigint(20)',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',

2
framework/yii/db/mysql/QueryBuilder.php

@ -29,7 +29,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'int(11)',
Schema::TYPE_BIGINT => 'bigint(20)',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',

6
framework/yii/db/mysql/Schema.php

@ -178,6 +178,7 @@ class Schema extends \yii\db\Schema
* Collects the metadata of table columns.
* @param TableSchema $table the table metadata
* @return boolean whether the table exists in the database
* @throws \Exception if DB query fails
*/
protected function findColumns($table)
{
@ -185,8 +186,13 @@ class Schema extends \yii\db\Schema
try {
$columns = $this->db->createCommand($sql)->queryAll();
} catch (\Exception $e) {
$previous = $e->getPrevious();
if ($previous instanceof \PDOException && $previous->getCode() == '42S02') {
// table does not exist
return false;
}
throw $e;
}
foreach ($columns as $info) {
$column = $this->loadColumnSchema($info);
$table->columns[$column->name] = $column;

41
framework/yii/db/pgsql/QueryBuilder.php

@ -0,0 +1,41 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\pgsql;
/**
* QueryBuilder is the query builder for PostgreSQL databases.
*
* @author Gevik Babakhani <gevikb@gmail.com>
* @since 2.0
*/
class QueryBuilder extends \yii\db\QueryBuilder
{
/**
* @var array mapping from abstract column types (keys) to physical column types (values).
*/
public $typeMap = array(
Schema::TYPE_PK => 'serial not null primary key',
Schema::TYPE_STRING => 'varchar',
Schema::TYPE_TEXT => 'text',
Schema::TYPE_SMALLINT => 'smallint',
Schema::TYPE_INTEGER => 'integer',
Schema::TYPE_BIGINT => 'bigint',
Schema::TYPE_FLOAT => 'double precision',
Schema::TYPE_DECIMAL => 'numeric',
Schema::TYPE_DATETIME => 'timestamp',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'bytea',
Schema::TYPE_BOOLEAN => 'boolean',
Schema::TYPE_MONEY => 'numeric(19,4)',
);
}

288
framework/yii/db/pgsql/Schema.php

@ -0,0 +1,288 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\pgsql;
use yii\db\TableSchema;
use yii\db\ColumnSchema;
/**
* Schema is the class for retrieving metadata from a PostgreSQL database
* (version 9.x and above).
*
* @author Gevik Babakhani <gevikb@gmail.com>
* @since 2.0
*/
class Schema extends \yii\db\Schema
{
/**
* The default schema used for the current session.
* @var string
*/
public $defaultSchema = 'public';
/**
* @var array mapping from physical column types (keys) to abstract
* column types (values)
*/
public $typeMap = array(
'abstime' => self::TYPE_TIMESTAMP,
'bit' => self::TYPE_STRING,
'boolean' => self::TYPE_BOOLEAN,
'box' => self::TYPE_STRING,
'character' => self::TYPE_STRING,
'bytea' => self::TYPE_BINARY,
'char' => self::TYPE_STRING,
'cidr' => self::TYPE_STRING,
'circle' => self::TYPE_STRING,
'date' => self::TYPE_DATE,
'real' => self::TYPE_FLOAT,
'double precision' => self::TYPE_DECIMAL,
'inet' => self::TYPE_STRING,
'smallint' => self::TYPE_SMALLINT,
'integer' => self::TYPE_INTEGER,
'bigint' => self::TYPE_BIGINT,
'interval' => self::TYPE_STRING,
'json' => self::TYPE_STRING,
'line' => self::TYPE_STRING,
'macaddr' => self::TYPE_STRING,
'money' => self::TYPE_MONEY,
'name' => self::TYPE_STRING,
'numeric' => self::TYPE_STRING,
'numrange' => self::TYPE_DECIMAL,
'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal!
'path' => self::TYPE_STRING,
'point' => self::TYPE_STRING,
'polygon' => self::TYPE_STRING,
'text' => self::TYPE_TEXT,
'time without time zone' => self::TYPE_TIME,
'timestamp without time zone' => self::TYPE_TIMESTAMP,
'timestamp with time zone' => self::TYPE_TIMESTAMP,
'time with time zone' => self::TYPE_TIMESTAMP,
'unknown' => self::TYPE_STRING,
'uuid' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING,
'character varying' => self::TYPE_STRING,
'xml' => self::TYPE_STRING
);
/**
* Creates a query builder for the PostgreSQL database.
* @return QueryBuilder query builder instance
*/
public function createQueryBuilder()
{
return new QueryBuilder($this->db);
}
/**
* Resolves the table name and schema name (if any).
* @param TableSchema $table the table metadata object
* @param string $name the table name
*/
protected function resolveTableNames($table, $name)
{
$parts = explode('.', str_replace('"', '', $name));
if (isset($parts[1])) {
$table->schemaName = $parts[0];
$table->name = $parts[1];
} else {
$table->name = $parts[0];
}
if ($table->schemaName === null) {
$table->schemaName = $this->defaultSchema;
}
}
/**
* Quotes a table name for use in a query.
* A simple table name has no schema prefix.
* @param string $name table name
* @return string the properly quoted table name
*/
public function quoteSimpleTableName($name)
{
return strpos($name, '"') !== false ? $name : '"' . $name . '"';
}
/**
* Loads the metadata for the specified table.
* @param string $name table name
* @return TableSchema|null driver dependent table metadata. Null if the table does not exist.
*/
public function loadTableSchema($name)
{
$table = new TableSchema();
$this->resolveTableNames($table, $name);
if ($this->findColumns($table)) {
$this->findConstraints($table);
return $table;
} else {
return null;
}
}
/**
* Collects the foreign key column details for the given table.
* @param TableSchema $table the table metadata
*/
protected function findConstraints($table)
{
$tableName = $this->quoteValue($table->name);
$tableSchema = $this->quoteValue($table->schemaName);
//We need to extract the constraints de hard way since:
//http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us
$sql = <<<SQL
select
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.conrelid and attnum = any(ct.conkey)) as columns,
fc.relname as foreign_table_name,
fns.nspname as foreign_table_schema,
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.confrelid and attnum = any(ct.confkey)) as foreign_columns
from
pg_constraint ct
inner join pg_class c on c.oid=ct.conrelid
inner join pg_namespace ns on c.relnamespace=ns.oid
left join pg_class fc on fc.oid=ct.confrelid
left join pg_namespace fns on fc.relnamespace=fns.oid
where
ct.contype='f'
and c.relname={$tableName}
and ns.nspname={$tableSchema}
SQL;
$constraints = $this->db->createCommand($sql)->queryAll();
foreach ($constraints as $constraint) {
$columns = explode(',', $constraint['columns']);
$fcolumns = explode(',', $constraint['foreign_columns']);
if ($constraint['foreign_table_schema'] !== $this->defaultSchema) {
$foreignTable = $constraint['foreign_table_schema'] . '.' . $constraint['foreign_table_name'];
} else {
$foreignTable = $constraint['foreign_table_name'];
}
$citem = array($foreignTable);
foreach ($columns as $idx => $column) {
$citem[] = array($fcolumns[$idx] => $column);
}
$table->foreignKeys[] = $citem;
}
}
/**
* Collects the metadata of table columns.
* @param TableSchema $table the table metadata
* @return boolean whether the table exists in the database
*/
protected function findColumns($table)
{
$tableName = $this->db->quoteValue($table->name);
$schemaName = $this->db->quoteValue($table->schemaName);
$sql = <<<SQL
SELECT
current_database() as table_catalog,
d.nspname AS table_schema,
c.relname AS table_name,
a.attname AS column_name,
t.typname AS data_type,
a.attlen AS character_maximum_length,
pg_catalog.col_description(c.oid, a.attnum) AS column_comment,
a.atttypmod AS modifier,
a.attnotnull = false AS is_nullable,
CAST(pg_get_expr(ad.adbin, ad.adrelid) AS varchar) AS column_default,
coalesce(pg_get_expr(ad.adbin, ad.adrelid) ~ 'nextval',false) AS is_autoinc,
array_to_string((select array_agg(enumlabel) from pg_enum where enumtypid=a.atttypid)::varchar[],',') as enum_values,
CASE atttypid
WHEN 21 /*int2*/ THEN 16
WHEN 23 /*int4*/ THEN 32
WHEN 20 /*int8*/ THEN 64
WHEN 1700 /*numeric*/ THEN
CASE WHEN atttypmod = -1
THEN null
ELSE ((atttypmod - 4) >> 16) & 65535
END
WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/
WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/
ELSE null
END AS numeric_precision,
CASE
WHEN atttypid IN (21, 23, 20) THEN 0
WHEN atttypid IN (1700) THEN
CASE
WHEN atttypmod = -1 THEN null
ELSE (atttypmod - 4) & 65535
END
ELSE null
END AS numeric_scale,
CAST(
information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t))
AS numeric
) AS size,
a.attnum = any (ct.conkey) as is_pkey
FROM
pg_class c
LEFT JOIN pg_attribute a ON a.attrelid = c.oid
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
LEFT JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_namespace d ON d.oid = c.relnamespace
LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p'
WHERE
a.attnum > 0
and c.relname = {$tableName}
and d.nspname = {$schemaName}
ORDER BY
a.attnum;
SQL;
$columns = $this->db->createCommand($sql)->queryAll();
foreach ($columns as $column) {
$column = $this->loadColumnSchema($column);
$table->columns[$column->name] = $column;
if ($column->isPrimaryKey === true) {
$table->primaryKey[] = $column->name;
if ($table->sequenceName === null && preg_match("/nextval\('\w+'(::regclass)?\)/", $column->defaultValue) === 1) {
$table->sequenceName = preg_replace(array('/nextval/', '/::/', '/regclass/', '/\'\)/', '/\(\'/'), '', $column->defaultValue);
}
}
}
return true;
}
/**
* Loads the column information into a [[ColumnSchema]] object.
* @param array $info column information
* @return ColumnSchema the column schema object
*/
protected function loadColumnSchema($info)
{
$column = new ColumnSchema();
$column->allowNull = $info['is_nullable'];
$column->autoIncrement = $info['is_autoinc'];
$column->comment = $info['column_comment'];
$column->dbType = $info['data_type'];
$column->defaultValue = $info['column_default'];
$column->enumValues = explode(',', str_replace(array("''"), array("'"), $info['enum_values']));
$column->unsigned = false; // has no meanining in PG
$column->isPrimaryKey = $info['is_pkey'];
$column->name = $info['column_name'];
$column->precision = $info['numeric_precision'];
$column->scale = $info['numeric_scale'];
$column->size = $info['size'];
if (isset($this->typeMap[$column->dbType])) {
$column->type = $this->typeMap[$column->dbType];
} else {
$column->type = self::TYPE_STRING;
}
$column->phpType = $this->getColumnPhpType($column);
return $column;
}
}

4
framework/yii/db/sqlite/QueryBuilder.php

@ -30,13 +30,13 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_INTEGER => 'integer',
Schema::TYPE_BIGINT => 'bigint',
Schema::TYPE_FLOAT => 'float',
Schema::TYPE_DECIMAL => 'decimal',
Schema::TYPE_DECIMAL => 'decimal(10,0)',
Schema::TYPE_DATETIME => 'datetime',
Schema::TYPE_TIMESTAMP => 'timestamp',
Schema::TYPE_TIME => 'time',
Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'blob',
Schema::TYPE_BOOLEAN => 'tinyint(1)',
Schema::TYPE_BOOLEAN => 'boolean',
Schema::TYPE_MONEY => 'decimal(19,4)',
);

1
framework/yii/helpers/Json.php

@ -14,5 +14,4 @@ namespace yii\helpers;
*/
class Json extends base\Json
{
}

1
framework/yii/helpers/base/Console.php

@ -593,7 +593,6 @@ class Console
return $size = array((int)preg_replace('~[^0-9]~', '', $output[3]), (int)preg_replace('~[^0-9]~', '', $output[4]));
}
} else {
// try stty if available
$stty = array();
if (exec('stty -a 2>&1', $stty) && preg_match('/rows\s+(\d+);\s*columns\s+(\d+);/mi', implode(' ', $stty), $matches)) {

1
framework/yii/helpers/base/Html.php

@ -1479,5 +1479,4 @@ class Html
$name = strtolower(static::getInputName($model, $attribute));
return str_replace(array('[]', '][', '[', ']', ' '), array('', '-', '-', '', '-'), $name);
}
}

2
framework/yii/helpers/base/Inflector.php

@ -498,7 +498,7 @@ class Inflector
if (in_array(($number % 100), range(11, 13))) {
return $number . 'th';
}
switch (($number % 10)) {
switch ($number % 10) {
case 1: return $number . 'st';
case 2: return $number . 'nd';
case 3: return $number . 'rd';

6
framework/yii/helpers/base/Json.php

@ -8,6 +8,7 @@
namespace yii\helpers\base;
use yii\base\InvalidParamException;
use yii\base\Jsonable;
use yii\web\JsExpression;
/**
@ -90,7 +91,9 @@ class Json
$token = '!{[' . count($expressions) . ']}!';
$expressions['"' . $token . '"'] = $data->expression;
return $token;
}
} elseif ($data instanceof Jsonable) {
return $data->toJson();
} else {
$result = array();
foreach ($data as $key => $value) {
if (is_array($value) || is_object($value)) {
@ -100,6 +103,7 @@ class Json
}
}
return $result;
}
} else {
return $data;
}

21
framework/yii/helpers/base/SecurityHelper.php

@ -131,15 +131,30 @@ class SecurityHelper
$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);
$keys[$name] = static::generateRandomKey($length);
file_put_contents($keyFile, "<?php\nreturn " . var_export($keys, true) . ";\n");
}
return $keys[$name];
}
/**
* Generates a random key.
* @param integer $length the length of the key that should be generated
* @return string the generated random key
*/
public static function generateRandomKey($length = 32)
{
if (function_exists('openssl_random_pseudo_bytes')) {
$key = base64_encode(openssl_random_pseudo_bytes($length, $strong));
if ($strong) {
return substr($key, 0, $length);
}
}
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return substr(str_shuffle(str_repeat($chars, 5)), 0, $length);
}
/**
* Opens the mcrypt module.
* @return resource the mcrypt module handle.
* @throws InvalidConfigException if mcrypt extension is not installed

158
framework/yii/i18n/DbMessageSource.php

@ -0,0 +1,158 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\i18n;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\caching\Cache;
use yii\db\Connection;
use yii\db\Query;
/**
* DbMessageSource extends [[MessageSource]] and represents a message source that stores translated
* messages in database.
*
* The database must contain the following two tables:
*
* ~~~
* CREATE TABLE tbl_source_message (
* id INTEGER PRIMARY KEY,
* category VARCHAR(32),
* message TEXT
* );
*
* CREATE TABLE tbl_message (
* id INTEGER,
* language VARCHAR(16),
* translation TEXT,
* PRIMARY KEY (id, language),
* CONSTRAINT fk_message_source_message FOREIGN KEY (id)
* REFERENCES tbl_source_message (id) ON DELETE CASCADE ON UPDATE RESTRICT
* );
* ~~~
*
* The `tbl_source_message` table stores the messages to be translated, and the `tbl_message` table stores
* the translated messages. The name of these two tables can be customized by setting [[sourceMessageTable]]
* and [[messageTable]], respectively.
*
* @author resurtm <resurtm@gmail.com>
* @since 2.0
*/
class DbMessageSource extends MessageSource
{
/**
* Prefix which would be used when generating cache key.
*/
const CACHE_KEY_PREFIX = 'DbMessageSource';
/**
* @var Connection|string the DB connection object or the application component ID of the DB connection.
* After the DbMessageSource object is created, if you want to change this property, you should only assign
* it with a DB connection object.
*/
public $db = 'db';
/**
* @var Cache|string the cache object or the application component ID of the cache object.
* The messages data will be cached using this cache object. Note, this property has meaning only
* in case [[cachingDuration]] set to non-zero value.
* After the DbMessageSource object is created, if you want to change this property, you should only assign
* it with a cache object.
*/
public $cache = 'cache';
/**
* @var string the name of the source message table.
*/
public $sourceMessageTable = 'tbl_source_message';
/**
* @var string the name of the translated message table.
*/
public $messageTable = 'tbl_message';
/**
* @var integer the time in seconds that the messages can remain valid in cache.
* Use 0 to indicate that the cached data will never expire.
* @see enableCaching
*/
public $cachingDuration = 0;
/**
* @var boolean whether to enable caching translated messages
*/
public $enableCaching = false;
/**
* Initializes the DbMessageSource component.
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
* Configured [[cache]] component would also be initialized.
* @throws InvalidConfigException if [[db]] is invalid or [[cache]] is invalid.
*/
public function init()
{
parent::init();
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbMessageSource::db must be either a DB connection instance or the application component ID of a DB connection.");
}
if ($this->enableCaching) {
if (is_string($this->cache)) {
$this->cache = Yii::$app->getComponent($this->cache);
}
if (!$this->cache instanceof Cache) {
throw new InvalidConfigException("DbMessageSource::cache must be either a cache object or the application component ID of the cache object.");
}
}
}
/**
* Loads the message translation for the specified language and category.
* Child classes should override this method to return the message translations of
* the specified language and category.
* @param string $category the message category
* @param string $language the target language
* @return array the loaded messages. The keys are original messages, and the values
* are translated messages.
*/
protected function loadMessages($category, $language)
{
if ($this->enableCaching) {
$key = array(
__CLASS__,
$category,
$language,
);
$messages = $this->cache->get($key);
if ($messages === false) {
$messages = $this->loadMessagesFromDb($category, $language);
$this->cache->set($key, $messages, $this->cachingDuration);
}
return $messages;
} else {
return $this->loadMessagesFromDb($category, $language);
}
}
/**
* Loads the messages from database.
* You may override this method to customize the message storage in the database.
* @param string $category the message category.
* @param string $language the target language.
* @return array the messages loaded from database.
*/
protected function loadMessagesFromDb($category, $language)
{
$query = new Query();
$messages = $query->select(array('t1.message message', 't2.translation translation'))
->from(array($this->sourceMessageTable . ' t1', $this->messageTable . ' t2'))
->where('t1.id = t2.id AND t1.category = :category AND t2.language = :language')
->params(array(':category' => $category, ':language' => $language))
->createCommand($this->db)
->queryAll();
return ArrayHelper::map($messages, 'message', 'translation');
}
}

58
framework/yii/i18n/Formatter.php

@ -30,21 +30,40 @@ class Formatter extends \yii\base\Formatter
*/
public $locale;
/**
* @var string the default format string to be used to format a date using PHP date() function.
* @var string the default format string to be used to format a date.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $dateFormat = 'short';
/**
* @var string the default format string to be used to format a time using PHP date() function.
* @var string the default format string to be used to format a time.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $timeFormat = 'short';
/**
* @var string the default format string to be used to format a date and time using PHP date() function.
* @var string the default format string to be used to format a date and time.
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*/
public $datetimeFormat = 'short';
/**
* @var array the options to be set for the NumberFormatter objects. Please refer to
* [PHP manual](http://php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants.unumberformatattribute)
* for the possible options. This property is used by [[createNumberFormatter]] when
* creating a new number formatter to format decimals, currencies, etc.
*/
public $numberFormatOptions = array();
/**
* @var string the character displayed as the decimal point when formatting a number.
* If not set, the decimal separator corresponding to [[locale]] will be used.
*/
public $decimalSeparator;
/**
* @var string the character displayed as the thousands separator character when formatting a number.
* If not set, the thousand separator corresponding to [[locale]] will be used.
*/
public $thousandSeparator;
/**
@ -61,6 +80,16 @@ class Formatter extends \yii\base\Formatter
if ($this->locale === null) {
$this->locale = Yii::$app->language;
}
if ($this->decimalSeparator === null || $this->thousandSeparator === null) {
$formatter = new NumberFormatter($this->locale, NumberFormatter::DECIMAL);
if ($this->decimalSeparator === null) {
$this->decimalSeparator = $formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
}
if ($this->thousandSeparator === null) {
$this->thousandSeparator = $formatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
}
}
parent::init();
}
@ -81,8 +110,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see dateFormat
*/
@ -111,8 +143,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see timeFormat
*/
@ -141,8 +176,11 @@ class Formatter extends \yii\base\Formatter
* - a PHP DateTime object
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used. The format string should be the one
* that can be recognized by the PHP `date()` function.
* If null, [[dateFormat]] will be used.
*
* This can be "short", "medium", "long", or "full", which represents a preset format of different lengths.
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* @return string the formatted result
* @see datetimeFormat
*/
@ -213,7 +251,7 @@ class Formatter extends \yii\base\Formatter
/**
* Creates a number formatter based on the given type and format.
* @param integer $type the type of the number formatter
* @param string $format the format to be used
* @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
* @return NumberFormatter the created formatter instance
*/
protected function createNumberFormatter($type, $format)

9
framework/yii/i18n/I18N.php

@ -78,16 +78,11 @@ class I18N extends Component
* @param string $category the message category.
* @param string $message the message to be translated.
* @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
* @param string $language the language code (e.g. `en_US`, `en`). If this is null, the current
* [[\yii\base\Application::language|application language]] will be used.
* @param string $language the language code (e.g. `en_US`, `en`).
* @return string the translated message.
*/
public function translate($category, $message, $params = array(), $language = null)
public function translate($category, $message, $params, $language)
{
if ($language === null) {
$language = Yii::$app->language;
}
$message = $this->getMessageSource($category)->translate($category, $message, $language);
if (!is_array($params)) {

1
framework/yii/i18n/MessageSource.php

@ -118,4 +118,3 @@ class MessageSource extends Component
}
}
}

2
framework/yii/jui/Accordion.php

@ -125,7 +125,7 @@ class Accordion extends Widget
$items[] = Html::tag($headerTag, $item['header'], $headerOptions);
$options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', array()));
$tag = ArrayHelper::remove($options, 'tag', 'div');
$items[] = Html::tag($tag, $item['content'], $options);;
$items[] = Html::tag($tag, $item['content'], $options);
}
return implode("\n", $items);

1
framework/yii/jui/Menu.php

@ -10,7 +10,6 @@ namespace yii\jui;
use Yii;
use yii\helpers\Json;
/**
* Menu renders a menu jQuery UI widget.
*

1
framework/yii/jui/Widget.php

@ -10,7 +10,6 @@ namespace yii\jui;
use Yii;
use yii\helpers\Json;
/**
* \yii\jui\Widget is the base class for all jQuery UI widgets.
*

2
framework/yii/logging/ProfileTarget.php

@ -70,7 +70,7 @@ class CProfileLogRoute extends CWebLogRoute
public function processLogs($logs)
{
$app = \Yii::$app;
if (!($app instanceof CWebApplication) || $app->getRequest()->getIsAjaxRequest())
if (!($app instanceof \yii\web\Application) || $app->getRequest()->getIsAjax())
return;
if ($this->getReport() === 'summary')

2
framework/yii/logging/Target.php

@ -204,14 +204,12 @@ abstract class Target extends Component
if ($matched) {
foreach ($this->except as $category) {
$prefix = rtrim($category, '*');
foreach ($messages as $i => $message) {
if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) {
$matched = false;
break;
}
}
}
}
if (!$matched) {
unset($messages[$i]);

3
framework/yii/rbac/DbManager.php

@ -493,9 +493,10 @@ class DbManager extends Manager
'bizRule' => $row['biz_rule'],
'data' => $data,
));
} else
} else {
return null;
}
}
/**
* Saves an authorization item to persistent storage.

1
framework/yii/validators/CaptchaValidator.php

@ -117,4 +117,3 @@ class CaptchaValidator extends Validator
return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');';
}
}

2
framework/yii/validators/CompareValidator.php

@ -58,7 +58,7 @@ class CompareValidator extends Validator
* - `<`: validates to see if the value being validated is less than the value being compared with.
* - `<=`: validates to see if the value being validated is less than or equal to the value being compared with.
*/
public $operator = '=';
public $operator = '==';
/**
* @var string the user-defined error message. It may contain the following placeholders which
* will be replaced accordingly by the validator:

3
framework/yii/validators/DateValidator.php

@ -58,7 +58,7 @@ class DateValidator extends Validator
$date = DateTime::createFromFormat($this->format, $value);
if ($date === false) {
$this->addError($object, $attribute, $this->message);
} elseif ($this->timestampAttribute !== false) {
} elseif ($this->timestampAttribute !== null) {
$object->{$this->timestampAttribute} = $date->getTimestamp();
}
}
@ -73,4 +73,3 @@ class DateValidator extends Validator
return DateTime::createFromFormat($this->format, $value) !== false;
}
}

1
framework/yii/validators/DefaultValueValidator.php

@ -40,4 +40,3 @@ class DefaultValueValidator extends Validator
}
}
}

1
framework/yii/validators/ExistValidator.php

@ -99,4 +99,3 @@ class ExistValidator extends Validator
return $query->exists();
}
}

1
framework/yii/validators/FilterValidator.php

@ -6,6 +6,7 @@
*/
namespace yii\validators;
use yii\base\InvalidConfigException;
/**

1
framework/yii/validators/StringValidator.php

@ -174,4 +174,3 @@ class StringValidator extends Validator
return 'yii.validation.string(value, messages, ' . json_encode($options) . ');';
}
}

2
framework/yii/web/AccessRule.php

@ -99,7 +99,7 @@ class AccessRule extends Component
if ($this->matchAction($action)
&& $this->matchRole($user)
&& $this->matchIP($request->getUserIP())
&& $this->matchVerb($request->getRequestMethod())
&& $this->matchVerb($request->getMethod())
&& $this->matchController($action->controller)
&& $this->matchCustom($action)
) {

28
framework/yii/web/CaptchaAction.php

@ -277,11 +277,8 @@ class CaptchaAction extends Action
imagecolordeallocate($image, $foreColor);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-type: image/png");
$this->sendHttpHeaders();
imagepng($image);
imagedestroy($image);
}
@ -319,12 +316,21 @@ class CaptchaAction extends Action
$x += (int)($fontMetrics['textWidth']) + $this->offset;
}
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-type: image/png");
$image->setImageFormat('png');
echo $image;
Yii::$app->getResponse()->content = (string)$image;
$this->sendHttpHeaders();
}
/**
* Sends the HTTP headers needed by image response.
*/
protected function sendHttpHeaders()
{
Yii::$app->getResponse()->getHeaders()
->set('Pragma', 'public')
->set('Expires', '0')
->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->set('Content-Transfer-Encoding', 'binary')
->set('Content-type', 'image/png');
}
}

2
framework/yii/web/Cookie.php

@ -45,7 +45,7 @@ class Cookie extends \yii\base\Object
* By setting this property to true, the cookie will not be accessible by scripting languages,
* such as JavaScript, which can effectively help to reduce identity theft through XSS attacks.
*/
public $httponly = false;
public $httpOnly = false;
/**
* Magic method to turn a cookie object into a string without having to explicitly access [[value]].

111
framework/yii/web/CookieCollection.php

@ -9,7 +9,8 @@ namespace yii\web;
use Yii;
use ArrayIterator;
use yii\helpers\SecurityHelper;
use yii\base\InvalidCallException;
use yii\base\Object;
/**
* CookieCollection maintains the cookies available in the current request.
@ -19,17 +20,12 @@ use yii\helpers\SecurityHelper;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \ArrayAccess, \Countable
class CookieCollection extends Object implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var boolean whether to enable cookie validation. By setting this property to true,
* if a cookie is tampered on the client side, it will be ignored when received on the server side.
* @var boolean whether this collection is read only.
*/
public $enableValidation = true;
/**
* @var string the secret key used for cookie validation. If not set, a random key will be generated and used.
*/
public $validationKey;
public $readOnly = false;
/**
* @var Cookie[] the cookies in this collection (indexed by the cookie names)
@ -38,12 +34,14 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
/**
* Constructor.
* @param array $cookies the cookies that this collection initially contains. This should be
* an array of name-value pairs.s
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($config = array())
public function __construct($cookies = array(), $config = array())
{
$this->_cookies = $cookies;
parent::__construct($config);
$this->_cookies = $this->loadCookies();
}
/**
@ -101,53 +99,66 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
}
/**
* Returns whether there is a cookie with the specified name.
* @param string $name the cookie name
* @return boolean whether the named cookie exists
*/
public function has($name)
{
return isset($this->_cookies[$name]);
}
/**
* Adds a cookie to the collection.
* If there is already a cookie with the same name in the collection, it will be removed first.
* @param Cookie $cookie the cookie to be added
* @throws InvalidCallException if the cookie collection is read only
*/
public function add($cookie)
{
if (isset($this->_cookies[$cookie->name])) {
$c = $this->_cookies[$cookie->name];
setcookie($c->name, '', 0, $c->path, $c->domain, $c->secure, $c->httponly);
}
$value = $cookie->value;
if ($this->enableValidation) {
if ($this->validationKey === null) {
$key = SecurityHelper::getSecretKey(__CLASS__ . '/' . Yii::$app->id);
} else {
$key = $this->validationKey;
if ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
$value = SecurityHelper::hashData(serialize($value), $key);
}
setcookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httponly);
$this->_cookies[$cookie->name] = $cookie;
}
/**
* Removes a cookie from the collection.
* Removes a cookie.
* If `$removeFromBrowser` is true, the cookie will be removed from the browser.
* In this case, a cookie with outdated expiry will be added to the collection.
* @param Cookie|string $cookie the cookie object or the name of the cookie to be removed.
* @param boolean $removeFromBrowser whether to remove the cookie from browser
* @throws InvalidCallException if the cookie collection is read only
*/
public function remove($cookie)
public function remove($cookie, $removeFromBrowser = true)
{
if (is_string($cookie) && isset($this->_cookies[$cookie])) {
$cookie = $this->_cookies[$cookie];
if ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
if ($cookie instanceof Cookie) {
setcookie($cookie->name, '', 0, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httponly);
$cookie->expire = 1;
$cookie->value = '';
} else {
$cookie = new Cookie(array(
'name' => $cookie,
'expire' => 1,
));
}
if ($removeFromBrowser) {
$this->_cookies[$cookie->name] = $cookie;
} else {
unset($this->_cookies[$cookie->name]);
}
}
/**
* Removes all cookies.
* @throws InvalidCallException if the cookie collection is read only
*/
public function removeAll()
{
foreach ($this->_cookies as $cookie) {
setcookie($cookie->name, '', 0, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httponly);
if ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
$this->_cookies = array();
}
@ -172,7 +183,7 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
*/
public function offsetExists($name)
{
return isset($this->_cookies[$name]);
return $this->has($name);
}
/**
@ -212,36 +223,4 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
{
$this->remove($name);
}
/**
* Returns the current cookies in terms of [[Cookie]] objects.
* @return Cookie[] list of current cookies
*/
protected function loadCookies()
{
$cookies = array();
if ($this->enableValidation) {
if ($this->validationKey === null) {
$key = SecurityHelper::getSecretKey(__CLASS__ . '/' . Yii::$app->id);
} else {
$key = $this->validationKey;
}
foreach ($_COOKIE as $name => $value) {
if (is_string($value) && ($value = SecurityHelper::validateData($value, $key)) !== false) {
$cookies[$name] = new Cookie(array(
'name' => $name,
'value' => @unserialize($value),
));
}
}
} else {
foreach ($_COOKIE as $name => $value) {
$cookies[$name] = new Cookie(array(
'name' => $name,
'value' => $value,
));
}
}
return $cookies;
}
}

201
framework/yii/web/HeaderCollection.php

@ -0,0 +1,201 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use Yii;
use yii\base\Object;
use ArrayIterator;
/**
* HeaderCollection is used by [[Response]] to maintain the currently registered HTTP headers.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var array the headers in this collection (indexed by the header names)
*/
private $_headers = array();
/**
* Returns an iterator for traversing the headers in the collection.
* This method is required by the SPL interface `IteratorAggregate`.
* It will be implicitly called when you use `foreach` to traverse the collection.
* @return ArrayIterator an iterator for traversing the headers in the collection.
*/
public function getIterator()
{
return new ArrayIterator($this->_headers);
}
/**
* Returns the number of headers in the collection.
* This method is required by the SPL `Countable` interface.
* It will be implicitly called when you use `count($collection)`.
* @return integer the number of headers in the collection.
*/
public function count()
{
return $this->getCount();
}
/**
* Returns the number of headers in the collection.
* @return integer the number of headers in the collection.
*/
public function getCount()
{
return count($this->_headers);
}
/**
* Returns the named header(s).
* @param string $name the name of the header to return
* @param mixed $default the value to return in case the named header does not exist
* @param boolean $first whether to only return the first header of the specified name.
* If false, all headers of the specified name will be returned.
* @return string|array the named header(s). If `$first` is true, a string will be returned;
* If `$first` is false, an array will be returned.
*/
public function get($name, $default = null, $first = true)
{
$name = strtolower($name);
if (isset($this->_headers[$name])) {
return $first ? reset($this->_headers[$name]) : $this->_headers[$name];
} else {
return $default;
}
}
/**
* Adds a new header.
* If there is already a header with the same name, it will be replaced.
* @param string $name the name of the header
* @param string $value the value of the header
* @return HeaderCollection the collection object itself
*/
public function set($name, $value = '')
{
$name = strtolower($name);
$this->_headers[$name] = (array)$value;
return $this;
}
/**
* Adds a new header.
* If there is already a header with the same name, the new one will
* be appended to it instead of replacing it.
* @param string $name the name of the header
* @param string $value the value of the header
* @return HeaderCollection the collection object itself
*/
public function add($name, $value)
{
$name = strtolower($name);
$this->_headers[$name][] = $value;
return $this;
}
/**
* Returns a value indicating whether the named header exists.
* @param string $name the name of the header
* @return boolean whether the named header exists
*/
public function has($name)
{
$name = strtolower($name);
return isset($this->_headers[$name]);
}
/**
* Removes a header.
* @param string $name the name of the header to be removed.
* @return string the value of the removed header. Null is returned if the header does not exist.
*/
public function remove($name)
{
$name = strtolower($name);
if (isset($this->_headers[$name])) {
$value = $this->_headers[$name];
unset($this->_headers[$name]);
return $value;
} else {
return null;
}
}
/**
* Removes all headers.
*/
public function removeAll()
{
$this->_headers = array();
}
/**
* Returns the collection as a PHP array.
* @return array the array representation of the collection.
* The array keys are header names, and the array values are the corresponding header values.
*/
public function toArray()
{
return $this->_headers;
}
/**
* Returns whether there is a header with the specified name.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `isset($collection[$name])`.
* @param string $name the header name
* @return boolean whether the named header exists
*/
public function offsetExists($name)
{
return $this->has($name);
}
/**
* Returns the header with the specified name.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$header = $collection[$name];`.
* This is equivalent to [[get()]].
* @param string $name the header name
* @return string the header value with the specified name, null if the named header does not exist.
*/
public function offsetGet($name)
{
return $this->get($name);
}
/**
* Adds the header to the collection.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `$collection[$name] = $header;`.
* This is equivalent to [[add()]].
* @param string $name the header name
* @param string $value the header value to be added
*/
public function offsetSet($name, $value)
{
$this->set($name, $value);
}
/**
* Removes the named header.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `unset($collection[$name])`.
* This is equivalent to [[remove()]].
* @param string $name the header name
*/
public function offsetUnset($name)
{
$this->remove($name);
}
}

16
framework/yii/web/HttpCache.php

@ -50,7 +50,7 @@ class HttpCache extends ActionFilter
/**
* @var string HTTP cache control header. If null, the header will not be sent.
*/
public $cacheControlHeader = 'Cache-Control: max-age=3600, public';
public $cacheControlHeader = 'max-age=3600, public';
/**
* This method is invoked right before an action is to be executed (after all possible filters.)
@ -60,7 +60,7 @@ class HttpCache extends ActionFilter
*/
public function beforeAction($action)
{
$verb = Yii::$app->request->getRequestMethod();
$verb = Yii::$app->getRequest()->getMethod();
if ($verb !== 'GET' && $verb !== 'HEAD' || $this->lastModified === null && $this->etagSeed === null) {
return true;
}
@ -75,17 +75,18 @@ class HttpCache extends ActionFilter
}
$this->sendCacheControlHeader();
$response = Yii::$app->getResponse();
if ($etag !== null) {
header("ETag: $etag");
$response->getHeaders()->set('Etag', $etag);
}
if ($this->validateCache($lastModified, $etag)) {
header('HTTP/1.1 304 Not Modified');
$response->setStatusCode(304);
return false;
}
if ($lastModified !== null) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
$response->getHeaders()->set('Last-Modified', gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
}
return true;
}
@ -113,9 +114,10 @@ class HttpCache extends ActionFilter
protected function sendCacheControlHeader()
{
session_cache_limiter('public');
header('Pragma:', true);
$headers = Yii::$app->getResponse()->getHeaders();
$headers->set('Pragma');
if ($this->cacheControlHeader !== null) {
header($this->cacheControlHeader, true);
$headers->set('Cache-Control', $this->cacheControlHeader);
}
}

94
framework/yii/web/Request.php

@ -10,6 +10,7 @@ namespace yii\web;
use Yii;
use yii\base\HttpException;
use yii\base\InvalidConfigException;
use yii\helpers\SecurityHelper;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
@ -37,19 +38,15 @@ class Request extends \yii\base\Request
* @var array the configuration of the CSRF cookie. This property is used only when [[enableCsrfValidation]] is true.
* @see Cookie
*/
public $csrfCookie = array('httponly' => true);
public $csrfCookie = array('httpOnly' => true);
/**
* @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to true.
*/
public $enableCookieValidation = true;
/**
* @var string the secret key used for cookie validation. If not set, a random key will be generated and used.
*/
public $cookieValidationKey;
/**
* @var string|boolean the name of the POST parameter that is used to indicate if a request is a PUT or DELETE
* request tunneled through POST. Default to '_method'.
* @see getRequestMethod
* @see getMethod
* @see getRestParams
*/
public $restVar = '_method';
@ -81,7 +78,7 @@ class Request extends \yii\base\Request
* @return string request method, such as GET, POST, HEAD, PUT, DELETE.
* The value returned is turned into upper case.
*/
public function getRequestMethod()
public function getMethod()
{
if (isset($_POST[$this->restVar])) {
return strtoupper($_POST[$this->restVar]);
@ -94,34 +91,34 @@ class Request extends \yii\base\Request
* Returns whether this is a POST request.
* @return boolean whether this is a POST request.
*/
public function getIsPostRequest()
public function getIsPost()
{
return $this->getRequestMethod() === 'POST';
return $this->getMethod() === 'POST';
}
/**
* Returns whether this is a DELETE request.
* @return boolean whether this is a DELETE request.
*/
public function getIsDeleteRequest()
public function getIsDelete()
{
return $this->getRequestMethod() === 'DELETE';
return $this->getMethod() === 'DELETE';
}
/**
* Returns whether this is a PUT request.
* @return boolean whether this is a PUT request.
*/
public function getIsPutRequest()
public function getIsPut()
{
return $this->getRequestMethod() === 'PUT';
return $this->getMethod() === 'PUT';
}
/**
* Returns whether this is an AJAX (XMLHttpRequest) request.
* @return boolean whether this is an AJAX (XMLHttpRequest) request.
*/
public function getIsAjaxRequest()
public function getIsAjax()
{
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}
@ -130,7 +127,7 @@ class Request extends \yii\base\Request
* Returns whether this is an Adobe Flash or Flex request.
* @return boolean whether this is an Adobe Flash or Adobe Flex request.
*/
public function getIsFlashRequest()
public function getIsFlash()
{
return isset($_SERVER['HTTP_USER_AGENT']) &&
(stripos($_SERVER['HTTP_USER_AGENT'], 'Shockwave') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'Flash') !== false);
@ -141,7 +138,7 @@ class Request extends \yii\base\Request
/**
* Returns the request parameters for the RESTful request.
* @return array the RESTful request parameters
* @see getRequestMethod
* @see getMethod
*/
public function getRestParams()
{
@ -203,7 +200,7 @@ class Request extends \yii\base\Request
* @return mixed the GET parameter value
* @see getPost
*/
public function getParam($name, $defaultValue = null)
public function get($name, $defaultValue = null)
{
return isset($_GET[$name]) ? $_GET[$name] : $defaultValue;
}
@ -229,7 +226,7 @@ class Request extends \yii\base\Request
*/
public function getDelete($name, $defaultValue = null)
{
return $this->getIsDeleteRequest() ? $this->getRestParam($name, $defaultValue) : null;
return $this->getIsDelete() ? $this->getRestParam($name, $defaultValue) : null;
}
/**
@ -240,7 +237,7 @@ class Request extends \yii\base\Request
*/
public function getPut($name, $defaultValue = null)
{
return $this->getIsPutRequest() ? $this->getRestParam($name, $defaultValue) : null;
return $this->getIsPut() ? $this->getRestParam($name, $defaultValue) : null;
}
private $_hostInfo;
@ -717,14 +714,64 @@ class Request extends \yii\base\Request
public function getCookies()
{
if ($this->_cookies === null) {
$this->_cookies = new CookieCollection(array(
'enableValidation' => $this->enableCookieValidation,
'validationKey' => $this->cookieValidationKey,
$this->_cookies = new CookieCollection($this->loadCookies(), array(
'readOnly' => true,
));
}
return $this->_cookies;
}
/**
* Converts `$_COOKIE` into an array of [[Cookie]].
* @return array the cookies obtained from request
*/
protected function loadCookies()
{
$cookies = array();
if ($this->enableCookieValidation) {
$key = $this->getCookieValidationKey();
foreach ($_COOKIE as $name => $value) {
if (is_string($value) && ($value = SecurityHelper::validateData($value, $key)) !== false) {
$cookies[$name] = new Cookie(array(
'name' => $name,
'value' => @unserialize($value),
));
}
}
} else {
foreach ($_COOKIE as $name => $value) {
$cookies[$name] = new Cookie(array(
'name' => $name,
'value' => $value,
));
}
}
return $cookies;
}
private $_cookieValidationKey;
/**
* @return string the secret key used for cookie validation. If it was set previously,
* a random key will be generated and used.
*/
public function getCookieValidationKey()
{
if ($this->_cookieValidationKey === null) {
$this->_cookieValidationKey = SecurityHelper::getSecretKey(__CLASS__ . '/' . Yii::$app->id);
}
return $this->_cookieValidationKey;
}
/**
* Sets the secret key used for cookie validation.
* @param string $value the secret key used for cookie validation.
*/
public function setCookieValidationKey($value)
{
$this->_cookieValidationKey = $value;
}
private $_csrfToken;
/**
@ -772,7 +819,7 @@ class Request extends \yii\base\Request
if (!$this->enableCsrfValidation) {
return;
}
$method = $this->getRequestMethod();
$method = $this->getMethod();
if ($method === 'POST' || $method === 'PUT' || $method === 'DELETE') {
$cookies = $this->getCookies();
switch ($method) {
@ -792,4 +839,3 @@ class Request extends \yii\base\Request
}
}
}

371
framework/yii/web/Response.php

@ -9,8 +9,11 @@ namespace yii\web;
use Yii;
use yii\base\HttpException;
use yii\base\InvalidParamException;
use yii\helpers\FileHelper;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\helpers\SecurityHelper;
use yii\helpers\StringHelper;
/**
@ -27,6 +30,237 @@ class Response extends \yii\base\Response
* @see redirect
*/
public $ajaxRedirectCode = 278;
/**
* @var string
*/
public $content;
/**
* @var string
*/
public $statusText;
/**
* @var string the charset to use. If not set, [[\yii\base\Application::charset]] will be used.
*/
public $charset;
/**
* @var string the version of the HTTP protocol to use
*/
public $version = '1.0';
/**
* @var array list of HTTP status codes and the corresponding texts
*/
public static $statusTexts = array(
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
118 => 'Connection timed out',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
208 => 'Already Reported',
210 => 'Content Different',
226 => 'IM Used',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Reserved',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
310 => 'Too many Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested range unsatisfiable',
417 => 'Expectation failed',
418 => 'I’m a teapot',
422 => 'Unprocessable entity',
423 => 'Locked',
424 => 'Method failure',
425 => 'Unordered Collection',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
449 => 'Retry With',
450 => 'Blocked by Windows Parental Controls',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway ou Proxy Error',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
507 => 'Insufficient storage',
508 => 'Loop Detected',
509 => 'Bandwidth Limit Exceeded',
510 => 'Not Extended',
511 => 'Network Authentication Required',
);
private $_statusCode;
/**
* @var HeaderCollection
*/
private $_headers;
public function init()
{
if ($this->charset === null) {
$this->charset = Yii::$app->charset;
}
}
public function begin()
{
parent::begin();
$this->beginOutput();
}
public function end()
{
$this->content .= $this->endOutput();
$this->send();
parent::end();
}
public function getStatusCode()
{
return $this->_statusCode;
}
public function setStatusCode($value, $text = null)
{
$this->_statusCode = (int)$value;
if ($this->isInvalid()) {
throw new InvalidParamException("The HTTP status code is invalid: $value");
}
if ($text === null) {
$this->statusText = isset(self::$statusTexts[$this->_statusCode]) ? self::$statusTexts[$this->_statusCode] : '';
} else {
$this->statusText = $text;
}
}
/**
* Returns the header collection.
* The header collection contains the currently registered HTTP headers.
* @return HeaderCollection the header collection
*/
public function getHeaders()
{
if ($this->_headers === null) {
$this->_headers = new HeaderCollection;
}
return $this->_headers;
}
public function renderJson($data)
{
$this->getHeaders()->set('content-type', 'application/json');
$this->content = Json::encode($data);
}
public function renderJsonp($data, $callbackName)
{
$this->getHeaders()->set('content-type', 'text/javascript');
$data = Json::encode($data);
$this->content = "$callbackName($data);";
}
/**
* Sends the response to the client.
* @return boolean true if the response was sent
*/
public function send()
{
$this->sendHeaders();
$this->sendContent();
}
public function reset()
{
$this->_headers = null;
$this->_statusCode = null;
$this->statusText = null;
$this->content = null;
}
/**
* Sends the response headers to the client
*/
protected function sendHeaders()
{
if (headers_sent()) {
return;
}
$statusCode = $this->getStatusCode();
if ($statusCode !== null) {
header("HTTP/{$this->version} $statusCode {$this->statusText}");
}
if ($this->_headers) {
$headers = $this->getHeaders();
foreach ($headers as $name => $values) {
foreach ($values as $value) {
header("$name: $value", false);
}
}
$headers->removeAll();
}
$this->sendCookies();
}
/**
* Sends the cookies to the client.
*/
protected function sendCookies()
{
if ($this->_cookies === null) {
return;
}
$request = Yii::$app->getRequest();
if ($request->enableCookieValidation) {
$validationKey = $request->getCookieValidationKey();
}
foreach ($this->getCookies() as $cookie) {
$value = $cookie->value;
if ($cookie->expire != 1 && isset($validationKey)) {
$value = SecurityHelper::hashData(serialize($value), $validationKey);
}
setcookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly);
}
$this->getCookies()->removeAll();
}
/**
* Sends the response content to the client
*/
protected function sendContent()
{
echo $this->content;
$this->content = null;
}
/**
* Sends a file to user.
@ -46,13 +280,15 @@ class Response extends \yii\base\Response
$contentStart = 0;
$contentEnd = $fileSize - 1;
$headers = $this->getHeaders();
// tell the client that we accept range requests
header('Accept-Ranges: bytes');
$headers->set('Accept-Ranges', 'bytes');
if (isset($_SERVER['HTTP_RANGE'])) {
// client sent us a multibyte range, can not hold this one for now
if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) {
header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
throw new HttpException(416, 'Requested Range Not Satisfiable');
}
@ -81,25 +317,26 @@ class Response extends \yii\base\Response
$wrongContentStart = ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0);
if ($wrongContentStart) {
header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
throw new HttpException(416, 'Requested Range Not Satisfiable');
}
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
$this->setStatusCode(206);
$headers->set('Content-Range', "bytes $contentStart-$contentEnd/$fileSize");
} else {
header('HTTP/1.1 200 OK');
$this->setStatusCode(200);
}
$length = $contentEnd - $contentStart + 1; // Calculate new content length
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: ' . $mimeType);
header('Content-Length: ' . $length);
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Transfer-Encoding: binary');
$headers->set('Pragma', 'public')
->set('Expires', '0')
->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->set('Content-Type', $mimeType)
->set('Content-Length', $length)
->set('Content-Disposition', "attachment; filename=\"$fileName\"")
->set('Content-Transfer-Encoding', 'binary');
$content = StringHelper::substr($content, $contentStart, $length);
if ($terminate) {
@ -108,10 +345,10 @@ class Response extends \yii\base\Response
ob_start();
Yii::$app->end(0, false);
ob_end_clean();
echo $content;
$this->content = $content;
exit(0);
} else {
echo $content;
$this->content = $content;
}
}
@ -186,7 +423,7 @@ class Response extends \yii\base\Response
}
if (!isset($options['mimeType'])) {
if (($options['mimeType'] = CFileHelper::getMimeTypeByExtension($filePath)) === null) {
if (($options['mimeType'] = FileHelper::getMimeTypeByExtension($filePath)) === null) {
$options['mimeType'] = 'text/plain';
}
}
@ -195,16 +432,18 @@ class Response extends \yii\base\Response
$options['xHeader'] = 'X-Sendfile';
}
$headers = $this->getHeaders();
if ($options['mimeType'] !== null) {
header('Content-type: ' . $options['mimeType']);
$headers->set('Content-Type', $options['mimeType']);
}
header('Content-Disposition: ' . $disposition . '; filename="' . $options['saveName'] . '"');
$headers->set('Content-Disposition', "$disposition; filename=\"{$options['saveName']}\"");
if (isset($options['addHeaders'])) {
foreach ($options['addHeaders'] as $header => $value) {
header($header . ': ' . $value);
$headers->set($header, $value);
}
}
header(trim($options['xHeader']) . ': ' . $filePath);
$headers->set(trim($options['xHeader']), $filePath);
if (!isset($options['terminate']) || $options['terminate']) {
Yii::$app->end();
@ -243,10 +482,11 @@ class Response extends \yii\base\Response
if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) {
$url = Yii::$app->getRequest()->getHostInfo() . $url;
}
if (Yii::$app->getRequest()->getIsAjaxRequest()) {
if (Yii::$app->getRequest()->getIsAjax()) {
$statusCode = $this->ajaxRedirectCode;
}
header('Location: ' . $url, true, $statusCode);
$this->getHeaders()->set('Location', $url);
$this->setStatusCode($statusCode);
if ($terminate) {
Yii::$app->end();
}
@ -265,6 +505,8 @@ class Response extends \yii\base\Response
$this->redirect(Yii::$app->getRequest()->getUrl() . $anchor, $terminate);
}
private $_cookies;
/**
* Returns the cookie collection.
* Through the returned cookie collection, you add or remove cookies as follows,
@ -286,6 +528,89 @@ class Response extends \yii\base\Response
*/
public function getCookies()
{
return Yii::$app->getRequest()->getCookies();
if ($this->_cookies === null) {
$this->_cookies = new CookieCollection;
}
return $this->_cookies;
}
/**
* @return boolean whether this response has a valid [[statusCode]].
*/
public function isInvalid()
{
return $this->getStatusCode() < 100 || $this->getStatusCode() >= 600;
}
/**
* @return boolean whether this response is informational
*/
public function isInformational()
{
return $this->getStatusCode() >= 100 && $this->getStatusCode() < 200;
}
/**
* @return boolean whether this response is successfully
*/
public function isSuccessful()
{
return $this->getStatusCode() >= 200 && $this->getStatusCode() < 300;
}
/**
* @return boolean whether this response is a redirection
*/
public function isRedirection()
{
return $this->getStatusCode() >= 300 && $this->getStatusCode() < 400;
}
/**
* @return boolean whether this response indicates a client error
*/
public function isClientError()
{
return $this->getStatusCode() >= 400 && $this->getStatusCode() < 500;
}
/**
* @return boolean whether this response indicates a server error
*/
public function isServerError()
{
return $this->getStatusCode() >= 500 && $this->getStatusCode() < 600;
}
/**
* @return boolean whether this response is OK
*/
public function isOk()
{
return 200 === $this->getStatusCode();
}
/**
* @return boolean whether this response indicates the current request is forbidden
*/
public function isForbidden()
{
return 403 === $this->getStatusCode();
}
/**
* @return boolean whether this response indicates the currently requested resource is not found
*/
public function isNotFound()
{
return 404 === $this->getStatusCode();
}
/**
* @return boolean whether this response is empty
*/
public function isEmpty()
{
return in_array($this->getStatusCode(), array(201, 204, 304));
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save