This commit is contained in:
2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329179 additions and 0 deletions

203
vendor/yiisoft/yii2/web/Application.php vendored Normal file
View File

@@ -0,0 +1,203 @@
<?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\InvalidRouteException;
use yii\helpers\Url;
/**
* Application is the base class for all web application classes.
*
* For more details and usage information on Application, see the [guide article on applications](guide:structure-applications).
*
* @property ErrorHandler $errorHandler The error handler application component. This property is read-only.
* @property string $homeUrl The homepage URL.
* @property Request $request The request component. This property is read-only.
* @property Response $response The response component. This property is read-only.
* @property Session $session The session component. This property is read-only.
* @property User $user The user component. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Application extends \yii\base\Application
{
/**
* @var string the default route of this application. Defaults to 'site'.
*/
public $defaultRoute = 'site';
/**
* @var array the configuration specifying a controller action which should handle
* all user requests. This is mainly used when the application is in maintenance mode
* and needs to handle all incoming requests via a single action.
* The configuration is an array whose first element specifies the route of the action.
* The rest of the array elements (key-value pairs) specify the parameters to be bound
* to the action. For example,
*
* ```php
* [
* 'offline/notice',
* 'param1' => 'value1',
* 'param2' => 'value2',
* ]
* ```
*
* Defaults to null, meaning catch-all is not used.
*/
public $catchAll;
/**
* @var Controller the currently active controller instance
*/
public $controller;
/**
* {@inheritdoc}
*/
protected function bootstrap()
{
$request = $this->getRequest();
Yii::setAlias('@webroot', dirname($request->getScriptFile()));
Yii::setAlias('@web', $request->getBaseUrl());
parent::bootstrap();
}
/**
* Handles the specified request.
* @param Request $request the request to be handled
* @return Response the resulting response
* @throws NotFoundHttpException if the requested route is invalid
*/
public function handleRequest($request)
{
if (empty($this->catchAll)) {
try {
list($route, $params) = $request->resolve();
} catch (UrlNormalizerRedirectException $e) {
$url = $e->url;
if (is_array($url)) {
if (isset($url[0])) {
// ensure the route is absolute
$url[0] = '/' . ltrim($url[0], '/');
}
$url += $request->getQueryParams();
}
return $this->getResponse()->redirect(Url::to($url, $e->scheme), $e->statusCode);
}
} else {
$route = $this->catchAll[0];
$params = $this->catchAll;
unset($params[0]);
}
try {
Yii::debug("Route requested: '$route'", __METHOD__);
$this->requestedRoute = $route;
$result = $this->runAction($route, $params);
if ($result instanceof Response) {
return $result;
}
$response = $this->getResponse();
if ($result !== null) {
$response->data = $result;
}
return $response;
} catch (InvalidRouteException $e) {
throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'), $e->getCode(), $e);
}
}
private $_homeUrl;
/**
* @return string the homepage URL
*/
public function getHomeUrl()
{
if ($this->_homeUrl === null) {
if ($this->getUrlManager()->showScriptName) {
return $this->getRequest()->getScriptUrl();
}
return $this->getRequest()->getBaseUrl() . '/';
}
return $this->_homeUrl;
}
/**
* @param string $value the homepage URL
*/
public function setHomeUrl($value)
{
$this->_homeUrl = $value;
}
/**
* Returns the error handler component.
* @return ErrorHandler the error handler application component.
*/
public function getErrorHandler()
{
return $this->get('errorHandler');
}
/**
* Returns the request component.
* @return Request the request component.
*/
public function getRequest()
{
return $this->get('request');
}
/**
* Returns the response component.
* @return Response the response component.
*/
public function getResponse()
{
return $this->get('response');
}
/**
* Returns the session component.
* @return Session the session component.
*/
public function getSession()
{
return $this->get('session');
}
/**
* Returns the user component.
* @return User the user component.
*/
public function getUser()
{
return $this->get('user');
}
/**
* {@inheritdoc}
*/
public function coreComponents()
{
return array_merge(parent::coreComponents(), [
'request' => ['class' => 'yii\web\Request'],
'response' => ['class' => 'yii\web\Response'],
'session' => ['class' => 'yii\web\Session'],
'user' => ['class' => 'yii\web\User'],
'errorHandler' => ['class' => 'yii\web\ErrorHandler'],
]);
}
}

215
vendor/yiisoft/yii2/web/AssetBundle.php vendored Normal file
View File

@@ -0,0 +1,215 @@
<?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\BaseObject;
use yii\helpers\ArrayHelper;
use yii\helpers\Url;
/**
* AssetBundle represents a collection of asset files, such as CSS, JS, images.
*
* Each asset bundle has a unique name that globally identifies it among all asset bundles used in an application.
* The name is the [fully qualified class name](http://php.net/manual/en/language.namespaces.rules.php)
* of the class representing it.
*
* An asset bundle can depend on other asset bundles. When registering an asset bundle
* with a view, all its dependent asset bundles will be automatically registered.
*
* For more details and usage information on AssetBundle, see the [guide article on assets](guide:structure-assets).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class AssetBundle extends BaseObject
{
/**
* @var string the directory that contains the source asset files for this asset bundle.
* A source asset file is a file that is part of your source code repository of your Web application.
*
* You must set this property if the directory containing the source asset files is not Web accessible.
* By setting this property, [[AssetManager]] will publish the source asset files
* to a Web-accessible directory automatically when the asset bundle is registered on a page.
*
* If you do not set this property, it means the source asset files are located under [[basePath]].
*
* You can use either a directory or an alias of the directory.
* @see $publishOptions
*/
public $sourcePath;
/**
* @var string the Web-accessible directory that contains the asset files in this bundle.
*
* If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]]
* when it publishes the asset files from [[sourcePath]].
*
* You can use either a directory or an alias of the directory.
*/
public $basePath;
/**
* @var string the base URL for the relative asset files listed in [[js]] and [[css]].
*
* If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]]
* when it publishes the asset files from [[sourcePath]].
*
* You can use either a URL or an alias of the URL.
*/
public $baseUrl;
/**
* @var array list of bundle class names that this bundle depends on.
*
* For example:
*
* ```php
* public $depends = [
* 'yii\web\YiiAsset',
* 'yii\bootstrap\BootstrapAsset',
* ];
* ```
*/
public $depends = [];
/**
* @var array list of JavaScript files that this bundle contains. Each JavaScript file can be
* specified in one of the following formats:
*
* - an absolute URL representing an external asset. For example,
* `http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` or
* `//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* - a relative path representing a local asset (e.g. `js/main.js`). The actual file path of a local
* asset can be determined by prefixing [[basePath]] to the relative path, and the actual URL
* of the asset can be determined by prefixing [[baseUrl]] to the relative path.
* - an array, with the first entry being the URL or relative path as described before, and a list of key => value pairs
* that will be used to overwrite [[jsOptions]] settings for this entry.
* This functionality is available since version 2.0.7.
*
* Note that only a forward slash "/" should be used as directory separator.
*/
public $js = [];
/**
* @var array list of CSS files that this bundle contains. Each CSS file can be specified
* in one of the three formats as explained in [[js]].
*
* Note that only a forward slash "/" should be used as directory separator.
*/
public $css = [];
/**
* @var array the options that will be passed to [[View::registerJsFile()]]
* when registering the JS files in this bundle.
*/
public $jsOptions = [];
/**
* @var array the options that will be passed to [[View::registerCssFile()]]
* when registering the CSS files in this bundle.
*/
public $cssOptions = [];
/**
* @var array the options to be passed to [[AssetManager::publish()]] when the asset bundle
* is being published. This property is used only when [[sourcePath]] is set.
*/
public $publishOptions = [];
/**
* Registers this asset bundle with a view.
* @param View $view the view to be registered with
* @return static the registered asset bundle instance
*/
public static function register($view)
{
return $view->registerAssetBundle(get_called_class());
}
/**
* Initializes the bundle.
* If you override this method, make sure you call the parent implementation in the last.
*/
public function init()
{
if ($this->sourcePath !== null) {
$this->sourcePath = rtrim(Yii::getAlias($this->sourcePath), '/\\');
}
if ($this->basePath !== null) {
$this->basePath = rtrim(Yii::getAlias($this->basePath), '/\\');
}
if ($this->baseUrl !== null) {
$this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
}
}
/**
* Registers the CSS and JS files with the given view.
* @param \yii\web\View $view the view that the asset files are to be registered with.
*/
public function registerAssetFiles($view)
{
$manager = $view->getAssetManager();
foreach ($this->js as $js) {
if (is_array($js)) {
$file = array_shift($js);
$options = ArrayHelper::merge($this->jsOptions, $js);
$view->registerJsFile($manager->getAssetUrl($this, $file), $options);
} else {
if ($js !== null) {
$view->registerJsFile($manager->getAssetUrl($this, $js), $this->jsOptions);
}
}
}
foreach ($this->css as $css) {
if (is_array($css)) {
$file = array_shift($css);
$options = ArrayHelper::merge($this->cssOptions, $css);
$view->registerCssFile($manager->getAssetUrl($this, $file), $options);
} else {
if ($css !== null) {
$view->registerCssFile($manager->getAssetUrl($this, $css), $this->cssOptions);
}
}
}
}
/**
* Publishes the asset bundle if its source code is not under Web-accessible directory.
* It will also try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding
* CSS or JS files using [[AssetManager::converter|asset converter]].
* @param AssetManager $am the asset manager to perform the asset publishing
*/
public function publish($am)
{
if ($this->sourcePath !== null && !isset($this->basePath, $this->baseUrl)) {
list($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions);
}
if (isset($this->basePath, $this->baseUrl) && ($converter = $am->getConverter()) !== null) {
foreach ($this->js as $i => $js) {
if (is_array($js)) {
$file = array_shift($js);
if (Url::isRelative($file)) {
$js = ArrayHelper::merge($this->jsOptions, $js);
array_unshift($js, $converter->convert($file, $this->basePath));
$this->js[$i] = $js;
}
} elseif (Url::isRelative($js)) {
$this->js[$i] = $converter->convert($js, $this->basePath);
}
}
foreach ($this->css as $i => $css) {
if (is_array($css)) {
$file = array_shift($css);
if (Url::isRelative($file)) {
$css = ArrayHelper::merge($this->cssOptions, $css);
array_unshift($css, $converter->convert($file, $this->basePath));
$this->css[$i] = $css;
}
} elseif (Url::isRelative($css)) {
$this->css[$i] = $converter->convert($css, $this->basePath);
}
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?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\Component;
use yii\base\Exception;
/**
* AssetConverter supports conversion of several popular script formats into JS or CSS scripts.
*
* It is used by [[AssetManager]] to convert files after they have been published.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class AssetConverter extends Component implements AssetConverterInterface
{
/**
* @var array the commands that are used to perform the asset conversion.
* The keys are the asset file extension names, and the values are the corresponding
* target script types (either "css" or "js") and the commands used for the conversion.
*
* You may also use a [path alias](guide:concept-aliases) to specify the location of the command:
*
* ```php
* [
* 'styl' => ['css', '@app/node_modules/bin/stylus < {from} > {to}'],
* ]
* ```
*/
public $commands = [
'less' => ['css', 'lessc {from} {to} --no-color --source-map'],
'scss' => ['css', 'sass {from} {to} --sourcemap'],
'sass' => ['css', 'sass {from} {to} --sourcemap'],
'styl' => ['css', 'stylus < {from} > {to}'],
'coffee' => ['js', 'coffee -p {from} > {to}'],
'ts' => ['js', 'tsc --out {to} {from}'],
];
/**
* @var bool whether the source asset file should be converted even if its result already exists.
* You may want to set this to be `true` during the development stage to make sure the converted
* assets are always up-to-date. Do not set this to true on production servers as it will
* significantly degrade the performance.
*/
public $forceConvert = false;
/**
* Converts a given asset file into a CSS or JS file.
* @param string $asset the asset file path, relative to $basePath
* @param string $basePath the directory the $asset is relative to.
* @return string the converted asset file path, relative to $basePath.
*/
public function convert($asset, $basePath)
{
$pos = strrpos($asset, '.');
if ($pos !== false) {
$ext = substr($asset, $pos + 1);
if (isset($this->commands[$ext])) {
list($ext, $command) = $this->commands[$ext];
$result = substr($asset, 0, $pos + 1) . $ext;
if ($this->forceConvert || @filemtime("$basePath/$result") < @filemtime("$basePath/$asset")) {
$this->runCommand($command, $basePath, $asset, $result);
}
return $result;
}
}
return $asset;
}
/**
* Runs a command to convert asset files.
* @param string $command the command to run. If prefixed with an `@` it will be treated as a [path alias](guide:concept-aliases).
* @param string $basePath asset base path and command working directory
* @param string $asset the name of the asset file
* @param string $result the name of the file to be generated by the converter command
* @return bool true on success, false on failure. Failures will be logged.
* @throws \yii\base\Exception when the command fails and YII_DEBUG is true.
* In production mode the error will be logged.
*/
protected function runCommand($command, $basePath, $asset, $result)
{
$command = Yii::getAlias($command);
$command = strtr($command, [
'{from}' => escapeshellarg("$basePath/$asset"),
'{to}' => escapeshellarg("$basePath/$result"),
]);
$descriptor = [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$pipes = [];
$proc = proc_open($command, $descriptor, $pipes, $basePath);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$status = proc_close($proc);
if ($status === 0) {
Yii::debug("Converted $asset into $result:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr", __METHOD__);
} elseif (YII_DEBUG) {
throw new Exception("AssetConverter command '$command' failed with exit code $status:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr");
} else {
Yii::error("AssetConverter command '$command' failed with exit code $status:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr", __METHOD__);
}
return $status === 0;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* The AssetConverterInterface must be implemented by asset converter classes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface AssetConverterInterface
{
/**
* Converts a given asset file into a CSS or JS file.
* @param string $asset the asset file path, relative to $basePath
* @param string $basePath the directory the $asset is relative to.
* @return string the converted asset file path, relative to $basePath.
*/
public function convert($asset, $basePath);
}

621
vendor/yiisoft/yii2/web/AssetManager.php vendored Normal file
View File

@@ -0,0 +1,621 @@
<?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\Component;
use yii\base\InvalidArgumentException;
use yii\base\InvalidConfigException;
use yii\helpers\FileHelper;
use yii\helpers\Url;
/**
* AssetManager manages asset bundle configuration and loading.
*
* AssetManager is configured as an application component in [[\yii\web\Application]] by default.
* You can access that instance via `Yii::$app->assetManager`.
*
* You can modify its configuration by adding an array to your application config under `components`
* as shown in the following example:
*
* ```php
* 'assetManager' => [
* 'bundles' => [
* // you can override AssetBundle configs here
* ],
* ]
* ```
*
* For more details and usage information on AssetManager, see the [guide article on assets](guide:structure-assets).
*
* @property AssetConverterInterface $converter The asset converter. Note that the type of this property
* differs in getter and setter. See [[getConverter()]] and [[setConverter()]] for details.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class AssetManager extends Component
{
/**
* @var array|bool list of asset bundle configurations. This property is provided to customize asset bundles.
* When a bundle is being loaded by [[getBundle()]], if it has a corresponding configuration specified here,
* the configuration will be applied to the bundle.
*
* The array keys are the asset bundle names, which typically are asset bundle class names without leading backslash.
* The array values are the corresponding configurations. If a value is false, it means the corresponding asset
* bundle is disabled and [[getBundle()]] should return null.
*
* If this property is false, it means the whole asset bundle feature is disabled and [[getBundle()]]
* will always return null.
*
* The following example shows how to disable the bootstrap css file used by Bootstrap widgets
* (because you want to use your own styles):
*
* ```php
* [
* 'yii\bootstrap\BootstrapAsset' => [
* 'css' => [],
* ],
* ]
* ```
*/
public $bundles = [];
/**
* @var string the root directory storing the published asset files.
*/
public $basePath = '@webroot/assets';
/**
* @var string the base URL through which the published asset files can be accessed.
*/
public $baseUrl = '@web/assets';
/**
* @var array mapping from source asset files (keys) to target asset files (values).
*
* This property is provided to support fixing incorrect asset file paths in some asset bundles.
* When an asset bundle is registered with a view, each relative asset file in its [[AssetBundle::css|css]]
* and [[AssetBundle::js|js]] arrays will be examined against this map. If any of the keys is found
* to be the last part of an asset file (which is prefixed with [[AssetBundle::sourcePath]] if available),
* the corresponding value will replace the asset and be registered with the view.
* For example, an asset file `my/path/to/jquery.js` matches a key `jquery.js`.
*
* Note that the target asset files should be absolute URLs, domain relative URLs (starting from '/') or paths
* relative to [[baseUrl]] and [[basePath]].
*
* In the following example, any assets ending with `jquery.min.js` will be replaced with `jquery/dist/jquery.js`
* which is relative to [[baseUrl]] and [[basePath]].
*
* ```php
* [
* 'jquery.min.js' => 'jquery/dist/jquery.js',
* ]
* ```
*
* You may also use aliases while specifying map value, for example:
*
* ```php
* [
* 'jquery.min.js' => '@web/js/jquery/jquery.js',
* ]
* ```
*/
public $assetMap = [];
/**
* @var bool whether to use symbolic link to publish asset files. Defaults to false, meaning
* asset files are copied to [[basePath]]. Using symbolic links has the benefit that the published
* assets will always be consistent with the source assets and there is no copy operation required.
* This is especially useful during development.
*
* However, there are special requirements for hosting environments in order to use symbolic links.
* In particular, symbolic links are supported only on Linux/Unix, and Windows Vista/2008 or greater.
*
* Moreover, some Web servers need to be properly configured so that the linked assets are accessible
* to Web users. For example, for Apache Web server, the following configuration directive should be added
* for the Web folder:
*
* ```apache
* Options FollowSymLinks
* ```
*/
public $linkAssets = false;
/**
* @var int the permission to be set for newly published asset files.
* This value will be used by PHP chmod() function. No umask will be applied.
* If not set, the permission will be determined by the current environment.
*/
public $fileMode;
/**
* @var int the permission to be set for newly generated asset directories.
* This value will be used by PHP chmod() function. No umask will be applied.
* Defaults to 0775, meaning the directory is read-writable by owner and group,
* but read-only for other users.
*/
public $dirMode = 0775;
/**
* @var callback a PHP callback that is called before copying each sub-directory or file.
* This option is used only when publishing a directory. If the callback returns false, the copy
* operation for the sub-directory or file will be cancelled.
*
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file to be copied from, while `$to` is the copy target.
*
* This is passed as a parameter `beforeCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
*/
public $beforeCopy;
/**
* @var callback a PHP callback that is called after a sub-directory or file is successfully copied.
* This option is used only when publishing a directory. The signature of the callback is the same as
* for [[beforeCopy]].
* This is passed as a parameter `afterCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
*/
public $afterCopy;
/**
* @var bool whether the directory being published should be copied even if
* it is found in the target directory. This option is used only when publishing a directory.
* You may want to set this to be `true` during the development stage to make sure the published
* directory is always up-to-date. Do not set this to true on production servers as it will
* significantly degrade the performance.
*/
public $forceCopy = false;
/**
* @var bool whether to append a timestamp to the URL of every published asset. When this is true,
* the URL of a published asset may look like `/path/to/asset?v=timestamp`, where `timestamp` is the
* last modification time of the published asset file.
* You normally would want to set this property to true when you have enabled HTTP caching for assets,
* because it allows you to bust caching when the assets are updated.
* @since 2.0.3
*/
public $appendTimestamp = false;
/**
* @var callable a callback that will be called to produce hash for asset directory generation.
* The signature of the callback should be as follows:
*
* ```
* function ($path)
* ```
*
* where `$path` is the asset path. Note that the `$path` can be either directory where the asset
* files reside or a single file. For a CSS file that uses relative path in `url()`, the hash
* implementation should use the directory path of the file instead of the file path to include
* the relative asset files in the copying.
*
* If this is not set, the asset manager will use the default CRC32 and filemtime in the `hash`
* method.
*
* Example of an implementation using MD4 hash:
*
* ```php
* function ($path) {
* return hash('md4', $path);
* }
* ```
*
* @since 2.0.6
*/
public $hashCallback;
private $_dummyBundles = [];
/**
* Initializes the component.
* @throws InvalidConfigException if [[basePath]] is invalid
*/
public function init()
{
parent::init();
$this->basePath = Yii::getAlias($this->basePath);
if (!is_dir($this->basePath)) {
throw new InvalidConfigException("The directory does not exist: {$this->basePath}");
} elseif (!is_writable($this->basePath)) {
throw new InvalidConfigException("The directory is not writable by the Web process: {$this->basePath}");
}
$this->basePath = realpath($this->basePath);
$this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
}
/**
* Returns the named asset bundle.
*
* This method will first look for the bundle in [[bundles]]. If not found,
* it will treat `$name` as the class of the asset bundle and create a new instance of it.
*
* @param string $name the class name of the asset bundle (without the leading backslash)
* @param bool $publish whether to publish the asset files in the asset bundle before it is returned.
* If you set this false, you must manually call `AssetBundle::publish()` to publish the asset files.
* @return AssetBundle the asset bundle instance
* @throws InvalidConfigException if $name does not refer to a valid asset bundle
*/
public function getBundle($name, $publish = true)
{
if ($this->bundles === false) {
return $this->loadDummyBundle($name);
} elseif (!isset($this->bundles[$name])) {
return $this->bundles[$name] = $this->loadBundle($name, [], $publish);
} elseif ($this->bundles[$name] instanceof AssetBundle) {
return $this->bundles[$name];
} elseif (is_array($this->bundles[$name])) {
return $this->bundles[$name] = $this->loadBundle($name, $this->bundles[$name], $publish);
} elseif ($this->bundles[$name] === false) {
return $this->loadDummyBundle($name);
}
throw new InvalidConfigException("Invalid asset bundle configuration: $name");
}
/**
* Loads asset bundle class by name.
*
* @param string $name bundle name
* @param array $config bundle object configuration
* @param bool $publish if bundle should be published
* @return AssetBundle
* @throws InvalidConfigException if configuration isn't valid
*/
protected function loadBundle($name, $config = [], $publish = true)
{
if (!isset($config['class'])) {
$config['class'] = $name;
}
/* @var $bundle AssetBundle */
$bundle = Yii::createObject($config);
if ($publish) {
$bundle->publish($this);
}
return $bundle;
}
/**
* Loads dummy bundle by name.
*
* @param string $name
* @return AssetBundle
*/
protected function loadDummyBundle($name)
{
if (!isset($this->_dummyBundles[$name])) {
$this->_dummyBundles[$name] = $this->loadBundle($name, [
'sourcePath' => null,
'js' => [],
'css' => [],
'depends' => [],
]);
}
return $this->_dummyBundles[$name];
}
/**
* Returns the actual URL for the specified asset.
* The actual URL is obtained by prepending either [[AssetBundle::$baseUrl]] or [[AssetManager::$baseUrl]] to the given asset path.
* @param AssetBundle $bundle the asset bundle which the asset file belongs to
* @param string $asset the asset path. This should be one of the assets listed in [[AssetBundle::$js]] or [[AssetBundle::$css]].
* @return string the actual URL for the specified asset.
*/
public function getAssetUrl($bundle, $asset)
{
if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
if (strncmp($actualAsset, '@web/', 5) === 0) {
$asset = substr($actualAsset, 5);
$basePath = Yii::getAlias('@webroot');
$baseUrl = Yii::getAlias('@web');
} else {
$asset = Yii::getAlias($actualAsset);
$basePath = $this->basePath;
$baseUrl = $this->baseUrl;
}
} else {
$basePath = $bundle->basePath;
$baseUrl = $bundle->baseUrl;
}
if (!Url::isRelative($asset) || strncmp($asset, '/', 1) === 0) {
return $asset;
}
if ($this->appendTimestamp && ($timestamp = @filemtime("$basePath/$asset")) > 0) {
return "$baseUrl/$asset?v=$timestamp";
}
return "$baseUrl/$asset";
}
/**
* Returns the actual file path for the specified asset.
* @param AssetBundle $bundle the asset bundle which the asset file belongs to
* @param string $asset the asset path. This should be one of the assets listed in [[AssetBundle::$js]] or [[AssetBundle::$css]].
* @return string|false the actual file path, or `false` if the asset is specified as an absolute URL
*/
public function getAssetPath($bundle, $asset)
{
if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
return Url::isRelative($actualAsset) ? $this->basePath . '/' . $actualAsset : false;
}
return Url::isRelative($asset) ? $bundle->basePath . '/' . $asset : false;
}
/**
* @param AssetBundle $bundle
* @param string $asset
* @return string|bool
*/
protected function resolveAsset($bundle, $asset)
{
if (isset($this->assetMap[$asset])) {
return $this->assetMap[$asset];
}
if ($bundle->sourcePath !== null && Url::isRelative($asset)) {
$asset = $bundle->sourcePath . '/' . $asset;
}
$n = mb_strlen($asset, Yii::$app->charset);
foreach ($this->assetMap as $from => $to) {
$n2 = mb_strlen($from, Yii::$app->charset);
if ($n2 <= $n && substr_compare($asset, $from, $n - $n2, $n2) === 0) {
return $to;
}
}
return false;
}
private $_converter;
/**
* Returns the asset converter.
* @return AssetConverterInterface the asset converter.
*/
public function getConverter()
{
if ($this->_converter === null) {
$this->_converter = Yii::createObject(AssetConverter::className());
} elseif (is_array($this->_converter) || is_string($this->_converter)) {
if (is_array($this->_converter) && !isset($this->_converter['class'])) {
$this->_converter['class'] = AssetConverter::className();
}
$this->_converter = Yii::createObject($this->_converter);
}
return $this->_converter;
}
/**
* Sets the asset converter.
* @param array|AssetConverterInterface $value the asset converter. This can be either
* an object implementing the [[AssetConverterInterface]], or a configuration
* array that can be used to create the asset converter object.
*/
public function setConverter($value)
{
$this->_converter = $value;
}
/**
* @var array published assets
*/
private $_published = [];
/**
* Publishes a file or a directory.
*
* This method will copy the specified file or directory to [[basePath]] so that
* it can be accessed via the Web server.
*
* If the asset is a file, its file modification time will be checked to avoid
* unnecessary file copying.
*
* If the asset is a directory, all files and subdirectories under it will be published recursively.
* Note, in case $forceCopy is false the method only checks the existence of the target
* directory to avoid repetitive copying (which is very expensive).
*
* By default, when publishing a directory, subdirectories and files whose name starts with a dot "."
* will NOT be published. If you want to change this behavior, you may specify the "beforeCopy" option
* as explained in the `$options` parameter.
*
* Note: On rare scenario, a race condition can develop that will lead to a
* one-time-manifestation of a non-critical problem in the creation of the directory
* that holds the published assets. This problem can be avoided altogether by 'requesting'
* in advance all the resources that are supposed to trigger a 'publish()' call, and doing
* that in the application deployment phase, before system goes live. See more in the following
* discussion: http://code.google.com/p/yii/issues/detail?id=2579
*
* @param string $path the asset (file or directory) to be published
* @param array $options the options to be applied when publishing a directory.
* The following options are supported:
*
* - only: array, list of patterns that the file paths should match if they want to be copied.
* - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied.
* - caseSensitive: boolean, whether patterns specified at "only" or "except" should be case sensitive. Defaults to true.
* - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
* This overrides [[beforeCopy]] if set.
* - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
* This overrides [[afterCopy]] if set.
* - forceCopy: boolean, whether the directory being published should be copied even if
* it is found in the target directory. This option is used only when publishing a directory.
* This overrides [[forceCopy]] if set.
*
* @return array the path (directory or file path) and the URL that the asset is published as.
* @throws InvalidArgumentException if the asset to be published does not exist.
*/
public function publish($path, $options = [])
{
$path = Yii::getAlias($path);
if (isset($this->_published[$path])) {
return $this->_published[$path];
}
if (!is_string($path) || ($src = realpath($path)) === false) {
throw new InvalidArgumentException("The file or directory to be published does not exist: $path");
}
if (is_file($src)) {
return $this->_published[$path] = $this->publishFile($src);
}
return $this->_published[$path] = $this->publishDirectory($src, $options);
}
/**
* Publishes a file.
* @param string $src the asset file to be published
* @return string[] the path and the URL that the asset is published as.
* @throws InvalidArgumentException if the asset to be published does not exist.
*/
protected function publishFile($src)
{
$dir = $this->hash($src);
$fileName = basename($src);
$dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
$dstFile = $dstDir . DIRECTORY_SEPARATOR . $fileName;
if (!is_dir($dstDir)) {
FileHelper::createDirectory($dstDir, $this->dirMode, true);
}
if ($this->linkAssets) {
if (!is_file($dstFile)) {
try { // fix #6226 symlinking multi threaded
symlink($src, $dstFile);
} catch (\Exception $e) {
if (!is_file($dstFile)) {
throw $e;
}
}
}
} elseif (@filemtime($dstFile) < @filemtime($src)) {
copy($src, $dstFile);
if ($this->fileMode !== null) {
@chmod($dstFile, $this->fileMode);
}
}
return [$dstFile, $this->baseUrl . "/$dir/$fileName"];
}
/**
* Publishes a directory.
* @param string $src the asset directory to be published
* @param array $options the options to be applied when publishing a directory.
* The following options are supported:
*
* - only: array, list of patterns that the file paths should match if they want to be copied.
* - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied.
* - caseSensitive: boolean, whether patterns specified at "only" or "except" should be case sensitive. Defaults to true.
* - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
* This overrides [[beforeCopy]] if set.
* - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
* This overrides [[afterCopy]] if set.
* - forceCopy: boolean, whether the directory being published should be copied even if
* it is found in the target directory. This option is used only when publishing a directory.
* This overrides [[forceCopy]] if set.
*
* @return string[] the path directory and the URL that the asset is published as.
* @throws InvalidArgumentException if the asset to be published does not exist.
*/
protected function publishDirectory($src, $options)
{
$dir = $this->hash($src);
$dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
if ($this->linkAssets) {
if (!is_dir($dstDir)) {
FileHelper::createDirectory(dirname($dstDir), $this->dirMode, true);
try { // fix #6226 symlinking multi threaded
symlink($src, $dstDir);
} catch (\Exception $e) {
if (!is_dir($dstDir)) {
throw $e;
}
}
}
} elseif (!empty($options['forceCopy']) || ($this->forceCopy && !isset($options['forceCopy'])) || !is_dir($dstDir)) {
$opts = array_merge(
$options,
[
'dirMode' => $this->dirMode,
'fileMode' => $this->fileMode,
'copyEmptyDirectories' => false,
]
);
if (!isset($opts['beforeCopy'])) {
if ($this->beforeCopy !== null) {
$opts['beforeCopy'] = $this->beforeCopy;
} else {
$opts['beforeCopy'] = function ($from, $to) {
return strncmp(basename($from), '.', 1) !== 0;
};
}
}
if (!isset($opts['afterCopy']) && $this->afterCopy !== null) {
$opts['afterCopy'] = $this->afterCopy;
}
FileHelper::copyDirectory($src, $dstDir, $opts);
}
return [$dstDir, $this->baseUrl . '/' . $dir];
}
/**
* Returns the published path of a file path.
* This method does not perform any publishing. It merely tells you
* if the file or directory is published, where it will go.
* @param string $path directory or file path being published
* @return string|false string the published file path. False if the file or directory does not exist
*/
public function getPublishedPath($path)
{
$path = Yii::getAlias($path);
if (isset($this->_published[$path])) {
return $this->_published[$path][0];
}
if (is_string($path) && ($path = realpath($path)) !== false) {
return $this->basePath . DIRECTORY_SEPARATOR . $this->hash($path) . (is_file($path) ? DIRECTORY_SEPARATOR . basename($path) : '');
}
return false;
}
/**
* Returns the URL of a published file path.
* This method does not perform any publishing. It merely tells you
* if the file path is published, what the URL will be to access it.
* @param string $path directory or file path being published
* @return string|false string the published URL for the file or directory. False if the file or directory does not exist.
*/
public function getPublishedUrl($path)
{
$path = Yii::getAlias($path);
if (isset($this->_published[$path])) {
return $this->_published[$path][1];
}
if (is_string($path) && ($path = realpath($path)) !== false) {
return $this->baseUrl . '/' . $this->hash($path) . (is_file($path) ? '/' . basename($path) : '');
}
return false;
}
/**
* Generate a CRC32 hash for the directory path. Collisions are higher
* than MD5 but generates a much smaller hash string.
* @param string $path string to be hashed.
* @return string hashed string.
*/
protected function hash($path)
{
if (is_callable($this->hashCallback)) {
return call_user_func($this->hashCallback, $path);
}
$path = (is_file($path) ? dirname($path) : $path) . filemtime($path);
return sprintf('%x', crc32($path . Yii::getVersion() . '|' . $this->linkAssets));
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* BadRequestHttpException represents a "Bad Request" HTTP exception with status code 400.
*
* Use this exception to represent a generic client error. In many cases, there
* may be an HTTP exception that more precisely describes the error. In that
* case, consider using the more precise exception to provide the user with
* additional information.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.1
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class BadRequestHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(400, $message, $code, $previous);
}
}

122
vendor/yiisoft/yii2/web/CacheSession.php vendored Normal file
View File

@@ -0,0 +1,122 @@
<?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\caching\CacheInterface;
use yii\di\Instance;
/**
* CacheSession implements a session component using cache as storage medium.
*
* The cache being used can be any cache application component.
* The ID of the cache application component is specified via [[cache]], which defaults to 'cache'.
*
* Beware, by definition cache storage are volatile, which means the data stored on them
* may be swapped out and get lost. Therefore, you must make sure the cache used by this component
* is NOT volatile. If you want to use database as storage medium, [[DbSession]] is a better choice.
*
* The following example shows how you can configure the application to use CacheSession:
* Add the following to your application config under `components`:
*
* ```php
* 'session' => [
* 'class' => 'yii\web\CacheSession',
* // 'cache' => 'mycache',
* ]
* ```
*
* @property bool $useCustomStorage Whether to use custom storage. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class CacheSession extends Session
{
/**
* @var CacheInterface|array|string the cache object or the application component ID of the cache object.
* The session data will be stored using this cache object.
*
* After the CacheSession object is created, if you want to change this property,
* you should only assign it with a cache object.
*
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
*/
public $cache = 'cache';
/**
* Initializes the application component.
*/
public function init()
{
parent::init();
$this->cache = Instance::ensure($this->cache, 'yii\caching\CacheInterface');
}
/**
* Returns a value indicating whether to use custom session storage.
* This method overrides the parent implementation and always returns true.
* @return bool whether to use custom storage.
*/
public function getUseCustomStorage()
{
return true;
}
/**
* Session read handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return string the session data
*/
public function readSession($id)
{
$data = $this->cache->get($this->calculateKey($id));
return $data === false ? '' : $data;
}
/**
* Session write handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @param string $data session data
* @return bool whether session write is successful
*/
public function writeSession($id, $data)
{
return $this->cache->set($this->calculateKey($id), $data, $this->getTimeout());
}
/**
* Session destroy handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return bool whether session is destroyed successfully
*/
public function destroySession($id)
{
$cacheId = $this->calculateKey($id);
if ($this->cache->exists($cacheId) === false) {
return true;
}
return $this->cache->delete($cacheId);
}
/**
* Generates a unique key used for storing session data in cache.
* @param string $id session variable name
* @return mixed a safe cache key associated with the session variable name
*/
protected function calculateKey($id)
{
return [__CLASS__, $id];
}
}

View File

@@ -0,0 +1,143 @@
<?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\BaseObject;
/**
* CompositeUrlRule is the base class for URL rule classes that consist of multiple simpler rules.
*
* @property null|int $createUrlStatus Status of the URL creation after the last [[createUrl()]] call. `null`
* if rule does not provide info about create status. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class CompositeUrlRule extends BaseObject implements UrlRuleInterface
{
/**
* @var UrlRuleInterface[] the URL rules contained in this composite rule.
* This property is set in [[init()]] by the return value of [[createRules()]].
*/
protected $rules = [];
/**
* @var int|null status of the URL creation after the last [[createUrl()]] call.
* @since 2.0.12
*/
protected $createStatus;
/**
* Creates the URL rules that should be contained within this composite rule.
* @return UrlRuleInterface[] the URL rules
*/
abstract protected function createRules();
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
$this->rules = $this->createRules();
}
/**
* {@inheritdoc}
*/
public function parseRequest($manager, $request)
{
foreach ($this->rules as $rule) {
/* @var $rule UrlRule */
$result = $rule->parseRequest($manager, $request);
if (YII_DEBUG) {
Yii::debug([
'rule' => method_exists($rule, '__toString') ? $rule->__toString() : get_class($rule),
'match' => $result !== false,
'parent' => self::className(),
], __METHOD__);
}
if ($result !== false) {
return $result;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function createUrl($manager, $route, $params)
{
$this->createStatus = UrlRule::CREATE_STATUS_SUCCESS;
$url = $this->iterateRules($this->rules, $manager, $route, $params);
if ($url !== false) {
return $url;
}
if ($this->createStatus === UrlRule::CREATE_STATUS_SUCCESS) {
// create status was not changed - there is no rules configured
$this->createStatus = UrlRule::CREATE_STATUS_PARSING_ONLY;
}
return false;
}
/**
* Iterates through specified rules and calls [[createUrl()]] for each of them.
*
* @param UrlRuleInterface[] $rules rules to iterate.
* @param UrlManager $manager the URL manager
* @param string $route the route. It should not have slashes at the beginning or the end.
* @param array $params the parameters
* @return bool|string the created URL, or `false` if none of specified rules cannot be used for creating this URL.
* @see createUrl()
* @since 2.0.12
*/
protected function iterateRules($rules, $manager, $route, $params)
{
/* @var $rule UrlRule */
foreach ($rules as $rule) {
$url = $rule->createUrl($manager, $route, $params);
if ($url !== false) {
$this->createStatus = UrlRule::CREATE_STATUS_SUCCESS;
return $url;
}
if (
$this->createStatus === null
|| !method_exists($rule, 'getCreateUrlStatus')
|| $rule->getCreateUrlStatus() === null
) {
$this->createStatus = null;
} else {
$this->createStatus |= $rule->getCreateUrlStatus();
}
}
return false;
}
/**
* Returns status of the URL creation after the last [[createUrl()]] call.
*
* For multiple rules statuses will be combined by bitwise `or` operator
* (e.g. `UrlRule::CREATE_STATUS_PARSING_ONLY | UrlRule::CREATE_STATUS_PARAMS_MISMATCH`).
*
* @return null|int Status of the URL creation after the last [[createUrl()]] call. `null` if rule does not provide
* info about create status.
* @see $createStatus
* @see http://php.net/manual/en/language.operators.bitwise.php
* @since 2.0.12
*/
public function getCreateUrlStatus()
{
return $this->createStatus;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* ConflictHttpException represents a "Conflict" HTTP exception with status code 409.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.8
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class ConflictHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(409, $message, $code, $previous);
}
}

265
vendor/yiisoft/yii2/web/Controller.php vendored Normal file
View File

@@ -0,0 +1,265 @@
<?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\InlineAction;
use yii\helpers\Url;
/**
* Controller is the base class of web controllers.
*
* For more details and usage information on Controller, see the [guide article on controllers](guide:structure-controllers).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Controller extends \yii\base\Controller
{
/**
* @var bool whether to enable CSRF validation for the actions in this controller.
* CSRF validation is enabled only when both this property and [[\yii\web\Request::enableCsrfValidation]] are true.
*/
public $enableCsrfValidation = true;
/**
* @var array the parameters bound to the current action.
*/
public $actionParams = [];
/**
* Renders a view in response to an AJAX request.
*
* This method is similar to [[renderPartial()]] except that it will inject into
* the rendering result with JS/CSS scripts and files which are registered with the view.
* For this reason, you should use this method instead of [[renderPartial()]] to render
* a view to respond to an AJAX request.
*
* @param string $view the view name. Please refer to [[render()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
*/
public function renderAjax($view, $params = [])
{
return $this->getView()->renderAjax($view, $params, $this);
}
/**
* Send data formatted as JSON.
*
* This method is a shortcut for sending data formatted as JSON. It will return
* the [[Application::getResponse()|response]] application component after configuring
* the [[Response::$format|format]] and setting the [[Response::$data|data]] that should
* be formatted. A common usage will be:
*
* ```php
* return $this->asJson($data);
* ```
*
* @param mixed $data the data that should be formatted.
* @return Response a response that is configured to send `$data` formatted as JSON.
* @since 2.0.11
* @see Response::$format
* @see Response::FORMAT_JSON
* @see JsonResponseFormatter
*/
public function asJson($data)
{
$response = Yii::$app->getResponse();
$response->format = Response::FORMAT_JSON;
$response->data = $data;
return $response;
}
/**
* Send data formatted as XML.
*
* This method is a shortcut for sending data formatted as XML. It will return
* the [[Application::getResponse()|response]] application component after configuring
* the [[Response::$format|format]] and setting the [[Response::$data|data]] that should
* be formatted. A common usage will be:
*
* ```php
* return $this->asXml($data);
* ```
*
* @param mixed $data the data that should be formatted.
* @return Response a response that is configured to send `$data` formatted as XML.
* @since 2.0.11
* @see Response::$format
* @see Response::FORMAT_XML
* @see XmlResponseFormatter
*/
public function asXml($data)
{
$response = Yii::$app->getResponse();
$response->format = Response::FORMAT_XML;
$response->data = $data;
return $response;
}
/**
* Binds the parameters to the action.
* This method is invoked by [[\yii\base\Action]] when it begins to run with the given parameters.
* This method will check the parameter names that the action requires and return
* the provided parameters according to the requirement. If there is any missing parameter,
* an exception will be thrown.
* @param \yii\base\Action $action the action to be bound with parameters
* @param array $params the parameters to be bound to the action
* @return array the valid parameters that the action can run with.
* @throws BadRequestHttpException if there are missing or invalid parameters.
*/
public function bindActionParams($action, $params)
{
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
}
$args = [];
$missing = [];
$actionParams = [];
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
if ($param->isArray()) {
$args[] = $actionParams[$name] = (array) $params[$name];
} elseif (!is_array($params[$name])) {
$args[] = $actionParams[$name] = $params[$name];
} else {
throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [
'param' => $name,
]));
}
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $actionParams[$name] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
}
if (!empty($missing)) {
throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [
'params' => implode(', ', $missing),
]));
}
$this->actionParams = $actionParams;
return $args;
}
/**
* {@inheritdoc}
*/
public function beforeAction($action)
{
if (parent::beforeAction($action)) {
if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {
throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));
}
return true;
}
return false;
}
/**
* Redirects the browser to the specified URL.
* This method is a shortcut to [[Response::redirect()]].
*
* You can use it in an action by returning the [[Response]] directly:
*
* ```php
* // stop executing this action and redirect to login page
* return $this->redirect(['login']);
* ```
*
* @param string|array $url the URL to be redirected to. This can be in one of the following formats:
*
* - a string representing a URL (e.g. "http://example.com")
* - a string representing a URL alias (e.g. "@example.com")
* - an array in the format of `[$route, ...name-value pairs...]` (e.g. `['site/index', 'ref' => 1]`)
* [[Url::to()]] will be used to convert the array into a URL.
*
* Any relative URL that starts with a single forward slash "/" will be converted
* into an absolute one by prepending it with the host info of the current request.
*
* @param int $statusCode the HTTP status code. Defaults to 302.
* See <https://tools.ietf.org/html/rfc2616#section-10>
* for details about HTTP status code
* @return Response the current response object
*/
public function redirect($url, $statusCode = 302)
{
return Yii::$app->getResponse()->redirect(Url::to($url), $statusCode);
}
/**
* Redirects the browser to the home page.
*
* You can use this method in an action by returning the [[Response]] directly:
*
* ```php
* // stop executing this action and redirect to home page
* return $this->goHome();
* ```
*
* @return Response the current response object
*/
public function goHome()
{
return Yii::$app->getResponse()->redirect(Yii::$app->getHomeUrl());
}
/**
* Redirects the browser to the last visited page.
*
* You can use this method in an action by returning the [[Response]] directly:
*
* ```php
* // stop executing this action and redirect to last visited page
* return $this->goBack();
* ```
*
* For this function to work you have to [[User::setReturnUrl()|set the return URL]] in appropriate places before.
*
* @param string|array $defaultUrl the default return URL in case it was not set previously.
* If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to.
* Please refer to [[User::setReturnUrl()]] on accepted format of the URL.
* @return Response the current response object
* @see User::getReturnUrl()
*/
public function goBack($defaultUrl = null)
{
return Yii::$app->getResponse()->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl));
}
/**
* Refreshes the current page.
* This method is a shortcut to [[Response::refresh()]].
*
* You can use it in an action by returning the [[Response]] directly:
*
* ```php
* // stop executing this action and refresh the current page
* return $this->refresh();
* ```
*
* @param string $anchor the anchor that should be appended to the redirection URL.
* Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
* @return Response the response object itself
*/
public function refresh($anchor = '')
{
return Yii::$app->getResponse()->redirect(Yii::$app->getRequest()->getUrl() . $anchor);
}
}

68
vendor/yiisoft/yii2/web/Cookie.php vendored Normal file
View File

@@ -0,0 +1,68 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* Cookie represents information related with a cookie, such as [[name]], [[value]], [[domain]], etc.
*
* For more details and usage information on Cookie, see the [guide article on handling cookies](guide:runtime-sessions-cookies).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Cookie extends \yii\base\BaseObject
{
/**
* @var string name of the cookie
*/
public $name;
/**
* @var string value of the cookie
*/
public $value = '';
/**
* @var string domain of the cookie
*/
public $domain = '';
/**
* @var int the timestamp at which the cookie expires. This is the server timestamp.
* Defaults to 0, meaning "until the browser is closed".
*/
public $expire = 0;
/**
* @var string the path on the server in which the cookie will be available on. The default is '/'.
*/
public $path = '/';
/**
* @var bool whether cookie should be sent via secure connection
*/
public $secure = false;
/**
* @var bool whether the cookie should be accessible only through the HTTP protocol.
* 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 = true;
/**
* Magic method to turn a cookie object into a string without having to explicitly access [[value]].
*
* ```php
* if (isset($request->cookies['name'])) {
* $value = (string) $request->cookies['name'];
* }
* ```
*
* @return string The value of the cookie. If the value property is null, an empty string will be returned.
*/
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -0,0 +1,244 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use ArrayIterator;
use Yii;
use yii\base\BaseObject;
use yii\base\InvalidCallException;
/**
* CookieCollection maintains the cookies available in the current request.
*
* For more details and usage information on CookieCollection, see the [guide article on handling cookies](guide:runtime-sessions-cookies).
*
* @property int $count The number of cookies in the collection. This property is read-only.
* @property ArrayIterator $iterator An iterator for traversing the cookies in the collection. This property
* is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class CookieCollection extends BaseObject implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var bool whether this collection is read only.
*/
public $readOnly = false;
/**
* @var Cookie[] the cookies in this collection (indexed by the cookie names)
*/
private $_cookies;
/**
* Constructor.
* @param array $cookies the cookies that this collection initially contains. This should be
* an array of name-value pairs.
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($cookies = [], $config = [])
{
$this->_cookies = $cookies;
parent::__construct($config);
}
/**
* Returns an iterator for traversing the cookies 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 cookies in the collection.
*/
public function getIterator()
{
return new ArrayIterator($this->_cookies);
}
/**
* Returns the number of cookies in the collection.
* This method is required by the SPL `Countable` interface.
* It will be implicitly called when you use `count($collection)`.
* @return int the number of cookies in the collection.
*/
public function count()
{
return $this->getCount();
}
/**
* Returns the number of cookies in the collection.
* @return int the number of cookies in the collection.
*/
public function getCount()
{
return count($this->_cookies);
}
/**
* Returns the cookie with the specified name.
* @param string $name the cookie name
* @return Cookie the cookie with the specified name. Null if the named cookie does not exist.
* @see getValue()
*/
public function get($name)
{
return isset($this->_cookies[$name]) ? $this->_cookies[$name] : null;
}
/**
* Returns the value of the named cookie.
* @param string $name the cookie name
* @param mixed $defaultValue the value that should be returned when the named cookie does not exist.
* @return mixed the value of the named cookie.
* @see get()
*/
public function getValue($name, $defaultValue = null)
{
return isset($this->_cookies[$name]) ? $this->_cookies[$name]->value : $defaultValue;
}
/**
* Returns whether there is a cookie with the specified name.
* Note that if a cookie is marked for deletion from browser, this method will return false.
* @param string $name the cookie name
* @return bool whether the named cookie exists
* @see remove()
*/
public function has($name)
{
return isset($this->_cookies[$name]) && $this->_cookies[$name]->value !== ''
&& ($this->_cookies[$name]->expire === null || $this->_cookies[$name]->expire >= time());
}
/**
* 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 ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
$this->_cookies[$cookie->name] = $cookie;
}
/**
* 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 bool $removeFromBrowser whether to remove the cookie from browser
* @throws InvalidCallException if the cookie collection is read only
*/
public function remove($cookie, $removeFromBrowser = true)
{
if ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
if ($cookie instanceof Cookie) {
$cookie->expire = 1;
$cookie->value = '';
} else {
$cookie = Yii::createObject([
'class' => 'yii\web\Cookie',
'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()
{
if ($this->readOnly) {
throw new InvalidCallException('The cookie collection is read only.');
}
$this->_cookies = [];
}
/**
* Returns the collection as a PHP array.
* @return array the array representation of the collection.
* The array keys are cookie names, and the array values are the corresponding cookie objects.
*/
public function toArray()
{
return $this->_cookies;
}
/**
* Populates the cookie collection from an array.
* @param array $array the cookies to populate from
* @since 2.0.3
*/
public function fromArray(array $array)
{
$this->_cookies = $array;
}
/**
* Returns whether there is a cookie 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 cookie name
* @return bool whether the named cookie exists
*/
public function offsetExists($name)
{
return $this->has($name);
}
/**
* Returns the cookie with the specified name.
* This method is required by the SPL interface [[\ArrayAccess]].
* It is implicitly called when you use something like `$cookie = $collection[$name];`.
* This is equivalent to [[get()]].
* @param string $name the cookie name
* @return Cookie the cookie with the specified name, null if the named cookie does not exist.
*/
public function offsetGet($name)
{
return $this->get($name);
}
/**
* Adds the cookie to the collection.
* This method is required by the SPL interface [[\ArrayAccess]].
* It is implicitly called when you use something like `$collection[$name] = $cookie;`.
* This is equivalent to [[add()]].
* @param string $name the cookie name
* @param Cookie $cookie the cookie to be added
*/
public function offsetSet($name, $cookie)
{
$this->add($cookie);
}
/**
* Removes the named cookie.
* 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 cookie name
*/
public function offsetUnset($name)
{
$this->remove($name);
}
}

230
vendor/yiisoft/yii2/web/DbSession.php vendored Normal file
View File

@@ -0,0 +1,230 @@
<?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\InvalidConfigException;
use yii\db\Connection;
use yii\db\PdoValue;
use yii\db\Query;
use yii\di\Instance;
use yii\helpers\ArrayHelper;
/**
* DbSession extends [[Session]] by using database as session data storage.
*
* By default, DbSession stores session data in a DB table named 'session'. This table
* must be pre-created. The table name can be changed by setting [[sessionTable]].
*
* The following example shows how you can configure the application to use DbSession:
* Add the following to your application config under `components`:
*
* ```php
* 'session' => [
* 'class' => 'yii\web\DbSession',
* // 'db' => 'mydb',
* // 'sessionTable' => 'my_session',
* ]
* ```
*
* DbSession extends [[MultiFieldSession]], thus it allows saving extra fields into the [[sessionTable]].
* Refer to [[MultiFieldSession]] for more details.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class DbSession extends MultiFieldSession
{
/**
* @var Connection|array|string the DB connection object or the application component ID of the DB connection.
* After the DbSession object is created, if you want to change this property, you should only assign it
* with a DB connection object.
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
*/
public $db = 'db';
/**
* @var string the name of the DB table that stores the session data.
* The table should be pre-created as follows:
*
* ```sql
* CREATE TABLE session
* (
* id CHAR(40) NOT NULL PRIMARY KEY,
* expire INTEGER,
* data BLOB
* )
* ```
*
* where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB type
* that can be used for some popular DBMS:
*
* - MySQL: LONGBLOB
* - PostgreSQL: BYTEA
* - MSSQL: BLOB
*
* When using DbSession in a production server, we recommend you create a DB index for the 'expire'
* column in the session table to improve the performance.
*
* Note that according to the php.ini setting of `session.hash_function`, you may need to adjust
* the length of the `id` column. For example, if `session.hash_function=sha256`, you should use
* length 64 instead of 40.
*/
public $sessionTable = '{{%session}}';
/**
* Initializes the DbSession component.
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
* @throws InvalidConfigException if [[db]] is invalid.
*/
public function init()
{
parent::init();
$this->db = Instance::ensure($this->db, Connection::className());
}
/**
* Updates the current session ID with a newly generated one .
* Please refer to <http://php.net/session_regenerate_id> for more details.
* @param bool $deleteOldSession Whether to delete the old associated session file or not.
*/
public function regenerateID($deleteOldSession = false)
{
$oldID = session_id();
// if no session is started, there is nothing to regenerate
if (empty($oldID)) {
return;
}
parent::regenerateID(false);
$newID = session_id();
// if session id regeneration failed, no need to create/update it.
if (empty($newID)) {
Yii::warning('Failed to generate new session ID', __METHOD__);
return;
}
$row = $this->db->useMaster(function() use ($oldID) {
return (new Query())->from($this->sessionTable)
->where(['id' => $oldID])
->createCommand($this->db)
->queryOne();
});
if ($row !== false) {
if ($deleteOldSession) {
$this->db->createCommand()
->update($this->sessionTable, ['id' => $newID], ['id' => $oldID])
->execute();
} else {
$row['id'] = $newID;
$this->db->createCommand()
->insert($this->sessionTable, $row)
->execute();
}
} else {
// shouldn't reach here normally
$this->db->createCommand()
->insert($this->sessionTable, $this->composeFields($newID, ''))
->execute();
}
}
/**
* Session read handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return string the session data
*/
public function readSession($id)
{
$query = new Query();
$query->from($this->sessionTable)
->where('[[expire]]>:expire AND [[id]]=:id', [':expire' => time(), ':id' => $id]);
if ($this->readCallback !== null) {
$fields = $query->one($this->db);
return $fields === false ? '' : $this->extractData($fields);
}
$data = $query->select(['data'])->scalar($this->db);
return $data === false ? '' : $data;
}
/**
* Session write handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @param string $data session data
* @return bool whether session write is successful
*/
public function writeSession($id, $data)
{
// exception must be caught in session write handler
// http://us.php.net/manual/en/function.session-set-save-handler.php#refsect1-function.session-set-save-handler-notes
try {
$fields = $this->composeFields($id, $data);
$fields = $this->typecastFields($fields);
$this->db->createCommand()->upsert($this->sessionTable, $fields)->execute();
} catch (\Exception $e) {
Yii::$app->errorHandler->handleException($e);
return false;
}
return true;
}
/**
* Session destroy handler.
* @internal Do not call this method directly.
* @param string $id session ID
* @return bool whether session is destroyed successfully
*/
public function destroySession($id)
{
$this->db->createCommand()
->delete($this->sessionTable, ['id' => $id])
->execute();
return true;
}
/**
* Session GC (garbage collection) handler.
* @internal Do not call this method directly.
* @param int $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
* @return bool whether session is GCed successfully
*/
public function gcSession($maxLifetime)
{
$this->db->createCommand()
->delete($this->sessionTable, '[[expire]]<:expire', [':expire' => time()])
->execute();
return true;
}
/**
* Method typecasts $fields before passing them to PDO.
* Default implementation casts field `data` to `\PDO::PARAM_LOB`.
* You can override this method in case you need special type casting.
*
* @param array $fields Fields, that will be passed to PDO. Key - name, Value - value
* @return array
* @since 2.0.13
*/
protected function typecastFields($fields)
{
if (isset($fields['data']) && is_array($fields['data'] && is_object($fields['data']))) {
$fields['data'] = new PdoValue($fields['data'], \PDO::PARAM_LOB);
}
return $fields;
}
}

221
vendor/yiisoft/yii2/web/ErrorAction.php vendored Normal file
View File

@@ -0,0 +1,221 @@
<?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\Action;
use yii\base\Exception;
use yii\base\UserException;
/**
* ErrorAction displays application errors using a specified view.
*
* To use ErrorAction, you need to do the following steps:
*
* First, declare an action of ErrorAction type in the `actions()` method of your `SiteController`
* class (or whatever controller you prefer), like the following:
*
* ```php
* public function actions()
* {
* return [
* 'error' => ['class' => 'yii\web\ErrorAction'],
* ];
* }
* ```
*
* Then, create a view file for this action. If the route of your error action is `site/error`, then
* the view file should be `views/site/error.php`. In this view file, the following variables are available:
*
* - `$name`: the error name
* - `$message`: the error message
* - `$exception`: the exception being handled
*
* Finally, configure the "errorHandler" application component as follows,
*
* ```php
* 'errorHandler' => [
* 'errorAction' => 'site/error',
* ]
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Dmitry Naumenko <d.naumenko.a@gmail.com>
* @since 2.0
*/
class ErrorAction extends Action
{
/**
* @var string the view file to be rendered. If not set, it will take the value of [[id]].
* That means, if you name the action as "error" in "SiteController", then the view name
* would be "error", and the corresponding view file would be "views/site/error.php".
*/
public $view;
/**
* @var string the name of the error when the exception name cannot be determined.
* Defaults to "Error".
*/
public $defaultName;
/**
* @var string the message to be displayed when the exception message contains sensitive information.
* Defaults to "An internal server error occurred.".
*/
public $defaultMessage;
/**
* @var string|false|null the name of the layout to be applied to this error action view.
* If not set, the layout configured in the controller will be used.
* @see \yii\base\Controller::$layout
* @since 2.0.14
*/
public $layout;
/**
* @var \Exception the exception object, normally is filled on [[init()]] method call.
* @see [[findException()]] to know default way of obtaining exception.
* @since 2.0.11
*/
protected $exception;
/**
* {@inheritdoc}
*/
public function init()
{
$this->exception = $this->findException();
if ($this->defaultMessage === null) {
$this->defaultMessage = Yii::t('yii', 'An internal server error occurred.');
}
if ($this->defaultName === null) {
$this->defaultName = Yii::t('yii', 'Error');
}
}
/**
* Runs the action.
*
* @return string result content
*/
public function run()
{
if ($this->layout !== null) {
$this->controller->layout = $this->layout;
}
Yii::$app->getResponse()->setStatusCodeByException($this->exception);
if (Yii::$app->getRequest()->getIsAjax()) {
return $this->renderAjaxResponse();
}
return $this->renderHtmlResponse();
}
/**
* Builds string that represents the exception.
* Normally used to generate a response to AJAX request.
* @return string
* @since 2.0.11
*/
protected function renderAjaxResponse()
{
return $this->getExceptionName() . ': ' . $this->getExceptionMessage();
}
/**
* Renders a view that represents the exception.
* @return string
* @since 2.0.11
*/
protected function renderHtmlResponse()
{
return $this->controller->render($this->view ?: $this->id, $this->getViewRenderParams());
}
/**
* Builds array of parameters that will be passed to the view.
* @return array
* @since 2.0.11
*/
protected function getViewRenderParams()
{
return [
'name' => $this->getExceptionName(),
'message' => $this->getExceptionMessage(),
'exception' => $this->exception,
];
}
/**
* Gets exception from the [[yii\web\ErrorHandler|ErrorHandler]] component.
* In case there is no exception in the component, treat as the action has been invoked
* not from error handler, but by direct route, so '404 Not Found' error will be displayed.
* @return \Exception
* @since 2.0.11
*/
protected function findException()
{
if (($exception = Yii::$app->getErrorHandler()->exception) === null) {
$exception = new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
}
return $exception;
}
/**
* Gets the code from the [[exception]].
* @return mixed
* @since 2.0.11
*/
protected function getExceptionCode()
{
if ($this->exception instanceof HttpException) {
return $this->exception->statusCode;
}
return $this->exception->getCode();
}
/**
* Returns the exception name, followed by the code (if present).
*
* @return string
* @since 2.0.11
*/
protected function getExceptionName()
{
if ($this->exception instanceof Exception) {
$name = $this->exception->getName();
} else {
$name = $this->defaultName;
}
if ($code = $this->getExceptionCode()) {
$name .= " (#$code)";
}
return $name;
}
/**
* Returns the [[exception]] message for [[yii\base\UserException]] only.
* For other cases [[defaultMessage]] will be returned.
* @return string
* @since 2.0.11
*/
protected function getExceptionMessage()
{
if ($this->exception instanceof UserException) {
return $this->exception->getMessage();
}
return $this->defaultMessage;
}
}

501
vendor/yiisoft/yii2/web/ErrorHandler.php vendored Normal file
View File

@@ -0,0 +1,501 @@
<?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\ErrorException;
use yii\base\Exception;
use yii\base\UserException;
use yii\helpers\VarDumper;
/**
* ErrorHandler handles uncaught PHP errors and exceptions.
*
* ErrorHandler displays these errors using appropriate views based on the
* nature of the errors and the mode the application runs at.
*
* ErrorHandler is configured as an application component in [[\yii\base\Application]] by default.
* You can access that instance via `Yii::$app->errorHandler`.
*
* For more details and usage information on ErrorHandler, see the [guide article on handling errors](guide:runtime-handling-errors).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Timur Ruziev <resurtm@gmail.com>
* @since 2.0
*/
class ErrorHandler extends \yii\base\ErrorHandler
{
/**
* @var int maximum number of source code lines to be displayed. Defaults to 19.
*/
public $maxSourceLines = 19;
/**
* @var int maximum number of trace source code lines to be displayed. Defaults to 13.
*/
public $maxTraceSourceLines = 13;
/**
* @var string the route (e.g. `site/error`) to the controller action that will be used
* to display external errors. Inside the action, it can retrieve the error information
* using `Yii::$app->errorHandler->exception`. This property defaults to null, meaning ErrorHandler
* will handle the error display.
*/
public $errorAction;
/**
* @var string the path of the view file for rendering exceptions without call stack information.
*/
public $errorView = '@yii/views/errorHandler/error.php';
/**
* @var string the path of the view file for rendering exceptions.
*/
public $exceptionView = '@yii/views/errorHandler/exception.php';
/**
* @var string the path of the view file for rendering exceptions and errors call stack element.
*/
public $callStackItemView = '@yii/views/errorHandler/callStackItem.php';
/**
* @var string the path of the view file for rendering previous exceptions.
*/
public $previousExceptionView = '@yii/views/errorHandler/previousException.php';
/**
* @var array list of the PHP predefined variables that should be displayed on the error page.
* Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be displayed.
* Defaults to `['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION']`.
* @see renderRequest()
* @since 2.0.7
*/
public $displayVars = ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION'];
/**
* @var string trace line with placeholders to be be substituted.
* The placeholders are {file}, {line} and {text} and the string should be as follows.
*
* `File: {file} - Line: {line} - Text: {text}`
*
* @example <a href="ide://open?file={file}&line={line}">{html}</a>
* @see https://github.com/yiisoft/yii2-debug#open-files-in-ide
* @since 2.0.14
*/
public $traceLine = '{html}';
/**
* Renders the exception.
* @param \Exception|\Error $exception the exception to be rendered.
*/
protected function renderException($exception)
{
if (Yii::$app->has('response')) {
$response = Yii::$app->getResponse();
// reset parameters of response to avoid interference with partially created response data
// in case the error occurred while sending the response.
$response->isSent = false;
$response->stream = null;
$response->data = null;
$response->content = null;
} else {
$response = new Response();
}
$response->setStatusCodeByException($exception);
$useErrorView = $response->format === Response::FORMAT_HTML && (!YII_DEBUG || $exception instanceof UserException);
if ($useErrorView && $this->errorAction !== null) {
$result = Yii::$app->runAction($this->errorAction);
if ($result instanceof Response) {
$response = $result;
} else {
$response->data = $result;
}
} elseif ($response->format === Response::FORMAT_HTML) {
if ($this->shouldRenderSimpleHtml()) {
// AJAX request
$response->data = '<pre>' . $this->htmlEncode(static::convertExceptionToString($exception)) . '</pre>';
} else {
// if there is an error during error rendering it's useful to
// display PHP error in debug mode instead of a blank screen
if (YII_DEBUG) {
ini_set('display_errors', 1);
}
$file = $useErrorView ? $this->errorView : $this->exceptionView;
$response->data = $this->renderFile($file, [
'exception' => $exception,
]);
}
} elseif ($response->format === Response::FORMAT_RAW) {
$response->data = static::convertExceptionToString($exception);
} else {
$response->data = $this->convertExceptionToArray($exception);
}
$response->send();
}
/**
* Converts an exception into an array.
* @param \Exception|\Error $exception the exception being converted
* @return array the array representation of the exception.
*/
protected function convertExceptionToArray($exception)
{
if (!YII_DEBUG && !$exception instanceof UserException && !$exception instanceof HttpException) {
$exception = new HttpException(500, Yii::t('yii', 'An internal server error occurred.'));
}
$array = [
'name' => ($exception instanceof Exception || $exception instanceof ErrorException) ? $exception->getName() : 'Exception',
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
];
if ($exception instanceof HttpException) {
$array['status'] = $exception->statusCode;
}
if (YII_DEBUG) {
$array['type'] = get_class($exception);
if (!$exception instanceof UserException) {
$array['file'] = $exception->getFile();
$array['line'] = $exception->getLine();
$array['stack-trace'] = explode("\n", $exception->getTraceAsString());
if ($exception instanceof \yii\db\Exception) {
$array['error-info'] = $exception->errorInfo;
}
}
}
if (($prev = $exception->getPrevious()) !== null) {
$array['previous'] = $this->convertExceptionToArray($prev);
}
return $array;
}
/**
* Converts special characters to HTML entities.
* @param string $text to encode.
* @return string encoded original text.
*/
public function htmlEncode($text)
{
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}
/**
* Adds informational links to the given PHP type/class.
* @param string $code type/class name to be linkified.
* @return string linkified with HTML type/class name.
*/
public function addTypeLinks($code)
{
if (preg_match('/(.*?)::([^(]+)/', $code, $matches)) {
$class = $matches[1];
$method = $matches[2];
$text = $this->htmlEncode($class) . '::' . $this->htmlEncode($method);
} else {
$class = $code;
$method = null;
$text = $this->htmlEncode($class);
}
$url = null;
$shouldGenerateLink = true;
if ($method !== null && substr_compare($method, '{closure}', -9) !== 0) {
$reflection = new \ReflectionClass($class);
if ($reflection->hasMethod($method)) {
$reflectionMethod = $reflection->getMethod($method);
$shouldGenerateLink = $reflectionMethod->isPublic() || $reflectionMethod->isProtected();
} else {
$shouldGenerateLink = false;
}
}
if ($shouldGenerateLink) {
$url = $this->getTypeUrl($class, $method);
}
if ($url === null) {
return $text;
}
return '<a href="' . $url . '" target="_blank">' . $text . '</a>';
}
/**
* Returns the informational link URL for a given PHP type/class.
* @param string $class the type or class name.
* @param string|null $method the method name.
* @return string|null the informational link URL.
* @see addTypeLinks()
*/
protected function getTypeUrl($class, $method)
{
if (strncmp($class, 'yii\\', 4) !== 0) {
return null;
}
$page = $this->htmlEncode(strtolower(str_replace('\\', '-', $class)));
$url = "http://www.yiiframework.com/doc-2.0/$page.html";
if ($method) {
$url .= "#$method()-detail";
}
return $url;
}
/**
* Renders a view file as a PHP script.
* @param string $_file_ the view file.
* @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
* @return string the rendering result
*/
public function renderFile($_file_, $_params_)
{
$_params_['handler'] = $this;
if ($this->exception instanceof ErrorException || !Yii::$app->has('view')) {
ob_start();
ob_implicit_flush(false);
extract($_params_, EXTR_OVERWRITE);
require Yii::getAlias($_file_);
return ob_get_clean();
}
return Yii::$app->getView()->renderFile($_file_, $_params_, $this);
}
/**
* Renders the previous exception stack for a given Exception.
* @param \Exception $exception the exception whose precursors should be rendered.
* @return string HTML content of the rendered previous exceptions.
* Empty string if there are none.
*/
public function renderPreviousExceptions($exception)
{
if (($previous = $exception->getPrevious()) !== null) {
return $this->renderFile($this->previousExceptionView, ['exception' => $previous]);
}
return '';
}
/**
* Renders a single call stack element.
* @param string|null $file name where call has happened.
* @param int|null $line number on which call has happened.
* @param string|null $class called class name.
* @param string|null $method called function/method name.
* @param array $args array of method arguments.
* @param int $index number of the call stack element.
* @return string HTML content of the rendered call stack element.
*/
public function renderCallStackItem($file, $line, $class, $method, $args, $index)
{
$lines = [];
$begin = $end = 0;
if ($file !== null && $line !== null) {
$line--; // adjust line number from one-based to zero-based
$lines = @file($file);
if ($line < 0 || $lines === false || ($lineCount = count($lines)) < $line) {
return '';
}
$half = (int) (($index === 1 ? $this->maxSourceLines : $this->maxTraceSourceLines) / 2);
$begin = $line - $half > 0 ? $line - $half : 0;
$end = $line + $half < $lineCount ? $line + $half : $lineCount - 1;
}
return $this->renderFile($this->callStackItemView, [
'file' => $file,
'line' => $line,
'class' => $class,
'method' => $method,
'index' => $index,
'lines' => $lines,
'begin' => $begin,
'end' => $end,
'args' => $args,
]);
}
/**
* Renders call stack.
* @param \Exception|\ParseError $exception exception to get call stack from
* @return string HTML content of the rendered call stack.
* @since 2.0.12
*/
public function renderCallStack($exception)
{
$out = '<ul>';
$out .= $this->renderCallStackItem($exception->getFile(), $exception->getLine(), null, null, [], 1);
for ($i = 0, $trace = $exception->getTrace(), $length = count($trace); $i < $length; ++$i) {
$file = !empty($trace[$i]['file']) ? $trace[$i]['file'] : null;
$line = !empty($trace[$i]['line']) ? $trace[$i]['line'] : null;
$class = !empty($trace[$i]['class']) ? $trace[$i]['class'] : null;
$function = null;
if (!empty($trace[$i]['function']) && $trace[$i]['function'] !== 'unknown') {
$function = $trace[$i]['function'];
}
$args = !empty($trace[$i]['args']) ? $trace[$i]['args'] : [];
$out .= $this->renderCallStackItem($file, $line, $class, $function, $args, $i + 2);
}
$out .= '</ul>';
return $out;
}
/**
* Renders the global variables of the request.
* List of global variables is defined in [[displayVars]].
* @return string the rendering result
* @see displayVars
*/
public function renderRequest()
{
$request = '';
foreach ($this->displayVars as $name) {
if (!empty($GLOBALS[$name])) {
$request .= '$' . $name . ' = ' . VarDumper::export($GLOBALS[$name]) . ";\n\n";
}
}
return '<pre>' . $this->htmlEncode(rtrim($request, "\n")) . '</pre>';
}
/**
* Determines whether given name of the file belongs to the framework.
* @param string $file name to be checked.
* @return bool whether given name of the file belongs to the framework.
*/
public function isCoreFile($file)
{
return $file === null || strpos(realpath($file), YII2_PATH . DIRECTORY_SEPARATOR) === 0;
}
/**
* Creates HTML containing link to the page with the information on given HTTP status code.
* @param int $statusCode to be used to generate information link.
* @param string $statusDescription Description to display after the the status code.
* @return string generated HTML with HTTP status code information.
*/
public function createHttpStatusLink($statusCode, $statusDescription)
{
return '<a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#' . (int) $statusCode . '" target="_blank">HTTP ' . (int) $statusCode . ' &ndash; ' . $statusDescription . '</a>';
}
/**
* Creates string containing HTML link which refers to the home page of determined web-server software
* and its full name.
* @return string server software information hyperlink.
*/
public function createServerInformationLink()
{
$serverUrls = [
'http://httpd.apache.org/' => ['apache'],
'http://nginx.org/' => ['nginx'],
'http://lighttpd.net/' => ['lighttpd'],
'http://gwan.com/' => ['g-wan', 'gwan'],
'http://iis.net/' => ['iis', 'services'],
'http://php.net/manual/en/features.commandline.webserver.php' => ['development'],
];
if (isset($_SERVER['SERVER_SOFTWARE'])) {
foreach ($serverUrls as $url => $keywords) {
foreach ($keywords as $keyword) {
if (stripos($_SERVER['SERVER_SOFTWARE'], $keyword) !== false) {
return '<a href="' . $url . '" target="_blank">' . $this->htmlEncode($_SERVER['SERVER_SOFTWARE']) . '</a>';
}
}
}
}
return '';
}
/**
* Creates string containing HTML link which refers to the page with the current version
* of the framework and version number text.
* @return string framework version information hyperlink.
*/
public function createFrameworkVersionLink()
{
return '<a href="http://github.com/yiisoft/yii2/" target="_blank">' . $this->htmlEncode(Yii::getVersion()) . '</a>';
}
/**
* Converts arguments array to its string representation.
*
* @param array $args arguments array to be converted
* @return string string representation of the arguments array
*/
public function argumentsToString($args)
{
$count = 0;
$isAssoc = $args !== array_values($args);
foreach ($args as $key => $value) {
$count++;
if ($count >= 5) {
if ($count > 5) {
unset($args[$key]);
} else {
$args[$key] = '...';
}
continue;
}
if (is_object($value)) {
$args[$key] = '<span class="title">' . $this->htmlEncode(get_class($value)) . '</span>';
} elseif (is_bool($value)) {
$args[$key] = '<span class="keyword">' . ($value ? 'true' : 'false') . '</span>';
} elseif (is_string($value)) {
$fullValue = $this->htmlEncode($value);
if (mb_strlen($value, 'UTF-8') > 32) {
$displayValue = $this->htmlEncode(mb_substr($value, 0, 32, 'UTF-8')) . '...';
$args[$key] = "<span class=\"string\" title=\"$fullValue\">'$displayValue'</span>";
} else {
$args[$key] = "<span class=\"string\">'$fullValue'</span>";
}
} elseif (is_array($value)) {
$args[$key] = '[' . $this->argumentsToString($value) . ']';
} elseif ($value === null) {
$args[$key] = '<span class="keyword">null</span>';
} elseif (is_resource($value)) {
$args[$key] = '<span class="keyword">resource</span>';
} else {
$args[$key] = '<span class="number">' . $value . '</span>';
}
if (is_string($key)) {
$args[$key] = '<span class="string">\'' . $this->htmlEncode($key) . "'</span> => $args[$key]";
} elseif ($isAssoc) {
$args[$key] = "<span class=\"number\">$key</span> => $args[$key]";
}
}
return implode(', ', $args);
}
/**
* Returns human-readable exception name.
* @param \Exception $exception
* @return string human-readable exception name or null if it cannot be determined
*/
public function getExceptionName($exception)
{
if ($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\InvalidCallException || $exception instanceof \yii\base\InvalidParamException || $exception instanceof \yii\base\UnknownMethodException) {
return $exception->getName();
}
return null;
}
/**
* @return bool if simple HTML should be rendered
* @since 2.0.12
*/
protected function shouldRenderSimpleHtml()
{
return YII_ENV_TEST || Yii::$app->request->getIsAjax();
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* ForbiddenHttpException represents a "Forbidden" HTTP exception with status code 403.
*
* Use this exception when a user is not allowed to perform the requested action.
* Using different credentials might or might not allow performing the requested action.
* If you do not want to expose authorization information to the user, it is valid
* to respond with a 404 [[NotFoundHttpException]].
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.3
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class ForbiddenHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(403, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* GoneHttpException represents a "Gone" HTTP exception with status code 410.
*
* Throw a GoneHttpException when a user requests a resource that no longer exists
* at the requested url. For example, after a record is deleted, future requests
* for that record should return a 410 GoneHttpException instead of a 404
* [[NotFoundHttpException]].
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.9
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class GoneHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(410, $message, $code, $previous);
}
}

144
vendor/yiisoft/yii2/web/GroupUrlRule.php vendored Normal file
View File

@@ -0,0 +1,144 @@
<?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\InvalidConfigException;
/**
* GroupUrlRule represents a collection of URL rules sharing the same prefix in their patterns and routes.
*
* GroupUrlRule is best used by a module which often uses module ID as the prefix for the URL rules.
* For example, the following code creates a rule for the `admin` module:
*
* ```php
* new GroupUrlRule([
* 'prefix' => 'admin',
* 'rules' => [
* 'login' => 'user/login',
* 'logout' => 'user/logout',
* 'dashboard' => 'default/dashboard',
* ],
* ]);
*
* // the above rule is equivalent to the following three rules:
*
* [
* 'admin/login' => 'admin/user/login',
* 'admin/logout' => 'admin/user/logout',
* 'admin/dashboard' => 'admin/default/dashboard',
* ]
* ```
*
* The above example assumes the prefix for patterns and routes are the same. They can be made different
* by configuring [[prefix]] and [[routePrefix]] separately.
*
* Using a GroupUrlRule is more efficient than directly declaring the individual rules it contains.
* This is because GroupUrlRule can quickly determine if it should process a URL parsing or creation request
* by simply checking if the prefix matches.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class GroupUrlRule extends CompositeUrlRule
{
/**
* @var array the rules contained within this composite rule. Please refer to [[UrlManager::rules]]
* for the format of this property.
* @see prefix
* @see routePrefix
*/
public $rules = [];
/**
* @var string the prefix for the pattern part of every rule declared in [[rules]].
* The prefix and the pattern will be separated with a slash.
*/
public $prefix;
/**
* @var string the prefix for the route part of every rule declared in [[rules]].
* The prefix and the route will be separated with a slash.
* If this property is not set, it will take the value of [[prefix]].
*/
public $routePrefix;
/**
* @var array the default configuration of URL rules. Individual rule configurations
* specified via [[rules]] will take precedence when the same property of the rule is configured.
*/
public $ruleConfig = ['class' => 'yii\web\UrlRule'];
/**
* {@inheritdoc}
*/
public function init()
{
$this->prefix = trim($this->prefix, '/');
$this->routePrefix = $this->routePrefix === null ? $this->prefix : trim($this->routePrefix, '/');
parent::init();
}
/**
* {@inheritdoc}
*/
protected function createRules()
{
$rules = [];
foreach ($this->rules as $key => $rule) {
if (!is_array($rule)) {
$verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
$verb = null;
if (preg_match("/^((?:(?:$verbs),)*(?:$verbs))\\s+(.*)$/", $key, $matches)) {
$verb = explode(',', $matches[1]);
$key = $matches[2];
}
$rule = [
'pattern' => ltrim($this->prefix . '/' . $key, '/'),
'route' => ltrim($this->routePrefix . '/' . $rule, '/'),
'verb' => $verb
];
} elseif (isset($rule['pattern'], $rule['route'])) {
$rule['pattern'] = ltrim($this->prefix . '/' . $rule['pattern'], '/');
$rule['route'] = ltrim($this->routePrefix . '/' . $rule['route'], '/');
}
$rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
if (!$rule instanceof UrlRuleInterface) {
throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
}
$rules[] = $rule;
}
return $rules;
}
/**
* {@inheritdoc}
*/
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if ($this->prefix === '' || strpos($pathInfo . '/', $this->prefix . '/') === 0) {
return parent::parseRequest($manager, $request);
}
return false;
}
/**
* {@inheritdoc}
*/
public function createUrl($manager, $route, $params)
{
if ($this->routePrefix === '' || strpos($route, $this->routePrefix . '/') === 0) {
return parent::createUrl($manager, $route, $params);
}
$this->createStatus = UrlRule::CREATE_STATUS_ROUTE_MISMATCH;
return false;
}
}

View File

@@ -0,0 +1,235 @@
<?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\BaseObject;
/**
* HeaderCollection is used by [[Response]] to maintain the currently registered HTTP headers.
*
* @property int $count The number of headers in the collection. This property is read-only.
* @property \ArrayIterator $iterator An iterator for traversing the headers in the collection. This property
* is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HeaderCollection extends BaseObject implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var array the headers in this collection (indexed by the header names)
*/
private $_headers = [];
/**
* 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 int the number of headers in the collection.
*/
public function count()
{
return $this->getCount();
}
/**
* Returns the number of headers in the collection.
* @return int 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 bool $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];
}
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 $this 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 $this the collection object itself
*/
public function add($name, $value)
{
$name = strtolower($name);
$this->_headers[$name][] = $value;
return $this;
}
/**
* Sets a new header only if it does not exist yet.
* If there is already a header with the same name, the new one will be ignored.
* @param string $name the name of the header
* @param string $value the value of the header
* @return $this the collection object itself
*/
public function setDefault($name, $value)
{
$name = strtolower($name);
if (empty($this->_headers[$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 bool 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 array 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;
}
return null;
}
/**
* Removes all headers.
*/
public function removeAll()
{
$this->_headers = [];
}
/**
* 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;
}
/**
* Populates the header collection from an array.
* @param array $array the headers to populate from
* @since 2.0.3
*/
public function fromArray(array $array)
{
$this->_headers = $array;
}
/**
* 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 bool 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);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\Exception;
/**
* HeadersAlreadySentException represents an exception caused by
* any headers that were already sent before web response was sent.
*
* @author Dmitry Dorogin <dmirogin@ya.ru>
* @since 2.0.14
*/
class HeadersAlreadySentException extends Exception
{
/**
* {@inheritdoc}
*/
public function __construct($file, $line)
{
$message = YII_DEBUG ? "Headers already sent in {$file} on line {$line}." : 'Headers already sent.';
parent::__construct($message);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\Component;
/**
* HtmlResponseFormatter formats the given data into an HTML response content.
*
* It is used by [[Response]] to format response data.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HtmlResponseFormatter extends Component implements ResponseFormatterInterface
{
/**
* @var string the Content-Type header for the response
*/
public $contentType = 'text/html';
/**
* Formats the specified response.
* @param Response $response the response to be formatted.
*/
public function format($response)
{
if (stripos($this->contentType, 'charset') === false) {
$this->contentType .= '; charset=' . $response->charset;
}
$response->getHeaders()->set('Content-Type', $this->contentType);
if ($response->data !== null) {
$response->content = $response->data;
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\UserException;
/**
* HttpException represents an exception caused by an improper request of the end-user.
*
* HttpException can be differentiated via its [[statusCode]] property value which
* keeps a standard HTTP status code (e.g. 404, 500). Error handlers may use this status code
* to decide how to format the error page.
*
* Throwing an HttpException like in the following example will result in the 404 page to be displayed.
*
* ```php
* if ($item === null) { // item does not exist
* throw new \yii\web\HttpException(404, 'The requested Item could not be found.');
* }
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HttpException extends UserException
{
/**
* @var int HTTP status code, such as 403, 404, 500, etc.
*/
public $statusCode;
/**
* Constructor.
* @param int $status HTTP status code, such as 404, 500, etc.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($status, $message = null, $code = 0, \Exception $previous = null)
{
$this->statusCode = $status;
parent::__construct($message, $code, $previous);
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
if (isset(Response::$httpStatuses[$this->statusCode])) {
return Response::$httpStatuses[$this->statusCode];
}
return 'Error';
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* IdentityInterface is the interface that should be implemented by a class providing identity information.
*
* This interface can typically be implemented by a user model class. For example, the following
* code shows how to implement this interface by a User ActiveRecord class:
*
* ```php
* class User extends ActiveRecord implements IdentityInterface
* {
* public static function findIdentity($id)
* {
* return static::findOne($id);
* }
*
* public static function findIdentityByAccessToken($token, $type = null)
* {
* return static::findOne(['access_token' => $token]);
* }
*
* public function getId()
* {
* return $this->id;
* }
*
* public function getAuthKey()
* {
* return $this->authKey;
* }
*
* public function validateAuthKey($authKey)
* {
* return $this->authKey === $authKey;
* }
* }
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface IdentityInterface
{
/**
* Finds an identity by the given ID.
* @param string|int $id the ID to be looked for
* @return IdentityInterface the identity object that matches the given ID.
* Null should be returned if such an identity cannot be found
* or the identity is not in an active state (disabled, deleted, etc.)
*/
public static function findIdentity($id);
/**
* Finds an identity by the given token.
* @param mixed $token the token to be looked for
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
* @return IdentityInterface the identity object that matches the given token.
* Null should be returned if such an identity cannot be found
* or the identity is not in an active state (disabled, deleted, etc.)
*/
public static function findIdentityByAccessToken($token, $type = null);
/**
* Returns an ID that can uniquely identify a user identity.
* @return string|int an ID that uniquely identifies a user identity.
*/
public function getId();
/**
* Returns a key that can be used to check the validity of a given identity ID.
*
* The key should be unique for each individual user, and should be persistent
* so that it can be used to check the validity of the user identity.
*
* The space of such keys should be big enough to defeat potential identity attacks.
*
* This is required if [[User::enableAutoLogin]] is enabled.
* @return string a key that is used to check the validity of a given identity ID.
* @see validateAuthKey()
*/
public function getAuthKey();
/**
* Validates the given auth key.
*
* This is required if [[User::enableAutoLogin]] is enabled.
* @param string $authKey the given auth key
* @return bool whether the given auth key is valid.
* @see getAuthKey()
*/
public function validateAuthKey($authKey);
}

22
vendor/yiisoft/yii2/web/JqueryAsset.php vendored Normal file
View File

@@ -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\web;
/**
* This asset bundle provides the [jQuery](http://jquery.com/) JavaScript library.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class JqueryAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery/dist';
public $js = [
'jquery.js',
];
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\BaseObject;
/**
* JsExpression marks a string as a JavaScript expression.
*
* When using [[\yii\helpers\Json::encode()]] or [[\yii\helpers\Json::htmlEncode()]] to encode a value, JsonExpression objects
* will be specially handled and encoded as a JavaScript expression instead of a string.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class JsExpression extends BaseObject
{
/**
* @var string the JavaScript expression represented by this object
*/
public $expression;
/**
* Constructor.
* @param string $expression the JavaScript expression represented by this object
* @param array $config additional configurations for this object
*/
public function __construct($expression, $config = [])
{
$this->expression = $expression;
parent::__construct($config);
}
/**
* The PHP magic function converting an object into a string.
* @return string the JavaScript expression.
*/
public function __toString()
{
return $this->expression;
}
}

61
vendor/yiisoft/yii2/web/JsonParser.php vendored Normal file
View File

@@ -0,0 +1,61 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\InvalidParamException;
use yii\helpers\Json;
/**
* Parses a raw HTTP request using [[\yii\helpers\Json::decode()]].
*
* To enable parsing for JSON requests you can configure [[Request::parsers]] using this class:
*
* ```php
* 'request' => [
* 'parsers' => [
* 'application/json' => 'yii\web\JsonParser',
* ]
* ]
* ```
*
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class JsonParser implements RequestParserInterface
{
/**
* @var bool whether to return objects in terms of associative arrays.
*/
public $asArray = true;
/**
* @var bool whether to throw a [[BadRequestHttpException]] if the body is invalid json
*/
public $throwException = true;
/**
* Parses a HTTP request body.
* @param string $rawBody the raw HTTP request body.
* @param string $contentType the content type specified for the request body.
* @return array parameters parsed from the request body
* @throws BadRequestHttpException if the body contains invalid json and [[throwException]] is `true`.
*/
public function parse($rawBody, $contentType)
{
try {
$parameters = Json::decode($rawBody, $this->asArray);
return $parameters === null ? [] : $parameters;
} catch (InvalidParamException $e) {
if ($this->throwException) {
throw new BadRequestHttpException('Invalid JSON data in request body: ' . $e->getMessage());
}
return [];
}
}
}

View File

@@ -0,0 +1,145 @@
<?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\Component;
use yii\helpers\Json;
/**
* JsonResponseFormatter formats the given data into a JSON or JSONP response content.
*
* It is used by [[Response]] to format response data.
*
* To configure properties like [[encodeOptions]] or [[prettyPrint]], you can configure the `response`
* application component like the following:
*
* ```php
* 'response' => [
* // ...
* 'formatters' => [
* \yii\web\Response::FORMAT_JSON => [
* 'class' => 'yii\web\JsonResponseFormatter',
* 'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode
* // ...
* ],
* ],
* ],
* ```
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class JsonResponseFormatter extends Component implements ResponseFormatterInterface
{
/**
* JSON Content Type
* @since 2.0.14
*/
const CONTENT_TYPE_JSONP = 'application/javascript; charset=UTF-8';
/**
* JSONP Content Type
* @since 2.0.14
*/
const CONTENT_TYPE_JSON = 'application/json; charset=UTF-8';
/**
* HAL JSON Content Type
* @since 2.0.14
*/
const CONTENT_TYPE_HAL_JSON = 'application/hal+json; charset=UTF-8';
/**
* @var string|null custom value of the `Content-Type` header of the response.
* When equals `null` default content type will be used based on the `useJsonp` property.
* @since 2.0.14
*/
public $contentType;
/**
* @var bool whether to use JSONP response format. When this is true, the [[Response::data|response data]]
* must be an array consisting of `data` and `callback` members. The latter should be a JavaScript
* function name while the former will be passed to this function as a parameter.
*/
public $useJsonp = false;
/**
* @var int the encoding options passed to [[Json::encode()]]. For more details please refer to
* <http://www.php.net/manual/en/function.json-encode.php>.
* Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`.
* This property has no effect, when [[useJsonp]] is `true`.
* @since 2.0.7
*/
public $encodeOptions = 320;
/**
* @var bool whether to format the output in a readable "pretty" format. This can be useful for debugging purpose.
* If this is true, `JSON_PRETTY_PRINT` will be added to [[encodeOptions]].
* Defaults to `false`.
* This property has no effect, when [[useJsonp]] is `true`.
* @since 2.0.7
*/
public $prettyPrint = false;
/**
* Formats the specified response.
* @param Response $response the response to be formatted.
*/
public function format($response)
{
if ($this->contentType === null) {
$this->contentType = $this->useJsonp
? self::CONTENT_TYPE_JSONP
: self::CONTENT_TYPE_JSON;
} elseif (strpos($this->contentType, 'charset') === false) {
$this->contentType .= '; charset=UTF-8';
}
$response->getHeaders()->set('Content-Type', $this->contentType);
if ($this->useJsonp) {
$this->formatJsonp($response);
} else {
$this->formatJson($response);
}
}
/**
* Formats response data in JSON format.
* @param Response $response
*/
protected function formatJson($response)
{
if ($response->data !== null) {
$options = $this->encodeOptions;
if ($this->prettyPrint) {
$options |= JSON_PRETTY_PRINT;
}
$response->content = Json::encode($response->data, $options);
}
}
/**
* Formats response data in JSONP format.
* @param Response $response
*/
protected function formatJsonp($response)
{
if (is_array($response->data)
&& isset($response->data['data'], $response->data['callback'])
) {
$response->content = sprintf(
'%s(%s);',
$response->data['callback'],
Json::htmlEncode($response->data['data'])
);
} elseif ($response->data !== null) {
$response->content = '';
Yii::warning(
"The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements.",
__METHOD__
);
}
}
}

76
vendor/yiisoft/yii2/web/Link.php vendored Normal file
View File

@@ -0,0 +1,76 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\BaseObject;
/**
* Link represents a link object as defined in [JSON Hypermedia API Language](https://tools.ietf.org/html/draft-kelly-json-hal-03).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Link extends BaseObject
{
/**
* The self link.
*/
const REL_SELF = 'self';
/**
* @var string a URI [RFC3986](https://tools.ietf.org/html/rfc3986) or
* URI template [RFC6570](https://tools.ietf.org/html/rfc6570). This property is required.
*/
public $href;
/**
* @var string a secondary key for selecting Link Objects which share the same relation type
*/
public $name;
/**
* @var string a hint to indicate the media type expected when dereferencing the target resource
*/
public $type;
/**
* @var bool a value indicating whether [[href]] refers to a URI or URI template.
*/
public $templated = false;
/**
* @var string a URI that hints about the profile of the target resource.
*/
public $profile;
/**
* @var string a label describing the link
*/
public $title;
/**
* @var string the language of the target resource
*/
public $hreflang;
/**
* Serializes a list of links into proper array format.
* @param array $links the links to be serialized
* @return array the proper array representation of the links.
*/
public static function serialize(array $links)
{
foreach ($links as $rel => $link) {
if (is_array($link)) {
foreach ($link as $i => $l) {
$link[$i] = $l instanceof self ? array_filter((array) $l) : ['href' => $l];
}
$links[$rel] = $link;
} elseif (!$link instanceof self) {
$links[$rel] = ['href' => $link];
}
}
return $links;
}
}

42
vendor/yiisoft/yii2/web/Linkable.php vendored Normal file
View File

@@ -0,0 +1,42 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* Linkable is the interface that should be implemented by classes that typically represent locatable resources.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface Linkable
{
/**
* Returns a list of links.
*
* Each link is either a URI or a [[Link]] object. The return value of this method should
* be an array whose keys are the relation names and values the corresponding links.
*
* If a relation name corresponds to multiple links, use an array to represent them.
*
* For example,
*
* ```php
* [
* 'self' => 'http://example.com/users/1',
* 'friends' => [
* 'http://example.com/users/2',
* 'http://example.com/users/3',
* ],
* 'manager' => $managerLink, // $managerLink is a Link object
* ]
* ```
*
* @return array the links
*/
public function getLinks();
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* MethodNotAllowedHttpException represents a "Method Not Allowed" HTTP exception with status code 405.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.5
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class MethodNotAllowedHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(405, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,142 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* MultiFieldSession is the base class for session storage implementations with multi-field data storage support.
*
* With multi-field data storage, session data can be split between several fields in the storage record.
* Using such a storage allows saving particular session data into separated field, which then can be used
* to manipulate sessions in the way plain PHP does not allow.
*
* For example the ID of the authenticated user can be saved as separated column in the MySQL 'session' table,
* which allows to query all active sessions for a particular user or terminate them at will.
*
* Customizing of the session writing is performed via [[writeCallback]], reading via [[readCallback]].
*
* While extending this class you should use [[composeFields()]] method - while writing the session data into the storage and
* [[extractData()]] - while reading session data from the storage.
*
* @property bool $useCustomStorage Whether to use custom storage. This property is read-only.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.6
*/
abstract class MultiFieldSession extends Session
{
/**
* @var callable a callback that will be called during session data reading.
* The signature of the callback should be as follows:
*
* ```
* function ($fields)
* ```
*
* where `$fields` is the storage field set for read session and `$session` is this session instance.
* If callback returns an array, it will be merged into the session data.
*
* For example:
*
* ```php
* function ($fields) {
* return [
* 'expireDate' => Yii::$app->formatter->asDate($fields['expire']),
* ];
* }
* ```
*/
public $readCallback;
/**
* @var callable a callback that will be called during session data writing.
* The signature of the callback should be as follows:
*
* ```
* function ($session)
* ```
*
* where `$session` is this session instance, this variable can be used to retrieve session data.
* Callback should return the actual fields set, which should be saved into the session storage.
*
* For example:
*
* ```php
* function ($session) {
* return [
* 'user_id' => Yii::$app->user->id,
* 'ip' => $_SERVER['REMOTE_ADDR'],
* 'is_trusted' => $session->get('is_trusted', false),
* ];
* }
* ```
*/
public $writeCallback;
/**
* Returns a value indicating whether to use custom session storage.
* This method overrides the parent implementation and always returns true.
* @return bool whether to use custom storage.
*/
public function getUseCustomStorage()
{
return true;
}
/**
* Composes storage field set for session writing.
* @param string $id session id
* @param string $data session data
* @return array storage fields
*/
protected function composeFields($id, $data)
{
$fields = [
'data' => $data,
];
if ($this->writeCallback !== null) {
$fields = array_merge(
$fields,
call_user_func($this->writeCallback, $this)
);
if (!is_string($fields['data'])) {
$_SESSION = $fields['data'];
$fields['data'] = session_encode();
}
}
// ensure 'id' and 'expire' are never affected by [[writeCallback]]
$fields = array_merge($fields, [
'id' => $id,
'expire' => time() + $this->getTimeout(),
]);
return $fields;
}
/**
* Extracts session data from storage field set.
* @param array $fields storage fields.
* @return string session data.
*/
protected function extractData($fields)
{
if ($this->readCallback !== null) {
if (!isset($fields['data'])) {
$fields['data'] = '';
}
$extraData = call_user_func($this->readCallback, $fields);
if (!empty($extraData)) {
session_decode($fields['data']);
$_SESSION = array_merge((array) $_SESSION, (array) $extraData);
return session_encode();
}
return $fields['data'];
}
return isset($fields['data']) ? $fields['data'] : '';
}
}

View File

@@ -0,0 +1,370 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\BaseObject;
use yii\helpers\ArrayHelper;
use yii\helpers\StringHelper;
/**
* MultipartFormDataParser parses content encoded as 'multipart/form-data'.
* This parser provides the fallback for the 'multipart/form-data' processing on non POST requests,
* for example: the one with 'PUT' request method.
*
* In order to enable this parser you should configure [[Request::parsers]] in the following way:
*
* ```php
* return [
* 'components' => [
* 'request' => [
* 'parsers' => [
* 'multipart/form-data' => 'yii\web\MultipartFormDataParser'
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* Method [[parse()]] of this parser automatically populates `$_FILES` with the files parsed from raw body.
*
* > Note: since this is a request parser, it will initialize `$_FILES` values on [[Request::getBodyParams()]].
* Until this method is invoked, `$_FILES` array will remain empty even if there are submitted files in the
* request body. Make sure you have requested body params before any attempt to get uploaded file in case
* you are using this parser.
*
* Usage example:
*
* ```php
* use yii\web\UploadedFile;
*
* $restRequestData = Yii::$app->request->getBodyParams();
* $uploadedFile = UploadedFile::getInstancesByName('photo');
*
* $model = new Item();
* $model->populate($restRequestData);
* copy($uploadedFile->tempName, '/path/to/file/storage/photo.jpg');
* ```
*
* > Note: although this parser fully emulates regular structure of the `$_FILES`, related temporary
* files, which are available via `tmp_name` key, will not be recognized by PHP as uploaded ones.
* Thus functions like `is_uploaded_file()` and `move_uploaded_file()` will fail on them. This also
* means [[UploadedFile::saveAs()]] will fail as well.
*
* @property int $uploadFileMaxCount Maximum upload files count.
* @property int $uploadFileMaxSize Upload file max size in bytes.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.10
*/
class MultipartFormDataParser extends BaseObject implements RequestParserInterface
{
/**
* @var bool whether to parse raw body even for 'POST' request and `$_FILES` already populated.
* By default this option is disabled saving performance for 'POST' requests, which are already
* processed by PHP automatically.
* > Note: if this option is enabled, value of `$_FILES` will be reset on each parse.
* @since 2.0.13
*/
public $force = false;
/**
* @var int upload file max size in bytes.
*/
private $_uploadFileMaxSize;
/**
* @var int maximum upload files count.
*/
private $_uploadFileMaxCount;
/**
* @return int upload file max size in bytes.
*/
public function getUploadFileMaxSize()
{
if ($this->_uploadFileMaxSize === null) {
$this->_uploadFileMaxSize = $this->getByteSize(ini_get('upload_max_filesize'));
}
return $this->_uploadFileMaxSize;
}
/**
* @param int $uploadFileMaxSize upload file max size in bytes.
*/
public function setUploadFileMaxSize($uploadFileMaxSize)
{
$this->_uploadFileMaxSize = $uploadFileMaxSize;
}
/**
* @return int maximum upload files count.
*/
public function getUploadFileMaxCount()
{
if ($this->_uploadFileMaxCount === null) {
$this->_uploadFileMaxCount = ini_get('max_file_uploads');
}
return $this->_uploadFileMaxCount;
}
/**
* @param int $uploadFileMaxCount maximum upload files count.
*/
public function setUploadFileMaxCount($uploadFileMaxCount)
{
$this->_uploadFileMaxCount = $uploadFileMaxCount;
}
/**
* {@inheritdoc}
*/
public function parse($rawBody, $contentType)
{
if (!$this->force) {
if (!empty($_POST) || !empty($_FILES)) {
// normal POST request is parsed by PHP automatically
return $_POST;
}
} else {
$_FILES = [];
}
if (empty($rawBody)) {
return [];
}
if (!preg_match('/boundary=(.*)$/is', $contentType, $matches)) {
return [];
}
$boundary = $matches[1];
$bodyParts = preg_split('/\\R?-+' . preg_quote($boundary, '/') . '/s', $rawBody);
array_pop($bodyParts); // last block always has no data, contains boundary ending like `--`
$bodyParams = [];
$filesCount = 0;
foreach ($bodyParts as $bodyPart) {
if (empty($bodyPart)) {
continue;
}
list($headers, $value) = preg_split('/\\R\\R/', $bodyPart, 2);
$headers = $this->parseHeaders($headers);
if (!isset($headers['content-disposition']['name'])) {
continue;
}
if (isset($headers['content-disposition']['filename'])) {
// file upload:
if ($filesCount >= $this->getUploadFileMaxCount()) {
continue;
}
$fileInfo = [
'name' => $headers['content-disposition']['filename'],
'type' => ArrayHelper::getValue($headers, 'content-type', 'application/octet-stream'),
'size' => StringHelper::byteLength($value),
'error' => UPLOAD_ERR_OK,
'tmp_name' => null,
];
if ($fileInfo['size'] > $this->getUploadFileMaxSize()) {
$fileInfo['error'] = UPLOAD_ERR_INI_SIZE;
} else {
$tmpResource = tmpfile();
if ($tmpResource === false) {
$fileInfo['error'] = UPLOAD_ERR_CANT_WRITE;
} else {
$tmpResourceMetaData = stream_get_meta_data($tmpResource);
$tmpFileName = $tmpResourceMetaData['uri'];
if (empty($tmpFileName)) {
$fileInfo['error'] = UPLOAD_ERR_CANT_WRITE;
@fclose($tmpResource);
} else {
fwrite($tmpResource, $value);
$fileInfo['tmp_name'] = $tmpFileName;
$fileInfo['tmp_resource'] = $tmpResource; // save file resource, otherwise it will be deleted
}
}
}
$this->addFile($_FILES, $headers['content-disposition']['name'], $fileInfo);
$filesCount++;
} else {
// regular parameter:
$this->addValue($bodyParams, $headers['content-disposition']['name'], $value);
}
}
return $bodyParams;
}
/**
* Parses content part headers.
* @param string $headerContent headers source content
* @return array parsed headers.
*/
private function parseHeaders($headerContent)
{
$headers = [];
$headerParts = preg_split('/\\R/s', $headerContent, -1, PREG_SPLIT_NO_EMPTY);
foreach ($headerParts as $headerPart) {
if (strpos($headerPart, ':') === false) {
continue;
}
list($headerName, $headerValue) = explode(':', $headerPart, 2);
$headerName = strtolower(trim($headerName));
$headerValue = trim($headerValue);
if (strpos($headerValue, ';') === false) {
$headers[$headerName] = $headerValue;
} else {
$headers[$headerName] = [];
foreach (explode(';', $headerValue) as $part) {
$part = trim($part);
if (strpos($part, '=') === false) {
$headers[$headerName][] = $part;
} else {
list($name, $value) = explode('=', $part, 2);
$name = strtolower(trim($name));
$value = trim(trim($value), '"');
$headers[$headerName][$name] = $value;
}
}
}
}
return $headers;
}
/**
* Adds value to the array by input name, e.g. `Item[name]`.
* @param array $array array which should store value.
* @param string $name input name specification.
* @param mixed $value value to be added.
*/
private function addValue(&$array, $name, $value)
{
$nameParts = preg_split('/\\]\\[|\\[/s', $name);
$current = &$array;
foreach ($nameParts as $namePart) {
$namePart = trim($namePart, ']');
if ($namePart === '') {
$current[] = [];
$keys = array_keys($current);
$lastKey = array_pop($keys);
$current = &$current[$lastKey];
} else {
if (!isset($current[$namePart])) {
$current[$namePart] = [];
}
$current = &$current[$namePart];
}
}
$current = $value;
}
/**
* Adds file info to the uploaded files array by input name, e.g. `Item[file]`.
* @param array $files array containing uploaded files
* @param string $name input name specification.
* @param array $info file info.
*/
private function addFile(&$files, $name, $info)
{
if (strpos($name, '[') === false) {
$files[$name] = $info;
return;
}
$fileInfoAttributes = [
'name',
'type',
'size',
'error',
'tmp_name',
'tmp_resource',
];
$nameParts = preg_split('/\\]\\[|\\[/s', $name);
$baseName = array_shift($nameParts);
if (!isset($files[$baseName])) {
$files[$baseName] = [];
foreach ($fileInfoAttributes as $attribute) {
$files[$baseName][$attribute] = [];
}
} else {
foreach ($fileInfoAttributes as $attribute) {
$files[$baseName][$attribute] = (array) $files[$baseName][$attribute];
}
}
foreach ($fileInfoAttributes as $attribute) {
if (!isset($info[$attribute])) {
continue;
}
$current = &$files[$baseName][$attribute];
foreach ($nameParts as $namePart) {
$namePart = trim($namePart, ']');
if ($namePart === '') {
$current[] = [];
$lastKey = array_pop(array_keys($current));
$current = &$current[$lastKey];
} else {
if (!isset($current[$namePart])) {
$current[$namePart] = [];
}
$current = &$current[$namePart];
}
}
$current = $info[$attribute];
}
}
/**
* Gets the size in bytes from verbose size representation.
*
* For example: '5K' => 5*1024.
* @param string $verboseSize verbose size representation.
* @return int actual size in bytes.
*/
private function getByteSize($verboseSize)
{
if (empty($verboseSize)) {
return 0;
}
if (is_numeric($verboseSize)) {
return (int) $verboseSize;
}
$sizeUnit = trim($verboseSize, '0123456789');
$size = trim(str_replace($sizeUnit, '', $verboseSize));
if (!is_numeric($size)) {
return 0;
}
switch (strtolower($sizeUnit)) {
case 'kb':
case 'k':
return $size * 1024;
case 'mb':
case 'm':
return $size * 1024 * 1024;
case 'gb':
case 'g':
return $size * 1024 * 1024 * 1024;
default:
return 0;
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* NotAcceptableHttpException represents a "Not Acceptable" HTTP exception with status code 406.
*
* Use this exception when the client requests a Content-Type that your
* application cannot return. Note that, according to the HTTP 1.1 specification,
* you are not required to respond with this status code in this situation.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.6
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class NotAcceptableHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(406, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* NotFoundHttpException represents a "Not Found" HTTP exception with status code 404.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.4
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class NotFoundHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(404, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* RangeNotSatisfiableHttpException represents an exception caused by an improper request of the end-user.
* This exception thrown when the requested range is not satisfiable: the client asked for a portion of
* the file (byte serving), but the server cannot supply that portion. For example, if the client asked for
* a part of the file that lies beyond the end of the file.
*
* Throwing an RangeNotSatisfiableHttpException like in the following example will result in the error page
* with error 416 to be displayed.
*
* @author Zalatov Alexander <CaHbKa.Z@gmail.com>
*
* @since 2.0.11
*/
class RangeNotSatisfiableHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(416, $message, $code, $previous);
}
}

1717
vendor/yiisoft/yii2/web/Request.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* Interface for classes that parse the raw request body into a parameters array.
*
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
interface RequestParserInterface
{
/**
* Parses a HTTP request body.
* @param string $rawBody the raw HTTP request body.
* @param string $contentType the content type specified for the request body.
* @return array parameters parsed from the request body
*/
public function parse($rawBody, $contentType);
}

1066
vendor/yiisoft/yii2/web/Response.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* ResponseFormatterInterface specifies the interface needed to format a response before it is sent out.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface ResponseFormatterInterface
{
/**
* Formats the specified response.
* @param Response $response the response to be formatted.
*/
public function format($response);
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* ServerErrorHttpException represents an "Internal Server Error" HTTP exception with status code 500.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.6.1
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ServerErrorHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(500, $message, $code, $previous);
}
}

983
vendor/yiisoft/yii2/web/Session.php vendored Normal file
View File

@@ -0,0 +1,983 @@
<?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\Component;
use yii\base\InvalidArgumentException;
use yii\base\InvalidConfigException;
/**
* Session provides session data management and the related configurations.
*
* Session is a Web application component that can be accessed via `Yii::$app->session`.
*
* To start the session, call [[open()]]; To complete and send out session data, call [[close()]];
* To destroy the session, call [[destroy()]].
*
* Session can be used like an array to set and get session data. For example,
*
* ```php
* $session = new Session;
* $session->open();
* $value1 = $session['name1']; // get session variable 'name1'
* $value2 = $session['name2']; // get session variable 'name2'
* foreach ($session as $name => $value) // traverse all session variables
* $session['name3'] = $value3; // set session variable 'name3'
* ```
*
* Session can be extended to support customized session storage.
* To do so, override [[useCustomStorage]] so that it returns true, and
* override these methods with the actual logic about using custom storage:
* [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
* [[destroySession()]] and [[gcSession()]].
*
* Session also supports a special type of session data, called *flash messages*.
* A flash message is available only in the current request and the next request.
* After that, it will be deleted automatically. Flash messages are particularly
* useful for displaying confirmation messages. To use flash messages, simply
* call methods such as [[setFlash()]], [[getFlash()]].
*
* For more details and usage information on Session, see the [guide article on sessions](guide:runtime-sessions-cookies).
*
* @property array $allFlashes Flash messages (key => message or key => [message1, message2]). This property
* is read-only.
* @property string $cacheLimiter Current cache limiter. This property is read-only.
* @property array $cookieParams The session cookie parameters. This property is read-only.
* @property int $count The number of session variables. This property is read-only.
* @property string $flash The key identifying the flash message. Note that flash messages and normal session
* variables share the same name space. If you have a normal session variable using the same name, its value will
* be overwritten by this method. This property is write-only.
* @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is
* started on every session initialization, defaults to 1 meaning 1% chance.
* @property bool $hasSessionId Whether the current request has sent the session ID.
* @property string $id The current session ID.
* @property bool $isActive Whether the session has started. This property is read-only.
* @property SessionIterator $iterator An iterator for traversing the session variables. This property is
* read-only.
* @property string $name The current session name.
* @property string $savePath The current session save path, defaults to '/tmp'.
* @property int $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up. The
* default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
* @property bool|null $useCookies The value indicating whether cookies should be used to store session IDs.
* @property bool $useCustomStorage Whether to use custom storage. This property is read-only.
* @property bool $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to
* false.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable
{
/**
* @var string the name of the session variable that stores the flash message data.
*/
public $flashParam = '__flash';
/**
* @var \SessionHandlerInterface|array an object implementing the SessionHandlerInterface or a configuration array. If set, will be used to provide persistency instead of build-in methods.
*/
public $handler;
/**
* @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function
* Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httponly'
* @see http://www.php.net/manual/en/function.session-set-cookie-params.php
*/
private $_cookieParams = ['httponly' => true];
/**
* @var $frozenSessionData array|null is used for saving session between recreations due to session parameters update.
*/
private $frozenSessionData;
/**
* Initializes the application component.
* This method is required by IApplicationComponent and is invoked by application.
*/
public function init()
{
parent::init();
register_shutdown_function([$this, 'close']);
if ($this->getIsActive()) {
Yii::warning('Session is already started', __METHOD__);
$this->updateFlashCounters();
}
}
/**
* Returns a value indicating whether to use custom session storage.
* This method should be overridden to return true by child classes that implement custom session storage.
* To implement custom session storage, override these methods: [[openSession()]], [[closeSession()]],
* [[readSession()]], [[writeSession()]], [[destroySession()]] and [[gcSession()]].
* @return bool whether to use custom storage.
*/
public function getUseCustomStorage()
{
return false;
}
/**
* Starts the session.
*/
public function open()
{
if ($this->getIsActive()) {
return;
}
$this->registerSessionHandler();
$this->setCookieParamsInternal();
YII_DEBUG ? session_start() : @session_start();
if ($this->getIsActive()) {
Yii::info('Session started', __METHOD__);
$this->updateFlashCounters();
} else {
$error = error_get_last();
$message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
Yii::error($message, __METHOD__);
}
}
/**
* Registers session handler.
* @throws \yii\base\InvalidConfigException
*/
protected function registerSessionHandler()
{
if ($this->handler !== null) {
if (!is_object($this->handler)) {
$this->handler = Yii::createObject($this->handler);
}
if (!$this->handler instanceof \SessionHandlerInterface) {
throw new InvalidConfigException('"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.');
}
YII_DEBUG ? session_set_save_handler($this->handler, false) : @session_set_save_handler($this->handler, false);
} elseif ($this->getUseCustomStorage()) {
if (YII_DEBUG) {
session_set_save_handler(
[$this, 'openSession'],
[$this, 'closeSession'],
[$this, 'readSession'],
[$this, 'writeSession'],
[$this, 'destroySession'],
[$this, 'gcSession']
);
} else {
@session_set_save_handler(
[$this, 'openSession'],
[$this, 'closeSession'],
[$this, 'readSession'],
[$this, 'writeSession'],
[$this, 'destroySession'],
[$this, 'gcSession']
);
}
}
}
/**
* Ends the current session and store session data.
*/
public function close()
{
if ($this->getIsActive()) {
YII_DEBUG ? session_write_close() : @session_write_close();
}
}
/**
* Frees all session variables and destroys all data registered to a session.
*
* This method has no effect when session is not [[getIsActive()|active]].
* Make sure to call [[open()]] before calling it.
* @see open()
* @see isActive
*/
public function destroy()
{
if ($this->getIsActive()) {
$sessionId = session_id();
$this->close();
$this->setId($sessionId);
$this->open();
session_unset();
session_destroy();
$this->setId($sessionId);
}
}
/**
* @return bool whether the session has started
*/
public function getIsActive()
{
return session_status() === PHP_SESSION_ACTIVE;
}
private $_hasSessionId;
/**
* Returns a value indicating whether the current request has sent the session ID.
* The default implementation will check cookie and $_GET using the session name.
* If you send session ID via other ways, you may need to override this method
* or call [[setHasSessionId()]] to explicitly set whether the session ID is sent.
* @return bool whether the current request has sent the session ID.
*/
public function getHasSessionId()
{
if ($this->_hasSessionId === null) {
$name = $this->getName();
$request = Yii::$app->getRequest();
if (!empty($_COOKIE[$name]) && ini_get('session.use_cookies')) {
$this->_hasSessionId = true;
} elseif (!ini_get('session.use_only_cookies') && ini_get('session.use_trans_sid')) {
$this->_hasSessionId = $request->get($name) != '';
} else {
$this->_hasSessionId = false;
}
}
return $this->_hasSessionId;
}
/**
* Sets the value indicating whether the current request has sent the session ID.
* This method is provided so that you can override the default way of determining
* whether the session ID is sent.
* @param bool $value whether the current request has sent the session ID.
*/
public function setHasSessionId($value)
{
$this->_hasSessionId = $value;
}
/**
* Gets the session ID.
* This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
* @return string the current session ID
*/
public function getId()
{
return session_id();
}
/**
* Sets the session ID.
* This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
* @param string $value the session ID for the current session
*/
public function setId($value)
{
session_id($value);
}
/**
* Updates the current session ID with a newly generated one.
*
* Please refer to <http://php.net/session_regenerate_id> for more details.
*
* This method has no effect when session is not [[getIsActive()|active]].
* Make sure to call [[open()]] before calling it.
*
* @param bool $deleteOldSession Whether to delete the old associated session file or not.
* @see open()
* @see isActive
*/
public function regenerateID($deleteOldSession = false)
{
if ($this->getIsActive()) {
// add @ to inhibit possible warning due to race condition
// https://github.com/yiisoft/yii2/pull/1812
if (YII_DEBUG && !headers_sent()) {
session_regenerate_id($deleteOldSession);
} else {
@session_regenerate_id($deleteOldSession);
}
}
}
/**
* Gets the name of the current session.
* This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
* @return string the current session name
*/
public function getName()
{
return session_name();
}
/**
* Sets the name for the current session.
* This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
* @param string $value the session name for the current session, must be an alphanumeric string.
* It defaults to "PHPSESSID".
*/
public function setName($value)
{
$this->freeze();
session_name($value);
$this->unfreeze();
}
/**
* Gets the current session save path.
* This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
* @return string the current session save path, defaults to '/tmp'.
*/
public function getSavePath()
{
return session_save_path();
}
/**
* Sets the current session save path.
* This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
* @param string $value the current session save path. This can be either a directory name or a [path alias](guide:concept-aliases).
* @throws InvalidArgumentException if the path is not a valid directory
*/
public function setSavePath($value)
{
$path = Yii::getAlias($value);
if (is_dir($path)) {
session_save_path($path);
} else {
throw new InvalidArgumentException("Session save path is not a valid directory: $value");
}
}
/**
* @return array the session cookie parameters.
* @see http://php.net/manual/en/function.session-get-cookie-params.php
*/
public function getCookieParams()
{
return array_merge(session_get_cookie_params(), array_change_key_case($this->_cookieParams));
}
/**
* Sets the session cookie parameters.
* The cookie parameters passed to this method will be merged with the result
* of `session_get_cookie_params()`.
* @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httponly`.
* @throws InvalidArgumentException if the parameters are incomplete.
* @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
*/
public function setCookieParams(array $value)
{
$this->_cookieParams = $value;
}
/**
* Sets the session cookie parameters.
* This method is called by [[open()]] when it is about to open the session.
* @throws InvalidArgumentException if the parameters are incomplete.
* @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
*/
private function setCookieParamsInternal()
{
$data = $this->getCookieParams();
if (isset($data['lifetime'], $data['path'], $data['domain'], $data['secure'], $data['httponly'])) {
session_set_cookie_params($data['lifetime'], $data['path'], $data['domain'], $data['secure'], $data['httponly']);
} else {
throw new InvalidArgumentException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httponly.');
}
}
/**
* Returns the value indicating whether cookies should be used to store session IDs.
* @return bool|null the value indicating whether cookies should be used to store session IDs.
* @see setUseCookies()
*/
public function getUseCookies()
{
if (ini_get('session.use_cookies') === '0') {
return false;
} elseif (ini_get('session.use_only_cookies') === '1') {
return true;
}
return null;
}
/**
* Sets the value indicating whether cookies should be used to store session IDs.
*
* Three states are possible:
*
* - true: cookies and only cookies will be used to store session IDs.
* - false: cookies will not be used to store session IDs.
* - null: if possible, cookies will be used to store session IDs; if not, other mechanisms will be used (e.g. GET parameter)
*
* @param bool|null $value the value indicating whether cookies should be used to store session IDs.
*/
public function setUseCookies($value)
{
$this->freeze();
if ($value === false) {
ini_set('session.use_cookies', '0');
ini_set('session.use_only_cookies', '0');
} elseif ($value === true) {
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '1');
} else {
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '0');
}
$this->unfreeze();
}
/**
* @return float the probability (percentage) that the GC (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
*/
public function getGCProbability()
{
return (float) (ini_get('session.gc_probability') / ini_get('session.gc_divisor') * 100);
}
/**
* @param float $value the probability (percentage) that the GC (garbage collection) process is started on every session initialization.
* @throws InvalidArgumentException if the value is not between 0 and 100.
*/
public function setGCProbability($value)
{
$this->freeze();
if ($value >= 0 && $value <= 100) {
// percent * 21474837 / 2147483647 ≈ percent * 0.01
ini_set('session.gc_probability', floor($value * 21474836.47));
ini_set('session.gc_divisor', 2147483647);
} else {
throw new InvalidArgumentException('GCProbability must be a value between 0 and 100.');
}
$this->unfreeze();
}
/**
* @return bool whether transparent sid support is enabled or not, defaults to false.
*/
public function getUseTransparentSessionID()
{
return ini_get('session.use_trans_sid') == 1;
}
/**
* @param bool $value whether transparent sid support is enabled or not.
*/
public function setUseTransparentSessionID($value)
{
$this->freeze();
ini_set('session.use_trans_sid', $value ? '1' : '0');
$this->unfreeze();
}
/**
* @return int the number of seconds after which data will be seen as 'garbage' and cleaned up.
* The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
*/
public function getTimeout()
{
return (int) ini_get('session.gc_maxlifetime');
}
/**
* @param int $value the number of seconds after which data will be seen as 'garbage' and cleaned up
*/
public function setTimeout($value)
{
$this->freeze();
ini_set('session.gc_maxlifetime', $value);
$this->unfreeze();
}
/**
* Session open handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @param string $savePath session save path
* @param string $sessionName session name
* @return bool whether session is opened successfully
*/
public function openSession($savePath, $sessionName)
{
return true;
}
/**
* Session close handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @return bool whether session is closed successfully
*/
public function closeSession()
{
return true;
}
/**
* Session read handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @param string $id session ID
* @return string the session data
*/
public function readSession($id)
{
return '';
}
/**
* Session write handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @param string $id session ID
* @param string $data session data
* @return bool whether session write is successful
*/
public function writeSession($id, $data)
{
return true;
}
/**
* Session destroy handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @param string $id session ID
* @return bool whether session is destroyed successfully
*/
public function destroySession($id)
{
return true;
}
/**
* Session GC (garbage collection) handler.
* This method should be overridden if [[useCustomStorage]] returns true.
* @internal Do not call this method directly.
* @param int $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
* @return bool whether session is GCed successfully
*/
public function gcSession($maxLifetime)
{
return true;
}
/**
* Returns an iterator for traversing the session variables.
* This method is required by the interface [[\IteratorAggregate]].
* @return SessionIterator an iterator for traversing the session variables.
*/
public function getIterator()
{
$this->open();
return new SessionIterator();
}
/**
* Returns the number of items in the session.
* @return int the number of session variables
*/
public function getCount()
{
$this->open();
return count($_SESSION);
}
/**
* Returns the number of items in the session.
* This method is required by [[\Countable]] interface.
* @return int number of items in the session.
*/
public function count()
{
return $this->getCount();
}
/**
* Returns the session variable value with the session variable name.
* If the session variable does not exist, the `$defaultValue` will be returned.
* @param string $key the session variable name
* @param mixed $defaultValue the default value to be returned when the session variable does not exist.
* @return mixed the session variable value, or $defaultValue if the session variable does not exist.
*/
public function get($key, $defaultValue = null)
{
$this->open();
return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
}
/**
* Adds a session variable.
* If the specified name already exists, the old value will be overwritten.
* @param string $key session variable name
* @param mixed $value session variable value
*/
public function set($key, $value)
{
$this->open();
$_SESSION[$key] = $value;
}
/**
* Removes a session variable.
* @param string $key the name of the session variable to be removed
* @return mixed the removed value, null if no such session variable.
*/
public function remove($key)
{
$this->open();
if (isset($_SESSION[$key])) {
$value = $_SESSION[$key];
unset($_SESSION[$key]);
return $value;
}
return null;
}
/**
* Removes all session variables.
*/
public function removeAll()
{
$this->open();
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
}
/**
* @param mixed $key session variable name
* @return bool whether there is the named session variable
*/
public function has($key)
{
$this->open();
return isset($_SESSION[$key]);
}
/**
* Updates the counters for flash messages and removes outdated flash messages.
* This method should only be called once in [[init()]].
*/
protected function updateFlashCounters()
{
$counters = $this->get($this->flashParam, []);
if (is_array($counters)) {
foreach ($counters as $key => $count) {
if ($count > 0) {
unset($counters[$key], $_SESSION[$key]);
} elseif ($count == 0) {
$counters[$key]++;
}
}
$_SESSION[$this->flashParam] = $counters;
} else {
// fix the unexpected problem that flashParam doesn't return an array
unset($_SESSION[$this->flashParam]);
}
}
/**
* Returns a flash message.
* @param string $key the key identifying the flash message
* @param mixed $defaultValue value to be returned if the flash message does not exist.
* @param bool $delete whether to delete this flash message right after this method is called.
* If false, the flash message will be automatically deleted in the next request.
* @return mixed the flash message or an array of messages if addFlash was used
* @see setFlash()
* @see addFlash()
* @see hasFlash()
* @see getAllFlashes()
* @see removeFlash()
*/
public function getFlash($key, $defaultValue = null, $delete = false)
{
$counters = $this->get($this->flashParam, []);
if (isset($counters[$key])) {
$value = $this->get($key, $defaultValue);
if ($delete) {
$this->removeFlash($key);
} elseif ($counters[$key] < 0) {
// mark for deletion in the next request
$counters[$key] = 1;
$_SESSION[$this->flashParam] = $counters;
}
return $value;
}
return $defaultValue;
}
/**
* Returns all flash messages.
*
* You may use this method to display all the flash messages in a view file:
*
* ```php
* <?php
* foreach (Yii::$app->session->getAllFlashes() as $key => $message) {
* echo '<div class="alert alert-' . $key . '">' . $message . '</div>';
* } ?>
* ```
*
* With the above code you can use the [bootstrap alert][] classes such as `success`, `info`, `danger`
* as the flash message key to influence the color of the div.
*
* Note that if you use [[addFlash()]], `$message` will be an array, and you will have to adjust the above code.
*
* [bootstrap alert]: http://getbootstrap.com/components/#alerts
*
* @param bool $delete whether to delete the flash messages right after this method is called.
* If false, the flash messages will be automatically deleted in the next request.
* @return array flash messages (key => message or key => [message1, message2]).
* @see setFlash()
* @see addFlash()
* @see getFlash()
* @see hasFlash()
* @see removeFlash()
*/
public function getAllFlashes($delete = false)
{
$counters = $this->get($this->flashParam, []);
$flashes = [];
foreach (array_keys($counters) as $key) {
if (array_key_exists($key, $_SESSION)) {
$flashes[$key] = $_SESSION[$key];
if ($delete) {
unset($counters[$key], $_SESSION[$key]);
} elseif ($counters[$key] < 0) {
// mark for deletion in the next request
$counters[$key] = 1;
}
} else {
unset($counters[$key]);
}
}
$_SESSION[$this->flashParam] = $counters;
return $flashes;
}
/**
* Sets a flash message.
* A flash message will be automatically deleted after it is accessed in a request and the deletion will happen
* in the next request.
* If there is already an existing flash message with the same key, it will be overwritten by the new one.
* @param string $key the key identifying the flash message. Note that flash messages
* and normal session variables share the same name space. If you have a normal
* session variable using the same name, its value will be overwritten by this method.
* @param mixed $value flash message
* @param bool $removeAfterAccess whether the flash message should be automatically removed only if
* it is accessed. If false, the flash message will be automatically removed after the next request,
* regardless if it is accessed or not. If true (default value), the flash message will remain until after
* it is accessed.
* @see getFlash()
* @see addFlash()
* @see removeFlash()
*/
public function setFlash($key, $value = true, $removeAfterAccess = true)
{
$counters = $this->get($this->flashParam, []);
$counters[$key] = $removeAfterAccess ? -1 : 0;
$_SESSION[$key] = $value;
$_SESSION[$this->flashParam] = $counters;
}
/**
* Adds a flash message.
* If there are existing flash messages with the same key, the new one will be appended to the existing message array.
* @param string $key the key identifying the flash message.
* @param mixed $value flash message
* @param bool $removeAfterAccess whether the flash message should be automatically removed only if
* it is accessed. If false, the flash message will be automatically removed after the next request,
* regardless if it is accessed or not. If true (default value), the flash message will remain until after
* it is accessed.
* @see getFlash()
* @see setFlash()
* @see removeFlash()
*/
public function addFlash($key, $value = true, $removeAfterAccess = true)
{
$counters = $this->get($this->flashParam, []);
$counters[$key] = $removeAfterAccess ? -1 : 0;
$_SESSION[$this->flashParam] = $counters;
if (empty($_SESSION[$key])) {
$_SESSION[$key] = [$value];
} else {
if (is_array($_SESSION[$key])) {
$_SESSION[$key][] = $value;
} else {
$_SESSION[$key] = [$_SESSION[$key], $value];
}
}
}
/**
* Removes a flash message.
* @param string $key the key identifying the flash message. Note that flash messages
* and normal session variables share the same name space. If you have a normal
* session variable using the same name, it will be removed by this method.
* @return mixed the removed flash message. Null if the flash message does not exist.
* @see getFlash()
* @see setFlash()
* @see addFlash()
* @see removeAllFlashes()
*/
public function removeFlash($key)
{
$counters = $this->get($this->flashParam, []);
$value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null;
unset($counters[$key], $_SESSION[$key]);
$_SESSION[$this->flashParam] = $counters;
return $value;
}
/**
* Removes all flash messages.
* Note that flash messages and normal session variables share the same name space.
* If you have a normal session variable using the same name, it will be removed
* by this method.
* @see getFlash()
* @see setFlash()
* @see addFlash()
* @see removeFlash()
*/
public function removeAllFlashes()
{
$counters = $this->get($this->flashParam, []);
foreach (array_keys($counters) as $key) {
unset($_SESSION[$key]);
}
unset($_SESSION[$this->flashParam]);
}
/**
* Returns a value indicating whether there are flash messages associated with the specified key.
* @param string $key key identifying the flash message type
* @return bool whether any flash messages exist under specified key
*/
public function hasFlash($key)
{
return $this->getFlash($key) !== null;
}
/**
* This method is required by the interface [[\ArrayAccess]].
* @param mixed $offset the offset to check on
* @return bool
*/
public function offsetExists($offset)
{
$this->open();
return isset($_SESSION[$offset]);
}
/**
* This method is required by the interface [[\ArrayAccess]].
* @param int $offset the offset to retrieve element.
* @return mixed the element at the offset, null if no element is found at the offset
*/
public function offsetGet($offset)
{
$this->open();
return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
}
/**
* This method is required by the interface [[\ArrayAccess]].
* @param int $offset the offset to set element
* @param mixed $item the element value
*/
public function offsetSet($offset, $item)
{
$this->open();
$_SESSION[$offset] = $item;
}
/**
* This method is required by the interface [[\ArrayAccess]].
* @param mixed $offset the offset to unset element
*/
public function offsetUnset($offset)
{
$this->open();
unset($_SESSION[$offset]);
}
/**
* If session is started it's not possible to edit session ini settings. In PHP7.2+ it throws exception.
* This function saves session data to temporary variable and stop session.
* @since 2.0.14
*/
protected function freeze()
{
if ($this->getIsActive()) {
if (isset($_SESSION)) {
$this->frozenSessionData = $_SESSION;
}
$this->close();
Yii::info('Session frozen', __METHOD__);
}
}
/**
* Starts session and restores data from temporary variable
* @since 2.0.14
*/
protected function unfreeze()
{
if (null !== $this->frozenSessionData) {
YII_DEBUG ? session_start() : @session_start();
if ($this->getIsActive()) {
Yii::info('Session unfrozen', __METHOD__);
} else {
$error = error_get_last();
$message = isset($error['message']) ? $error['message'] : 'Failed to unfreeze session.';
Yii::error($message, __METHOD__);
}
$_SESSION = $this->frozenSessionData;
$this->frozenSessionData = null;
}
}
/**
* Set cache limiter
*
* @param string $cacheLimiter
* @since 2.0.14
*/
public function setCacheLimiter($cacheLimiter)
{
$this->freeze();
session_cache_limiter($cacheLimiter);
$this->unfreeze();
}
/**
* Returns current cache limiter
*
* @return string current cache limiter
* @since 2.0.14
*/
public function getCacheLimiter()
{
return session_cache_limiter();
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* SessionIterator implements an [[\Iterator|iterator]] for traversing session variables managed by [[Session]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class SessionIterator implements \Iterator
{
/**
* @var array list of keys in the map
*/
private $_keys;
/**
* @var mixed current key
*/
private $_key;
/**
* Constructor.
*/
public function __construct()
{
$this->_keys = array_keys($_SESSION);
}
/**
* Rewinds internal array pointer.
* This method is required by the interface [[\Iterator]].
*/
public function rewind()
{
$this->_key = reset($this->_keys);
}
/**
* Returns the key of the current array element.
* This method is required by the interface [[\Iterator]].
* @return mixed the key of the current array element
*/
public function key()
{
return $this->_key;
}
/**
* Returns the current array element.
* This method is required by the interface [[\Iterator]].
* @return mixed the current array element
*/
public function current()
{
return isset($_SESSION[$this->_key]) ? $_SESSION[$this->_key] : null;
}
/**
* Moves the internal pointer to the next array element.
* This method is required by the interface [[\Iterator]].
*/
public function next()
{
do {
$this->_key = next($this->_keys);
} while (!isset($_SESSION[$this->_key]) && $this->_key !== false);
}
/**
* Returns whether there is an element at current position.
* This method is required by the interface [[\Iterator]].
* @return bool
*/
public function valid()
{
return $this->_key !== false;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* TooManyRequestsHttpException represents a "Too Many Requests" HTTP exception with status code 429.
*
* Use this exception to indicate that a client has made too many requests in a
* given period of time. For example, you would throw this exception when
* 'throttling' an API user.
*
* @see https://tools.ietf.org/html/rfc6585#section-4
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class TooManyRequestsHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(429, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UnauthorizedHttpException represents an "Unauthorized" HTTP exception with status code 401.
*
* Use this exception to indicate that a client needs to authenticate via WWW-Authenticate header
* to perform the requested action.
*
* If the client is already authenticated and is simply not allowed to
* perform the action, consider using a 403 [[ForbiddenHttpException]]
* or 404 [[NotFoundHttpException]] instead.
*
* @link https://tools.ietf.org/html/rfc7235#section-3.1
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class UnauthorizedHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(401, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UnprocessableEntityHttpException represents an "Unprocessable Entity" HTTP
* exception with status code 422.
*
* Use this exception to inform that the server understands the content type of
* the request entity and the syntax of that request entity is correct but the server
* was unable to process the contained instructions. For example, to return form
* validation errors.
*
* @link http://www.webdav.org/specs/rfc2518.html#STATUS_422
* @author Jan Silva <janfrs3@gmail.com>
* @since 2.0.7
*/
class UnprocessableEntityHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(422, $message, $code, $previous);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UnsupportedMediaTypeHttpException represents an "Unsupported Media Type" HTTP exception with status code 415.
*
* Use this exception when the client sends data in a format that your
* application does not understand. For example, you would throw this exception
* if the client POSTs XML data to an action or controller that only accepts
* JSON.
*
* @see https://tools.ietf.org/html/rfc7231#section-6.5.13
* @author Dan Schmidt <danschmidt5189@gmail.com>
* @since 2.0
*/
class UnsupportedMediaTypeHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param int $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(415, $message, $code, $previous);
}
}

243
vendor/yiisoft/yii2/web/UploadedFile.php vendored Normal file
View File

@@ -0,0 +1,243 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\BaseObject;
use yii\helpers\Html;
/**
* UploadedFile represents the information for an uploaded file.
*
* You can call [[getInstance()]] to retrieve the instance of an uploaded file,
* and then use [[saveAs()]] to save it on the server.
* You may also query other information about the file, including [[name]],
* [[tempName]], [[type]], [[size]] and [[error]].
*
* For more details and usage information on UploadedFile, see the [guide article on handling uploads](guide:input-file-upload).
*
* @property string $baseName Original file base name. This property is read-only.
* @property string $extension File extension. This property is read-only.
* @property bool $hasError Whether there is an error with the uploaded file. Check [[error]] for detailed
* error code information. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UploadedFile extends BaseObject
{
/**
* @var string the original name of the file being uploaded
*/
public $name;
/**
* @var string the path of the uploaded file on the server.
* Note, this is a temporary file which will be automatically deleted by PHP
* after the current request is processed.
*/
public $tempName;
/**
* @var string the MIME-type of the uploaded file (such as "image/gif").
* Since this MIME type is not checked on the server-side, do not take this value for granted.
* Instead, use [[\yii\helpers\FileHelper::getMimeType()]] to determine the exact MIME type.
*/
public $type;
/**
* @var int the actual size of the uploaded file in bytes
*/
public $size;
/**
* @var int an error code describing the status of this file uploading.
* @see http://www.php.net/manual/en/features.file-upload.errors.php
*/
public $error;
private static $_files;
/**
* String output.
* This is PHP magic method that returns string representation of an object.
* The implementation here returns the uploaded file's name.
* @return string the string representation of the object
*/
public function __toString()
{
return $this->name;
}
/**
* Returns an uploaded file for the given model attribute.
* The file should be uploaded using [[\yii\widgets\ActiveField::fileInput()]].
* @param \yii\base\Model $model the data model
* @param string $attribute the attribute name. The attribute name may contain array indexes.
* For example, '[1]file' for tabular file uploading; and 'file[1]' for an element in a file array.
* @return UploadedFile the instance of the uploaded file.
* Null is returned if no file is uploaded for the specified model attribute.
* @see getInstanceByName()
*/
public static function getInstance($model, $attribute)
{
$name = Html::getInputName($model, $attribute);
return static::getInstanceByName($name);
}
/**
* Returns all uploaded files for the given model attribute.
* @param \yii\base\Model $model the data model
* @param string $attribute the attribute name. The attribute name may contain array indexes
* for tabular file uploading, e.g. '[1]file'.
* @return UploadedFile[] array of UploadedFile objects.
* Empty array is returned if no available file was found for the given attribute.
*/
public static function getInstances($model, $attribute)
{
$name = Html::getInputName($model, $attribute);
return static::getInstancesByName($name);
}
/**
* Returns an uploaded file according to the given file input name.
* The name can be a plain string or a string like an array element (e.g. 'Post[imageFile]', or 'Post[0][imageFile]').
* @param string $name the name of the file input field.
* @return null|UploadedFile the instance of the uploaded file.
* Null is returned if no file is uploaded for the specified name.
*/
public static function getInstanceByName($name)
{
$files = self::loadFiles();
return isset($files[$name]) ? new static($files[$name]) : null;
}
/**
* Returns an array of uploaded files corresponding to the specified file input name.
* This is mainly used when multiple files were uploaded and saved as 'files[0]', 'files[1]',
* 'files[n]'..., and you can retrieve them all by passing 'files' as the name.
* @param string $name the name of the array of files
* @return UploadedFile[] the array of UploadedFile objects. Empty array is returned
* if no adequate upload was found. Please note that this array will contain
* all files from all sub-arrays regardless how deeply nested they are.
*/
public static function getInstancesByName($name)
{
$files = self::loadFiles();
if (isset($files[$name])) {
return [new static($files[$name])];
}
$results = [];
foreach ($files as $key => $file) {
if (strpos($key, "{$name}[") === 0) {
$results[] = new static($file);
}
}
return $results;
}
/**
* Cleans up the loaded UploadedFile instances.
* This method is mainly used by test scripts to set up a fixture.
*/
public static function reset()
{
self::$_files = null;
}
/**
* Saves the uploaded file.
* Note that this method uses php's move_uploaded_file() method. If the target file `$file`
* already exists, it will be overwritten.
* @param string $file the file path used to save the uploaded file
* @param bool $deleteTempFile whether to delete the temporary file after saving.
* If true, you will not be able to save the uploaded file again in the current request.
* @return bool true whether the file is saved successfully
* @see error
*/
public function saveAs($file, $deleteTempFile = true)
{
if ($this->error == UPLOAD_ERR_OK) {
if ($deleteTempFile) {
return move_uploaded_file($this->tempName, $file);
} elseif (is_uploaded_file($this->tempName)) {
return copy($this->tempName, $file);
}
}
return false;
}
/**
* @return string original file base name
*/
public function getBaseName()
{
// https://github.com/yiisoft/yii2/issues/11012
$pathInfo = pathinfo('_' . $this->name, PATHINFO_FILENAME);
return mb_substr($pathInfo, 1, mb_strlen($pathInfo, '8bit'), '8bit');
}
/**
* @return string file extension
*/
public function getExtension()
{
return strtolower(pathinfo($this->name, PATHINFO_EXTENSION));
}
/**
* @return bool whether there is an error with the uploaded file.
* Check [[error]] for detailed error code information.
*/
public function getHasError()
{
return $this->error != UPLOAD_ERR_OK;
}
/**
* Creates UploadedFile instances from $_FILE.
* @return array the UploadedFile instances
*/
private static function loadFiles()
{
if (self::$_files === null) {
self::$_files = [];
if (isset($_FILES) && is_array($_FILES)) {
foreach ($_FILES as $class => $info) {
self::loadFilesRecursive($class, $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']);
}
}
}
return self::$_files;
}
/**
* Creates UploadedFile instances from $_FILE recursively.
* @param string $key key for identifying uploaded file: class name and sub-array indexes
* @param mixed $names file names provided by PHP
* @param mixed $tempNames temporary file names provided by PHP
* @param mixed $types file types provided by PHP
* @param mixed $sizes file sizes provided by PHP
* @param mixed $errors uploading issues provided by PHP
*/
private static function loadFilesRecursive($key, $names, $tempNames, $types, $sizes, $errors)
{
if (is_array($names)) {
foreach ($names as $i => $name) {
self::loadFilesRecursive($key . '[' . $i . ']', $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]);
}
} elseif ((int) $errors !== UPLOAD_ERR_NO_FILE) {
self::$_files[$key] = [
'name' => $names,
'tempName' => $tempNames,
'type' => $types,
'size' => $sizes,
'error' => $errors,
];
}
}
}

648
vendor/yiisoft/yii2/web/UrlManager.php vendored Normal file
View File

@@ -0,0 +1,648 @@
<?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\Component;
use yii\base\InvalidConfigException;
use yii\caching\CacheInterface;
use yii\helpers\Url;
/**
* UrlManager handles HTTP request parsing and creation of URLs based on a set of rules.
*
* UrlManager is configured as an application component in [[\yii\base\Application]] by default.
* You can access that instance via `Yii::$app->urlManager`.
*
* You can modify its configuration by adding an array to your application config under `components`
* as it is shown in the following example:
*
* ```php
* 'urlManager' => [
* 'enablePrettyUrl' => true,
* 'rules' => [
* // your rules go here
* ],
* // ...
* ]
* ```
*
* Rules are classes implementing the [[UrlRuleInterface]], by default that is [[UrlRule]].
* For nesting rules, there is also a [[GroupUrlRule]] class.
*
* For more details and usage information on UrlManager, see the [guide article on routing](guide:runtime-routing).
*
* @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend to created URLs.
* @property string $hostInfo The host info (e.g. `http://www.example.com`) that is used by
* [[createAbsoluteUrl()]] to prepend to created URLs.
* @property string $scriptUrl The entry script URL that is used by [[createUrl()]] to prepend to created
* URLs.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UrlManager extends Component
{
/**
* @var bool whether to enable pretty URLs. Instead of putting all parameters in the query
* string part of a URL, pretty URLs allow using path info to represent some of the parameters
* and can thus produce more user-friendly URLs, such as "/news/Yii-is-released", instead of
* "/index.php?r=news%2Fview&id=100".
*/
public $enablePrettyUrl = false;
/**
* @var bool whether to enable strict parsing. If strict parsing is enabled, the incoming
* requested URL must match at least one of the [[rules]] in order to be treated as a valid request.
* Otherwise, the path info part of the request will be treated as the requested route.
* This property is used only when [[enablePrettyUrl]] is `true`.
*/
public $enableStrictParsing = false;
/**
* @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is `true`.
* This property is used only if [[enablePrettyUrl]] is `true`. Each element in the array
* is the configuration array for creating a single URL rule. The configuration will
* be merged with [[ruleConfig]] first before it is used for creating the rule object.
*
* A special shortcut format can be used if a rule only specifies [[UrlRule::pattern|pattern]]
* and [[UrlRule::route|route]]: `'pattern' => 'route'`. That is, instead of using a configuration
* array, one can use the key to represent the pattern and the value the corresponding route.
* For example, `'post/<id:\d+>' => 'post/view'`.
*
* For RESTful routing the mentioned shortcut format also allows you to specify the
* [[UrlRule::verb|HTTP verb]] that the rule should apply for.
* You can do that by prepending it to the pattern, separated by space.
* For example, `'PUT post/<id:\d+>' => 'post/update'`.
* You may specify multiple verbs by separating them with comma
* like this: `'POST,PUT post/index' => 'post/create'`.
* The supported verbs in the shortcut format are: GET, HEAD, POST, PUT, PATCH and DELETE.
* Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way
* so you normally would not specify a verb for normal GET request.
*
* Here is an example configuration for RESTful CRUD controller:
*
* ```php
* [
* 'dashboard' => 'site/index',
*
* 'POST <controller:[\w-]+>s' => '<controller>/create',
* '<controller:[\w-]+>s' => '<controller>/index',
*
* 'PUT <controller:[\w-]+>/<id:\d+>' => '<controller>/update',
* 'DELETE <controller:[\w-]+>/<id:\d+>' => '<controller>/delete',
* '<controller:[\w-]+>/<id:\d+>' => '<controller>/view',
* ];
* ```
*
* Note that if you modify this property after the UrlManager object is created, make sure
* you populate the array with rule objects instead of rule configurations.
*/
public $rules = [];
/**
* @var string the URL suffix used when [[enablePrettyUrl]] is `true`.
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page.
* This property is used only if [[enablePrettyUrl]] is `true`.
*/
public $suffix;
/**
* @var bool whether to show entry script name in the constructed URL. Defaults to `true`.
* This property is used only if [[enablePrettyUrl]] is `true`.
*/
public $showScriptName = true;
/**
* @var string the GET parameter name for route. This property is used only if [[enablePrettyUrl]] is `false`.
*/
public $routeParam = 'r';
/**
* @var CacheInterface|string the cache object or the application component ID of the cache object.
* Compiled URL rules will be cached through this cache object, if it is available.
*
* After the UrlManager object is created, if you want to change this property,
* you should only assign it with a cache object.
* Set this property to `false` if you do not want to cache the URL rules.
*
* Cache entries are stored for the time set by [[\yii\caching\Cache::$defaultDuration|$defaultDuration]] in
* the cache configuration, which is unlimited by default. You may want to tune this value if your [[rules]]
* change frequently.
*/
public $cache = 'cache';
/**
* @var array the default configuration of URL rules. Individual rule configurations
* specified via [[rules]] will take precedence when the same property of the rule is configured.
*/
public $ruleConfig = ['class' => 'yii\web\UrlRule'];
/**
* @var UrlNormalizer|array|string|false the configuration for [[UrlNormalizer]] used by this UrlManager.
* The default value is `false`, which means normalization will be skipped.
* If you wish to enable URL normalization, you should configure this property manually.
* For example:
*
* ```php
* [
* 'class' => 'yii\web\UrlNormalizer',
* 'collapseSlashes' => true,
* 'normalizeTrailingSlash' => true,
* ]
* ```
*
* @since 2.0.10
*/
public $normalizer = false;
/**
* @var string the cache key for cached rules
* @since 2.0.8
*/
protected $cacheKey = __CLASS__;
private $_baseUrl;
private $_scriptUrl;
private $_hostInfo;
private $_ruleCache;
/**
* Initializes UrlManager.
*/
public function init()
{
parent::init();
if ($this->normalizer !== false) {
$this->normalizer = Yii::createObject($this->normalizer);
if (!$this->normalizer instanceof UrlNormalizer) {
throw new InvalidConfigException('`' . get_class($this) . '::normalizer` should be an instance of `' . UrlNormalizer::className() . '` or its DI compatible configuration.');
}
}
if (!$this->enablePrettyUrl) {
return;
}
if (is_string($this->cache)) {
$this->cache = Yii::$app->get($this->cache, false);
}
if (empty($this->rules)) {
return;
}
$this->rules = $this->buildRules($this->rules);
}
/**
* Adds additional URL rules.
*
* This method will call [[buildRules()]] to parse the given rule declarations and then append or insert
* them to the existing [[rules]].
*
* Note that if [[enablePrettyUrl]] is `false`, this method will do nothing.
*
* @param array $rules the new rules to be added. Each array element represents a single rule declaration.
* Please refer to [[rules]] for the acceptable rule format.
* @param bool $append whether to add the new rules by appending them to the end of the existing rules.
*/
public function addRules($rules, $append = true)
{
if (!$this->enablePrettyUrl) {
return;
}
$rules = $this->buildRules($rules);
if ($append) {
$this->rules = array_merge($this->rules, $rules);
} else {
$this->rules = array_merge($rules, $this->rules);
}
}
/**
* Builds URL rule objects from the given rule declarations.
*
* @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration.
* Please refer to [[rules]] for the acceptable rule formats.
* @return UrlRuleInterface[] the rule objects built from the given rule declarations
* @throws InvalidConfigException if a rule declaration is invalid
*/
protected function buildRules($ruleDeclarations)
{
$builtRules = $this->getBuiltRulesFromCache($ruleDeclarations);
if ($builtRules !== false) {
return $builtRules;
}
$builtRules = [];
$verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
foreach ($ruleDeclarations as $key => $rule) {
if (is_string($rule)) {
$rule = ['route' => $rule];
if (preg_match("/^((?:($verbs),)*($verbs))\\s+(.*)$/", $key, $matches)) {
$rule['verb'] = explode(',', $matches[1]);
// rules that are not applicable for GET requests should not be used to create URLs
if (!in_array('GET', $rule['verb'], true)) {
$rule['mode'] = UrlRule::PARSING_ONLY;
}
$key = $matches[4];
}
$rule['pattern'] = $key;
}
if (is_array($rule)) {
$rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
}
if (!$rule instanceof UrlRuleInterface) {
throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
}
$builtRules[] = $rule;
}
$this->setBuiltRulesCache($ruleDeclarations, $builtRules);
return $builtRules;
}
/**
* Stores $builtRules to cache, using $rulesDeclaration as a part of cache key.
*
* @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration.
* Please refer to [[rules]] for the acceptable rule formats.
* @param UrlRuleInterface[] $builtRules the rule objects built from the given rule declarations.
* @return bool whether the value is successfully stored into cache
* @since 2.0.14
*/
protected function setBuiltRulesCache($ruleDeclarations, $builtRules)
{
if (!$this->cache instanceof CacheInterface) {
return false;
}
return $this->cache->set([$this->cacheKey, $this->ruleConfig, $ruleDeclarations], $builtRules);
}
/**
* Provides the built URL rules that are associated with the $ruleDeclarations from cache.
*
* @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration.
* Please refer to [[rules]] for the acceptable rule formats.
* @return UrlRuleInterface[]|false the rule objects built from the given rule declarations or boolean `false` when
* there are no cache items for this definition exists.
* @since 2.0.14
*/
protected function getBuiltRulesFromCache($ruleDeclarations)
{
if (!$this->cache instanceof CacheInterface) {
return false;
}
return $this->cache->get([$this->cacheKey, $this->ruleConfig, $ruleDeclarations]);
}
/**
* Parses the user request.
* @param Request $request the request component
* @return array|bool the route and the associated parameters. The latter is always empty
* if [[enablePrettyUrl]] is `false`. `false` is returned if the current request cannot be successfully parsed.
*/
public function parseRequest($request)
{
if ($this->enablePrettyUrl) {
/* @var $rule UrlRule */
foreach ($this->rules as $rule) {
$result = $rule->parseRequest($this, $request);
if (YII_DEBUG) {
Yii::debug([
'rule' => method_exists($rule, '__toString') ? $rule->__toString() : get_class($rule),
'match' => $result !== false,
'parent' => null,
], __METHOD__);
}
if ($result !== false) {
return $result;
}
}
if ($this->enableStrictParsing) {
return false;
}
Yii::debug('No matching URL rules. Using default URL parsing logic.', __METHOD__);
$suffix = (string) $this->suffix;
$pathInfo = $request->getPathInfo();
$normalized = false;
if ($this->normalizer !== false) {
$pathInfo = $this->normalizer->normalizePathInfo($pathInfo, $suffix, $normalized);
}
if ($suffix !== '' && $pathInfo !== '') {
$n = strlen($this->suffix);
if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {
$pathInfo = substr($pathInfo, 0, -$n);
if ($pathInfo === '') {
// suffix alone is not allowed
return false;
}
} else {
// suffix doesn't match
return false;
}
}
if ($normalized) {
// pathInfo was changed by normalizer - we need also normalize route
return $this->normalizer->normalizeRoute([$pathInfo, []]);
}
return [$pathInfo, []];
}
Yii::debug('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
$route = $request->getQueryParam($this->routeParam, '');
if (is_array($route)) {
$route = '';
}
return [(string) $route, []];
}
/**
* Creates a URL using the given route and query parameters.
*
* You may specify the route as a string, e.g., `site/index`. You may also use an array
* if you want to specify additional query parameters for the URL being created. The
* array format must be:
*
* ```php
* // generates: /index.php?r=site%2Findex&param1=value1&param2=value2
* ['site/index', 'param1' => 'value1', 'param2' => 'value2']
* ```
*
* If you want to create a URL with an anchor, you can use the array format with a `#` parameter.
* For example,
*
* ```php
* // generates: /index.php?r=site%2Findex&param1=value1#name
* ['site/index', 'param1' => 'value1', '#' => 'name']
* ```
*
* The URL created is a relative one. Use [[createAbsoluteUrl()]] to create an absolute URL.
*
* Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route
* as an absolute route.
*
* @param string|array $params use a string to represent a route (e.g. `site/index`),
* or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`).
* @return string the created URL
*/
public function createUrl($params)
{
$params = (array) $params;
$anchor = isset($params['#']) ? '#' . $params['#'] : '';
unset($params['#'], $params[$this->routeParam]);
$route = trim($params[0], '/');
unset($params[0]);
$baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl();
if ($this->enablePrettyUrl) {
$cacheKey = $route . '?';
foreach ($params as $key => $value) {
if ($value !== null) {
$cacheKey .= $key . '&';
}
}
$url = $this->getUrlFromCache($cacheKey, $route, $params);
if ($url === false) {
/* @var $rule UrlRule */
foreach ($this->rules as $rule) {
if (in_array($rule, $this->_ruleCache[$cacheKey], true)) {
// avoid redundant calls of `UrlRule::createUrl()` for rules checked in `getUrlFromCache()`
// @see https://github.com/yiisoft/yii2/issues/14094
continue;
}
$url = $rule->createUrl($this, $route, $params);
if ($this->canBeCached($rule)) {
$this->setRuleToCache($cacheKey, $rule);
}
if ($url !== false) {
break;
}
}
}
if ($url !== false) {
if (strpos($url, '://') !== false) {
if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) {
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor;
}
return $url . $baseUrl . $anchor;
} elseif (strncmp($url, '//', 2) === 0) {
if ($baseUrl !== '' && ($pos = strpos($url, '/', 2)) !== false) {
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor;
}
return $url . $baseUrl . $anchor;
}
$url = ltrim($url, '/');
return "$baseUrl/{$url}{$anchor}";
}
if ($this->suffix !== null) {
$route .= $this->suffix;
}
if (!empty($params) && ($query = http_build_query($params)) !== '') {
$route .= '?' . $query;
}
$route = ltrim($route, '/');
return "$baseUrl/{$route}{$anchor}";
}
$url = "$baseUrl?{$this->routeParam}=" . urlencode($route);
if (!empty($params) && ($query = http_build_query($params)) !== '') {
$url .= '&' . $query;
}
return $url . $anchor;
}
/**
* Returns the value indicating whether result of [[createUrl()]] of rule should be cached in internal cache.
*
* @param UrlRuleInterface $rule
* @return bool `true` if result should be cached, `false` if not.
* @since 2.0.12
* @see getUrlFromCache()
* @see setRuleToCache()
* @see UrlRule::getCreateUrlStatus()
*/
protected function canBeCached(UrlRuleInterface $rule)
{
return
// if rule does not provide info about create status, we cache it every time to prevent bugs like #13350
// @see https://github.com/yiisoft/yii2/pull/13350#discussion_r114873476
!method_exists($rule, 'getCreateUrlStatus') || ($status = $rule->getCreateUrlStatus()) === null
|| $status === UrlRule::CREATE_STATUS_SUCCESS
|| $status & UrlRule::CREATE_STATUS_PARAMS_MISMATCH;
}
/**
* Get URL from internal cache if exists.
* @param string $cacheKey generated cache key to store data.
* @param string $route the route (e.g. `site/index`).
* @param array $params rule params.
* @return bool|string the created URL
* @see createUrl()
* @since 2.0.8
*/
protected function getUrlFromCache($cacheKey, $route, $params)
{
if (!empty($this->_ruleCache[$cacheKey])) {
foreach ($this->_ruleCache[$cacheKey] as $rule) {
/* @var $rule UrlRule */
if (($url = $rule->createUrl($this, $route, $params)) !== false) {
return $url;
}
}
} else {
$this->_ruleCache[$cacheKey] = [];
}
return false;
}
/**
* Store rule (e.g. [[UrlRule]]) to internal cache.
* @param $cacheKey
* @param UrlRuleInterface $rule
* @since 2.0.8
*/
protected function setRuleToCache($cacheKey, UrlRuleInterface $rule)
{
$this->_ruleCache[$cacheKey][] = $rule;
}
/**
* Creates an absolute URL using the given route and query parameters.
*
* This method prepends the URL created by [[createUrl()]] with the [[hostInfo]].
*
* Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route
* as an absolute route.
*
* @param string|array $params use a string to represent a route (e.g. `site/index`),
* or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`).
* @param string|null $scheme the scheme to use for the URL (either `http`, `https` or empty string
* for protocol-relative URL).
* If not specified the scheme of the current request will be used.
* @return string the created URL
* @see createUrl()
*/
public function createAbsoluteUrl($params, $scheme = null)
{
$params = (array) $params;
$url = $this->createUrl($params);
if (strpos($url, '://') === false) {
$hostInfo = $this->getHostInfo();
if (strncmp($url, '//', 2) === 0) {
$url = substr($hostInfo, 0, strpos($hostInfo, '://')) . ':' . $url;
} else {
$url = $hostInfo . $url;
}
}
return Url::ensureScheme($url, $scheme);
}
/**
* Returns the base URL that is used by [[createUrl()]] to prepend to created URLs.
* It defaults to [[Request::baseUrl]].
* This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`.
* @return string the base URL that is used by [[createUrl()]] to prepend to created URLs.
* @throws InvalidConfigException if running in console application and [[baseUrl]] is not configured.
*/
public function getBaseUrl()
{
if ($this->_baseUrl === null) {
$request = Yii::$app->getRequest();
if ($request instanceof Request) {
$this->_baseUrl = $request->getBaseUrl();
} else {
throw new InvalidConfigException('Please configure UrlManager::baseUrl correctly as you are running a console application.');
}
}
return $this->_baseUrl;
}
/**
* Sets the base URL that is used by [[createUrl()]] to prepend to created URLs.
* This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`.
* @param string $value the base URL that is used by [[createUrl()]] to prepend to created URLs.
*/
public function setBaseUrl($value)
{
$this->_baseUrl = $value === null ? null : rtrim(Yii::getAlias($value), '/');
}
/**
* Returns the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
* It defaults to [[Request::scriptUrl]].
* This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`.
* @return string the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
* @throws InvalidConfigException if running in console application and [[scriptUrl]] is not configured.
*/
public function getScriptUrl()
{
if ($this->_scriptUrl === null) {
$request = Yii::$app->getRequest();
if ($request instanceof Request) {
$this->_scriptUrl = $request->getScriptUrl();
} else {
throw new InvalidConfigException('Please configure UrlManager::scriptUrl correctly as you are running a console application.');
}
}
return $this->_scriptUrl;
}
/**
* Sets the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
* This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`.
* @param string $value the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
*/
public function setScriptUrl($value)
{
$this->_scriptUrl = $value;
}
/**
* Returns the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @return string the host info (e.g. `http://www.example.com`) that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @throws InvalidConfigException if running in console application and [[hostInfo]] is not configured.
*/
public function getHostInfo()
{
if ($this->_hostInfo === null) {
$request = Yii::$app->getRequest();
if ($request instanceof \yii\web\Request) {
$this->_hostInfo = $request->getHostInfo();
} else {
throw new InvalidConfigException('Please configure UrlManager::hostInfo correctly as you are running a console application.');
}
}
return $this->_hostInfo;
}
/**
* Sets the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @param string $value the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
*/
public function setHostInfo($value)
{
$this->_hostInfo = $value === null ? null : rtrim($value, '/');
}
}

View File

@@ -0,0 +1,150 @@
<?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\BaseObject;
use yii\base\InvalidConfigException;
/**
* UrlNormalizer normalizes URLs for [[UrlManager]] and [[UrlRule]].
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @author Cronfy <cronfy@gmail.com>
* @since 2.0.10
*/
class UrlNormalizer extends BaseObject
{
/**
* Represents permament redirection during route normalization.
* @see https://en.wikipedia.org/wiki/HTTP_301
*/
const ACTION_REDIRECT_PERMANENT = 301;
/**
* Represents temporary redirection during route normalization.
* @see https://en.wikipedia.org/wiki/HTTP_302
*/
const ACTION_REDIRECT_TEMPORARY = 302;
/**
* Represents showing 404 error page during route normalization.
* @see https://en.wikipedia.org/wiki/HTTP_404
*/
const ACTION_NOT_FOUND = 404;
/**
* @var bool whether slashes should be collapsed, for example `site///index` will be
* converted into `site/index`
*/
public $collapseSlashes = true;
/**
* @var bool whether trailing slash should be normalized according to the suffix settings
* of the rule
*/
public $normalizeTrailingSlash = true;
/**
* @var int|callable|null action to perform during route normalization.
* Available options are:
* - `null` - no special action will be performed
* - `301` - the request should be redirected to the normalized URL using
* permanent redirection
* - `302` - the request should be redirected to the normalized URL using
* temporary redirection
* - `404` - [[NotFoundHttpException]] will be thrown
* - `callable` - custom user callback, for example:
*
* ```php
* function ($route, $normalizer) {
* // use custom action for redirections
* $route[1]['oldRoute'] = $route[0];
* $route[0] = 'site/redirect';
* return $route;
* }
* ```
*/
public $action = self::ACTION_REDIRECT_PERMANENT;
/**
* Performs normalization action for the specified $route.
* @param array $route route for normalization
* @return array normalized route
* @throws InvalidConfigException if invalid normalization action is used.
* @throws UrlNormalizerRedirectException if normalization requires redirection.
* @throws NotFoundHttpException if normalization suggests action matching route does not exist.
*/
public function normalizeRoute($route)
{
if ($this->action === null) {
return $route;
} elseif ($this->action === static::ACTION_REDIRECT_PERMANENT || $this->action === static::ACTION_REDIRECT_TEMPORARY) {
throw new UrlNormalizerRedirectException([$route[0]] + $route[1], $this->action);
} elseif ($this->action === static::ACTION_NOT_FOUND) {
throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
} elseif (is_callable($this->action)) {
return call_user_func($this->action, $route, $this);
}
throw new InvalidConfigException('Invalid normalizer action.');
}
/**
* Normalizes specified pathInfo.
* @param string $pathInfo pathInfo for normalization
* @param string $suffix current rule suffix
* @param bool $normalized if specified, this variable will be set to `true` if $pathInfo
* was changed during normalization
* @return string normalized pathInfo
*/
public function normalizePathInfo($pathInfo, $suffix, &$normalized = false)
{
if (empty($pathInfo)) {
return $pathInfo;
}
$sourcePathInfo = $pathInfo;
if ($this->collapseSlashes) {
$pathInfo = $this->collapseSlashes($pathInfo);
}
if ($this->normalizeTrailingSlash === true) {
$pathInfo = $this->normalizeTrailingSlash($pathInfo, $suffix);
}
$normalized = $sourcePathInfo !== $pathInfo;
return $pathInfo;
}
/**
* Collapse consecutive slashes in $pathInfo, for example converts `site///index` into `site/index`.
* @param string $pathInfo raw path info.
* @return string normalized path info.
*/
protected function collapseSlashes($pathInfo)
{
return ltrim(preg_replace('#/{2,}#', '/', $pathInfo), '/');
}
/**
* Adds or removes trailing slashes from $pathInfo depending on whether the $suffix has a
* trailing slash or not.
* @param string $pathInfo raw path info.
* @param string $suffix
* @return string normalized path info.
*/
protected function normalizeTrailingSlash($pathInfo, $suffix)
{
if (substr($suffix, -1) === '/' && substr($pathInfo, -1) !== '/') {
$pathInfo .= '/';
} elseif (substr($suffix, -1) !== '/' && substr($pathInfo, -1) === '/') {
$pathInfo = rtrim($pathInfo, '/');
}
return $pathInfo;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UrlNormalizerRedirectException represents an information for redirection which should be
* performed during the URL normalization.
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @since 2.0.10
*/
class UrlNormalizerRedirectException extends \yii\base\Exception
{
/**
* @var array|string the parameter to be used to generate a valid URL for redirection
* @see [[\yii\helpers\Url::to()]]
*/
public $url;
/**
* @var bool|string the URI scheme to use in the generated URL for redirection
* @see [[\yii\helpers\Url::to()]]
*/
public $scheme;
/**
* @var int the HTTP status code
*/
public $statusCode;
/**
* @param array|string $url the parameter to be used to generate a valid URL for redirection.
* This will be used as first parameter for [[\yii\helpers\Url::to()]]
* @param int $statusCode HTTP status code used for redirection
* @param bool|string $scheme the URI scheme to use in the generated URL for redirection.
* This will be used as second parameter for [[\yii\helpers\Url::to()]]
* @param string $message the error message
* @param int $code the error code
* @param \Exception $previous the previous exception used for the exception chaining
*/
public function __construct($url, $statusCode = 302, $scheme = false, $message = null, $code = 0, \Exception $previous = null)
{
$this->url = $url;
$this->scheme = $scheme;
$this->statusCode = $statusCode;
parent::__construct($message, $code, $previous);
}
}

602
vendor/yiisoft/yii2/web/UrlRule.php vendored Normal file
View File

@@ -0,0 +1,602 @@
<?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\BaseObject;
use yii\base\InvalidConfigException;
/**
* UrlRule represents a rule used by [[UrlManager]] for parsing and generating URLs.
*
* To define your own URL parsing and creation logic you can extend from this class
* and add it to [[UrlManager::rules]] like this:
*
* ```php
* 'rules' => [
* ['class' => 'MyUrlRule', 'pattern' => '...', 'route' => 'site/index', ...],
* // ...
* ]
* ```
*
* @property null|int $createUrlStatus Status of the URL creation after the last [[createUrl()]] call. `null`
* if rule does not provide info about create status. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UrlRule extends BaseObject implements UrlRuleInterface
{
/**
* Set [[mode]] with this value to mark that this rule is for URL parsing only.
*/
const PARSING_ONLY = 1;
/**
* Set [[mode]] with this value to mark that this rule is for URL creation only.
*/
const CREATION_ONLY = 2;
/**
* Represents the successful URL generation by last [[createUrl()]] call.
* @see $createStatus
* @since 2.0.12
*/
const CREATE_STATUS_SUCCESS = 0;
/**
* Represents the unsuccessful URL generation by last [[createUrl()]] call, because rule does not support
* creating URLs.
* @see $createStatus
* @since 2.0.12
*/
const CREATE_STATUS_PARSING_ONLY = 1;
/**
* Represents the unsuccessful URL generation by last [[createUrl()]] call, because of mismatched route.
* @see $createStatus
* @since 2.0.12
*/
const CREATE_STATUS_ROUTE_MISMATCH = 2;
/**
* Represents the unsuccessful URL generation by last [[createUrl()]] call, because of mismatched
* or missing parameters.
* @see $createStatus
* @since 2.0.12
*/
const CREATE_STATUS_PARAMS_MISMATCH = 4;
/**
* @var string the name of this rule. If not set, it will use [[pattern]] as the name.
*/
public $name;
/**
* On the rule initialization, the [[pattern]] matching parameters names will be replaced with [[placeholders]].
* @var string the pattern used to parse and create the path info part of a URL.
* @see host
* @see placeholders
*/
public $pattern;
/**
* @var string the pattern used to parse and create the host info part of a URL (e.g. `http://example.com`).
* @see pattern
*/
public $host;
/**
* @var string the route to the controller action
*/
public $route;
/**
* @var array the default GET parameters (name => value) that this rule provides.
* When this rule is used to parse the incoming request, the values declared in this property
* will be injected into $_GET.
*/
public $defaults = [];
/**
* @var string the URL suffix used for this rule.
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page.
* If not set, the value of [[UrlManager::suffix]] will be used.
*/
public $suffix;
/**
* @var string|array the HTTP verb (e.g. GET, POST, DELETE) that this rule should match.
* Use array to represent multiple verbs that this rule may match.
* If this property is not set, the rule can match any verb.
* Note that this property is only used when parsing a request. It is ignored for URL creation.
*/
public $verb;
/**
* @var int a value indicating if this rule should be used for both request parsing and URL creation,
* parsing only, or creation only.
* If not set or 0, it means the rule is both request parsing and URL creation.
* If it is [[PARSING_ONLY]], the rule is for request parsing only.
* If it is [[CREATION_ONLY]], the rule is for URL creation only.
*/
public $mode;
/**
* @var bool a value indicating if parameters should be url encoded.
*/
public $encodeParams = true;
/**
* @var UrlNormalizer|array|false|null the configuration for [[UrlNormalizer]] used by this rule.
* If `null`, [[UrlManager::normalizer]] will be used, if `false`, normalization will be skipped
* for this rule.
* @since 2.0.10
*/
public $normalizer;
/**
* @var int|null status of the URL creation after the last [[createUrl()]] call.
* @since 2.0.12
*/
protected $createStatus;
/**
* @var array list of placeholders for matching parameters names. Used in [[parseRequest()]], [[createUrl()]].
* On the rule initialization, the [[pattern]] parameters names will be replaced with placeholders.
* This array contains relations between the original parameters names and their placeholders.
* The array keys are the placeholders and the values are the original names.
*
* @see parseRequest()
* @see createUrl()
* @since 2.0.7
*/
protected $placeholders = [];
/**
* @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL.
*/
private $_template;
/**
* @var string the regex for matching the route part. This is used in generating URL.
*/
private $_routeRule;
/**
* @var array list of regex for matching parameters. This is used in generating URL.
*/
private $_paramRules = [];
/**
* @var array list of parameters used in the route.
*/
private $_routeParams = [];
/**
* @return string
* @since 2.0.11
*/
public function __toString()
{
$str = '';
if ($this->verb !== null) {
$str .= implode(',', $this->verb) . ' ';
}
if ($this->host !== null && strrpos($this->name, $this->host) === false) {
$str .= $this->host . '/';
}
$str .= $this->name;
if ($str === '') {
return '/';
}
return $str;
}
/**
* Initializes this rule.
*/
public function init()
{
if ($this->pattern === null) {
throw new InvalidConfigException('UrlRule::pattern must be set.');
}
if ($this->route === null) {
throw new InvalidConfigException('UrlRule::route must be set.');
}
if (is_array($this->normalizer)) {
$normalizerConfig = array_merge(['class' => UrlNormalizer::className()], $this->normalizer);
$this->normalizer = Yii::createObject($normalizerConfig);
}
if ($this->normalizer !== null && $this->normalizer !== false && !$this->normalizer instanceof UrlNormalizer) {
throw new InvalidConfigException('Invalid config for UrlRule::normalizer.');
}
if ($this->verb !== null) {
if (is_array($this->verb)) {
foreach ($this->verb as $i => $verb) {
$this->verb[$i] = strtoupper($verb);
}
} else {
$this->verb = [strtoupper($this->verb)];
}
}
if ($this->name === null) {
$this->name = $this->pattern;
}
$this->preparePattern();
}
/**
* Process [[$pattern]] on rule initialization.
*/
private function preparePattern()
{
$this->pattern = $this->trimSlashes($this->pattern);
$this->route = trim($this->route, '/');
if ($this->host !== null) {
$this->host = rtrim($this->host, '/');
$this->pattern = rtrim($this->host . '/' . $this->pattern, '/');
} elseif ($this->pattern === '') {
$this->_template = '';
$this->pattern = '#^$#u';
return;
} elseif (($pos = strpos($this->pattern, '://')) !== false) {
if (($pos2 = strpos($this->pattern, '/', $pos + 3)) !== false) {
$this->host = substr($this->pattern, 0, $pos2);
} else {
$this->host = $this->pattern;
}
} elseif (strncmp($this->pattern, '//', 2) === 0) {
if (($pos2 = strpos($this->pattern, '/', 2)) !== false) {
$this->host = substr($this->pattern, 0, $pos2);
} else {
$this->host = $this->pattern;
}
} else {
$this->pattern = '/' . $this->pattern . '/';
}
if (strpos($this->route, '<') !== false && preg_match_all('/<([\w._-]+)>/', $this->route, $matches)) {
foreach ($matches[1] as $name) {
$this->_routeParams[$name] = "<$name>";
}
}
$this->translatePattern(true);
}
/**
* Prepares [[$pattern]] on rule initialization - replace parameter names by placeholders.
*
* @param bool $allowAppendSlash Defines position of slash in the param pattern in [[$pattern]].
* If `false` slash will be placed at the beginning of param pattern. If `true` slash position will be detected
* depending on non-optional pattern part.
*/
private function translatePattern($allowAppendSlash)
{
$tr = [
'.' => '\\.',
'*' => '\\*',
'$' => '\\$',
'[' => '\\[',
']' => '\\]',
'(' => '\\(',
')' => '\\)',
];
$tr2 = [];
$requiredPatternPart = $this->pattern;
$oldOffset = 0;
if (preg_match_all('/<([\w._-]+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
$appendSlash = false;
foreach ($matches as $match) {
$name = $match[1][0];
$pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+';
$placeholder = 'a' . hash('crc32b', $name); // placeholder must begin with a letter
$this->placeholders[$placeholder] = $name;
if (array_key_exists($name, $this->defaults)) {
$length = strlen($match[0][0]);
$offset = $match[0][1];
$requiredPatternPart = str_replace("/{$match[0][0]}/", '//', $requiredPatternPart);
if (
$allowAppendSlash
&& ($appendSlash || $offset === 1)
&& (($offset - $oldOffset) === 1)
&& isset($this->pattern[$offset + $length])
&& $this->pattern[$offset + $length] === '/'
&& isset($this->pattern[$offset + $length + 1])
) {
// if pattern starts from optional params, put slash at the end of param pattern
// @see https://github.com/yiisoft/yii2/issues/13086
$appendSlash = true;
$tr["<$name>/"] = "((?P<$placeholder>$pattern)/)?";
} elseif (
$offset > 1
&& $this->pattern[$offset - 1] === '/'
&& (!isset($this->pattern[$offset + $length]) || $this->pattern[$offset + $length] === '/')
) {
$appendSlash = false;
$tr["/<$name>"] = "(/(?P<$placeholder>$pattern))?";
}
$tr["<$name>"] = "(?P<$placeholder>$pattern)?";
$oldOffset = $offset + $length;
} else {
$appendSlash = false;
$tr["<$name>"] = "(?P<$placeholder>$pattern)";
}
if (isset($this->_routeParams[$name])) {
$tr2["<$name>"] = "(?P<$placeholder>$pattern)";
} else {
$this->_paramRules[$name] = $pattern === '[^\/]+' ? '' : "#^$pattern$#u";
}
}
}
// we have only optional params in route - ensure slash position on param patterns
if ($allowAppendSlash && trim($requiredPatternPart, '/') === '') {
$this->translatePattern(false);
return;
}
$this->_template = preg_replace('/<([\w._-]+):?([^>]+)?>/', '<$1>', $this->pattern);
$this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u';
// if host starts with relative scheme, then insert pattern to match any
if (strncmp($this->host, '//', 2) === 0) {
$this->pattern = substr_replace($this->pattern, '[\w]+://', 2, 0);
}
if (!empty($this->_routeParams)) {
$this->_routeRule = '#^' . strtr($this->route, $tr2) . '$#u';
}
}
/**
* @param UrlManager $manager the URL manager
* @return UrlNormalizer|null
* @since 2.0.10
*/
protected function getNormalizer($manager)
{
if ($this->normalizer === null) {
return $manager->normalizer;
}
return $this->normalizer;
}
/**
* @param UrlManager $manager the URL manager
* @return bool
* @since 2.0.10
*/
protected function hasNormalizer($manager)
{
return $this->getNormalizer($manager) instanceof UrlNormalizer;
}
/**
* Parses the given request and returns the corresponding route and parameters.
* @param UrlManager $manager the URL manager
* @param Request $request the request component
* @return array|bool the parsing result. The route and the parameters are returned as an array.
* If `false`, it means this rule cannot be used to parse this path info.
*/
public function parseRequest($manager, $request)
{
if ($this->mode === self::CREATION_ONLY) {
return false;
}
if (!empty($this->verb) && !in_array($request->getMethod(), $this->verb, true)) {
return false;
}
$suffix = (string) ($this->suffix === null ? $manager->suffix : $this->suffix);
$pathInfo = $request->getPathInfo();
$normalized = false;
if ($this->hasNormalizer($manager)) {
$pathInfo = $this->getNormalizer($manager)->normalizePathInfo($pathInfo, $suffix, $normalized);
}
if ($suffix !== '' && $pathInfo !== '') {
$n = strlen($suffix);
if (substr_compare($pathInfo, $suffix, -$n, $n) === 0) {
$pathInfo = substr($pathInfo, 0, -$n);
if ($pathInfo === '') {
// suffix alone is not allowed
return false;
}
} else {
return false;
}
}
if ($this->host !== null) {
$pathInfo = strtolower($request->getHostInfo()) . ($pathInfo === '' ? '' : '/' . $pathInfo);
}
if (!preg_match($this->pattern, $pathInfo, $matches)) {
return false;
}
$matches = $this->substitutePlaceholderNames($matches);
foreach ($this->defaults as $name => $value) {
if (!isset($matches[$name]) || $matches[$name] === '') {
$matches[$name] = $value;
}
}
$params = $this->defaults;
$tr = [];
foreach ($matches as $name => $value) {
if (isset($this->_routeParams[$name])) {
$tr[$this->_routeParams[$name]] = $value;
unset($params[$name]);
} elseif (isset($this->_paramRules[$name])) {
$params[$name] = $value;
}
}
if ($this->_routeRule !== null) {
$route = strtr($this->route, $tr);
} else {
$route = $this->route;
}
Yii::debug("Request parsed with URL rule: {$this->name}", __METHOD__);
if ($normalized) {
// pathInfo was changed by normalizer - we need also normalize route
return $this->getNormalizer($manager)->normalizeRoute([$route, $params]);
}
return [$route, $params];
}
/**
* Creates a URL according to the given route and parameters.
* @param UrlManager $manager the URL manager
* @param string $route the route. It should not have slashes at the beginning or the end.
* @param array $params the parameters
* @return string|bool the created URL, or `false` if this rule cannot be used for creating this URL.
*/
public function createUrl($manager, $route, $params)
{
if ($this->mode === self::PARSING_ONLY) {
$this->createStatus = self::CREATE_STATUS_PARSING_ONLY;
return false;
}
$tr = [];
// match the route part first
if ($route !== $this->route) {
if ($this->_routeRule !== null && preg_match($this->_routeRule, $route, $matches)) {
$matches = $this->substitutePlaceholderNames($matches);
foreach ($this->_routeParams as $name => $token) {
if (isset($this->defaults[$name]) && strcmp($this->defaults[$name], $matches[$name]) === 0) {
$tr[$token] = '';
} else {
$tr[$token] = $matches[$name];
}
}
} else {
$this->createStatus = self::CREATE_STATUS_ROUTE_MISMATCH;
return false;
}
}
// match default params
// if a default param is not in the route pattern, its value must also be matched
foreach ($this->defaults as $name => $value) {
if (isset($this->_routeParams[$name])) {
continue;
}
if (!isset($params[$name])) {
// allow omit empty optional params
// @see https://github.com/yiisoft/yii2/issues/10970
if (in_array($name, $this->placeholders) && strcmp($value, '') === 0) {
$params[$name] = '';
} else {
$this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH;
return false;
}
}
if (strcmp($params[$name], $value) === 0) { // strcmp will do string conversion automatically
unset($params[$name]);
if (isset($this->_paramRules[$name])) {
$tr["<$name>"] = '';
}
} elseif (!isset($this->_paramRules[$name])) {
$this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH;
return false;
}
}
// match params in the pattern
foreach ($this->_paramRules as $name => $rule) {
if (isset($params[$name]) && !is_array($params[$name]) && ($rule === '' || preg_match($rule, $params[$name]))) {
$tr["<$name>"] = $this->encodeParams ? urlencode($params[$name]) : $params[$name];
unset($params[$name]);
} elseif (!isset($this->defaults[$name]) || isset($params[$name])) {
$this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH;
return false;
}
}
$url = $this->trimSlashes(strtr($this->_template, $tr));
if ($this->host !== null) {
$pos = strpos($url, '/', 8);
if ($pos !== false) {
$url = substr($url, 0, $pos) . preg_replace('#/+#', '/', substr($url, $pos));
}
} elseif (strpos($url, '//') !== false) {
$url = preg_replace('#/+#', '/', trim($url, '/'));
}
if ($url !== '') {
$url .= ($this->suffix === null ? $manager->suffix : $this->suffix);
}
if (!empty($params) && ($query = http_build_query($params)) !== '') {
$url .= '?' . $query;
}
$this->createStatus = self::CREATE_STATUS_SUCCESS;
return $url;
}
/**
* Returns status of the URL creation after the last [[createUrl()]] call.
*
* @return null|int Status of the URL creation after the last [[createUrl()]] call. `null` if rule does not provide
* info about create status.
* @see $createStatus
* @since 2.0.12
*/
public function getCreateUrlStatus()
{
return $this->createStatus;
}
/**
* Returns list of regex for matching parameter.
* @return array parameter keys and regexp rules.
*
* @since 2.0.6
*/
protected function getParamRules()
{
return $this->_paramRules;
}
/**
* Iterates over [[placeholders]] and checks whether each placeholder exists as a key in $matches array.
* When found - replaces this placeholder key with a appropriate name of matching parameter.
* Used in [[parseRequest()]], [[createUrl()]].
*
* @param array $matches result of `preg_match()` call
* @return array input array with replaced placeholder keys
* @see placeholders
* @since 2.0.7
*/
protected function substitutePlaceholderNames(array $matches)
{
foreach ($this->placeholders as $placeholder => $name) {
if (isset($matches[$placeholder])) {
$matches[$name] = $matches[$placeholder];
unset($matches[$placeholder]);
}
}
return $matches;
}
/**
* Trim slashes in passed string. If string begins with '//', two slashes are left as is
* in the beginning of a string.
*
* @param string $string
* @return string
*/
private function trimSlashes($string)
{
if (strncmp($string, '//', 2) === 0) {
return '//' . trim($string, '/');
}
return trim($string, '/');
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UrlRuleInterface is the interface that should be implemented by URL rule classes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface UrlRuleInterface
{
/**
* Parses the given request and returns the corresponding route and parameters.
* @param UrlManager $manager the URL manager
* @param Request $request the request component
* @return array|bool the parsing result. The route and the parameters are returned as an array.
* If false, it means this rule cannot be used to parse this path info.
*/
public function parseRequest($manager, $request);
/**
* Creates a URL according to the given route and parameters.
* @param UrlManager $manager the URL manager
* @param string $route the route. It should not have slashes at the beginning or the end.
* @param array $params the parameters
* @return string|bool the created URL, or false if this rule cannot be used for creating this URL.
*/
public function createUrl($manager, $route, $params);
}

777
vendor/yiisoft/yii2/web/User.php vendored Normal file
View File

@@ -0,0 +1,777 @@
<?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\Component;
use yii\base\InvalidConfigException;
use yii\base\InvalidValueException;
use yii\rbac\CheckAccessInterface;
/**
* User is the class for the `user` application component that manages the user authentication status.
*
* You may use [[isGuest]] to determine whether the current user is a guest or not.
* If the user is a guest, the [[identity]] property would return `null`. Otherwise, it would
* be an instance of [[IdentityInterface]].
*
* You may call various methods to change the user authentication status:
*
* - [[login()]]: sets the specified identity and remembers the authentication status in session and cookie;
* - [[logout()]]: marks the user as a guest and clears the relevant information from session and cookie;
* - [[setIdentity()]]: changes the user identity without touching session or cookie
* (this is best used in stateless RESTful API implementation).
*
* Note that User only maintains the user authentication status. It does NOT handle how to authenticate
* a user. The logic of how to authenticate a user should be done in the class implementing [[IdentityInterface]].
* You are also required to set [[identityClass]] with the name of this class.
*
* User is configured as an application component in [[\yii\web\Application]] by default.
* You can access that instance via `Yii::$app->user`.
*
* You can modify its configuration by adding an array to your application config under `components`
* as it is shown in the following example:
*
* ```php
* 'user' => [
* 'identityClass' => 'app\models\User', // User must implement the IdentityInterface
* 'enableAutoLogin' => true,
* // 'loginUrl' => ['user/login'],
* // ...
* ]
* ```
*
* @property string|int $id The unique identifier for the user. If `null`, it means the user is a guest. This
* property is read-only.
* @property IdentityInterface|null $identity The identity object associated with the currently logged-in
* user. `null` is returned if the user is not logged in (not authenticated).
* @property bool $isGuest Whether the current user is a guest. This property is read-only.
* @property string $returnUrl The URL that the user should be redirected to after login. Note that the type
* of this property differs in getter and setter. See [[getReturnUrl()]] and [[setReturnUrl()]] for details.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class User extends Component {
const EVENT_BEFORE_LOGIN = 'beforeLogin';
const EVENT_AFTER_LOGIN = 'afterLogin';
const EVENT_BEFORE_LOGOUT = 'beforeLogout';
const EVENT_AFTER_LOGOUT = 'afterLogout';
/**
* @var string the class name of the [[identity]] object.
*/
public $identityClass;
/**
* @var bool whether to enable cookie-based login. Defaults to `false`.
* Note that this property will be ignored if [[enableSession]] is `false`.
*/
public $enableAutoLogin = false;
/**
* @var bool whether to use session to persist authentication status across multiple requests.
* You set this property to be `false` if your application is stateless, which is often the case
* for RESTful APIs.
*/
public $enableSession = true;
/**
* @var string|array the URL for login when [[loginRequired()]] is called.
* If an array is given, [[UrlManager::createUrl()]] will be called to create the corresponding URL.
* The first element of the array should be the route to the login action, and the rest of
* the name-value pairs are GET parameters used to construct the login URL. For example,
*
* ```php
* ['site/login', 'ref' => 1]
* ```
*
* If this property is `null`, a 403 HTTP exception will be raised when [[loginRequired()]] is called.
*/
public $loginUrl = ['site/login'];
/**
* @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is `true`.
* @see Cookie
*/
public $identityCookie = ['name' => '_identity', 'httpOnly' => true];
/**
* @var int the number of seconds in which the user will be logged out automatically if he
* remains inactive. If this property is not set, the user will be logged out after
* the current session expires (c.f. [[Session::timeout]]).
* Note that this will not work if [[enableAutoLogin]] is `true`.
*/
public $authTimeout;
/**
* @var CheckAccessInterface The access checker to use for checking access.
* If not set the application auth manager will be used.
* @since 2.0.9
*/
public $accessChecker;
/**
* @var int the number of seconds in which the user will be logged out automatically
* regardless of activity.
* Note that this will not work if [[enableAutoLogin]] is `true`.
*/
public $absoluteAuthTimeout;
/**
* @var bool whether to automatically renew the identity cookie each time a page is requested.
* This property is effective only when [[enableAutoLogin]] is `true`.
* When this is `false`, the identity cookie will expire after the specified duration since the user
* is initially logged in. When this is `true`, the identity cookie will expire after the specified duration
* since the user visits the site the last time.
* @see enableAutoLogin
*/
public $autoRenewCookie = true;
/**
* @var string the session variable name used to store the value of [[id]].
*/
public $idParam = '__id';
/**
* @var string the session variable name used to store the value of expiration timestamp of the authenticated state.
* This is used when [[authTimeout]] is set.
*/
public $authTimeoutParam = '__expire';
/**
* @var string the session variable name used to store the value of absolute expiration timestamp of the authenticated state.
* This is used when [[absoluteAuthTimeout]] is set.
*/
public $absoluteAuthTimeoutParam = '__absoluteExpire';
/**
* @var string the session variable name used to store the value of [[returnUrl]].
*/
public $returnUrlParam = '__returnUrl';
/**
* @var array MIME types for which this component should redirect to the [[loginUrl]].
* @since 2.0.8
*/
public $acceptableRedirectTypes = ['text/html', 'application/xhtml+xml'];
private $_access = [];
/**
* Initializes the application component.
*/
public function init() {
parent::init();
if ($this->identityClass === null) {
throw new InvalidConfigException('User::identityClass must be set.');
}
if ($this->enableAutoLogin && !isset($this->identityCookie['name'])) {
throw new InvalidConfigException('User::identityCookie must contain the "name" element.');
}
if (!empty($this->accessChecker) && is_string($this->accessChecker)) {
$this->accessChecker = Yii::createObject($this->accessChecker);
}
}
private $_identity = false;
/**
* Returns the identity object associated with the currently logged-in user.
* When [[enableSession]] is true, this method may attempt to read the user's authentication data
* stored in session and reconstruct the corresponding identity object, if it has not done so before.
* @param bool $autoRenew whether to automatically renew authentication status if it has not been done so before.
* This is only useful when [[enableSession]] is true.
* @return IdentityInterface|null the identity object associated with the currently logged-in user.
* `null` is returned if the user is not logged in (not authenticated).
* @see login()
* @see logout()
*/
public function getIdentity($autoRenew = true) {
if ($this->_identity === false) {
if ($this->enableSession && $autoRenew) {
try {
$this->_identity = null;
$this->renewAuthStatus();
} catch (\Exception $e) {
$this->_identity = false;
throw $e;
} catch (\Throwable $e) {
$this->_identity = false;
throw $e;
}
} else {
return null;
}
}
return $this->_identity;
}
/**
* Sets the user identity object.
*
* Note that this method does not deal with session or cookie. You should usually use [[switchIdentity()]]
* to change the identity of the current user.
*
* @param IdentityInterface|null $identity the identity object associated with the currently logged user.
* If null, it means the current user will be a guest without any associated identity.
* @throws InvalidValueException if `$identity` object does not implement [[IdentityInterface]].
*/
public function setIdentity($identity) {
if ($identity instanceof IdentityInterface) {
$this->_identity = $identity;
$this->_access = [];
} elseif ($identity === null) {
$this->_identity = null;
} else {
throw new InvalidValueException('The identity object must implement IdentityInterface.');
}
}
/**
* Logs in a user.
*
* After logging in a user:
* - the user's identity information is obtainable from the [[identity]] property
*
* If [[enableSession]] is `true`:
* - the identity information will be stored in session and be available in the next requests
* - in case of `$duration == 0`: as long as the session remains active or till the user closes the browser
* - in case of `$duration > 0`: as long as the session remains active or as long as the cookie
* remains valid by it's `$duration` in seconds when [[enableAutoLogin]] is set `true`.
*
* If [[enableSession]] is `false`:
* - the `$duration` parameter will be ignored
*
* @param IdentityInterface $identity the user identity (which should already be authenticated)
* @param int $duration number of seconds that the user can remain in logged-in status, defaults to `0`
* @return bool whether the user is logged in
*/
public function login(IdentityInterface $identity, $duration = 0) {
if ($this->beforeLogin($identity, false, $duration)) {
$this->switchIdentity($identity, $duration);
$id = $identity->getId();
$ip = Yii::$app->getRequest()->getUserIP();
if ($this->enableSession) {
$log = "User '$id' logged in from $ip with duration $duration.";
} else {
$log = "User '$id' logged in from $ip. Session not enabled.";
}
$this->regenerateCsrfToken();
Yii::info($log, __METHOD__);
$this->afterLogin($identity, false, $duration);
}
return !$this->getIsGuest();
}
/**
* Regenerates CSRF token
*
* @since 2.0.14.2
*/
protected function regenerateCsrfToken() {
$request = Yii::$app->getRequest();
if ($request->enableCsrfCookie || $this->enableSession) {
$request->getCsrfToken(true);
}
}
/**
* Logs in a user by the given access token.
* This method will first authenticate the user by calling [[IdentityInterface::findIdentityByAccessToken()]]
* with the provided access token. If successful, it will call [[login()]] to log in the authenticated user.
* If authentication fails or [[login()]] is unsuccessful, it will return null.
* @param string $token the access token
* @param mixed $type the type of the token. The value of this parameter depends on the implementation.
* For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
* @return IdentityInterface|null the identity associated with the given access token. Null is returned if
* the access token is invalid or [[login()]] is unsuccessful.
*/
public function loginByAccessToken($token, $type = null) {
/* @var $class IdentityInterface */
$class = $this->identityClass;
$identity = $class::findIdentityByAccessToken($token, $type);
if ($identity && $this->login($identity)) {
return $identity;
}
return null;
}
/**
* Logs in a user by cookie.
*
* This method attempts to log in a user using the ID and authKey information
* provided by the [[identityCookie|identity cookie]].
*/
protected function loginByCookie() {
$data = $this->getIdentityAndDurationFromCookie();
if (isset($data['identity'], $data['duration'])) {
$identity = $data['identity'];
$duration = $data['duration'];
if ($this->beforeLogin($identity, true, $duration)) {
$this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
$id = $identity->getId();
$ip = Yii::$app->getRequest()->getUserIP();
Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__);
$this->afterLogin($identity, true, $duration);
}
}
}
/**
* Logs out the current user.
* This will remove authentication-related session data.
* If `$destroySession` is true, all session data will be removed.
* @param bool $destroySession whether to destroy the whole session. Defaults to true.
* This parameter is ignored if [[enableSession]] is false.
* @return bool whether the user is logged out
*/
public function logout($destroySession = true) {
$identity = $this->getIdentity();
if ($identity !== null && $this->beforeLogout($identity)) {
$this->switchIdentity(null);
$id = $identity->getId();
$ip = Yii::$app->getRequest()->getUserIP();
Yii::info("User '$id' logged out from $ip.", __METHOD__);
if ($destroySession && $this->enableSession) {
Yii::$app->getSession()->destroy();
}
$this->afterLogout($identity);
}
return $this->getIsGuest();
}
/**
* Returns a value indicating whether the user is a guest (not authenticated).
* @return bool whether the current user is a guest.
* @see getIdentity()
*/
public function getIsGuest() {
return $this->getIdentity() === null;
}
/**
* Returns a value that uniquely represents the user.
* @return string|int the unique identifier for the user. If `null`, it means the user is a guest.
* @see getIdentity()
*/
public function getId() {
$identity = $this->getIdentity();
return $identity !== null ? $identity->getId() : null;
}
/**
* Returns the URL that the browser should be redirected to after successful login.
*
* This method reads the return URL from the session. It is usually used by the login action which
* may call this method to redirect the browser to where it goes after successful authentication.
*
* @param string|array $defaultUrl the default return URL in case it was not set previously.
* If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to.
* Please refer to [[setReturnUrl()]] on accepted format of the URL.
* @return string the URL that the user should be redirected to after login.
* @see loginRequired()
*/
public function getReturnUrl($defaultUrl = null) {
$url = Yii::$app->getSession()->get($this->returnUrlParam, $defaultUrl);
if (is_array($url)) {
if (isset($url[0])) {
return Yii::$app->getUrlManager()->createUrl($url);
}
$url = null;
}
return $url === null ? Yii::$app->getHomeUrl() : $url;
}
/**
* Remembers the URL in the session so that it can be retrieved back later by [[getReturnUrl()]].
* @param string|array $url the URL that the user should be redirected to after login.
* If an array is given, [[UrlManager::createUrl()]] will be called to create the corresponding URL.
* The first element of the array should be the route, and the rest of
* the name-value pairs are GET parameters used to construct the URL. For example,
*
* ```php
* ['admin/index', 'ref' => 1]
* ```
*/
public function setReturnUrl($url) {
Yii::$app->getSession()->set($this->returnUrlParam, $url);
}
/**
* Redirects the user browser to the login page.
*
* Before the redirection, the current URL (if it's not an AJAX url) will be kept as [[returnUrl]] so that
* the user browser may be redirected back to the current page after successful login.
*
* Make sure you set [[loginUrl]] so that the user browser can be redirected to the specified login URL after
* calling this method.
*
* Note that when [[loginUrl]] is set, calling this method will NOT terminate the application execution.
*
* @param bool $checkAjax whether to check if the request is an AJAX request. When this is true and the request
* is an AJAX request, the current URL (for AJAX request) will NOT be set as the return URL.
* @param bool $checkAcceptHeader whether to check if the request accepts HTML responses. Defaults to `true`. When this is true and
* the request does not accept HTML responses the current URL will not be SET as the return URL. Also instead of
* redirecting the user an ForbiddenHttpException is thrown. This parameter is available since version 2.0.8.
* @return Response the redirection response if [[loginUrl]] is set
* @throws ForbiddenHttpException the "Access Denied" HTTP exception if [[loginUrl]] is not set or a redirect is
* not applicable.
*/
public function loginRequired($checkAjax = true, $checkAcceptHeader = true) {
$request = Yii::$app->getRequest();
$canRedirect = !$checkAcceptHeader || $this->checkRedirectAcceptable();
if ($this->enableSession && $request->getIsGet() && (!$checkAjax || !$request->getIsAjax()) && $canRedirect
) {
$this->setReturnUrl($request->getUrl());
}
if ($this->loginUrl !== null && $canRedirect) {
$loginUrl = (array) $this->loginUrl;
if ($loginUrl[0] !== Yii::$app->requestedRoute) {
return Yii::$app->getResponse()->redirect($this->loginUrl);
}
}
throw new ForbiddenHttpException(Yii::t('yii', 'Login Required'));
}
/**
* This method is called before logging in a user.
* The default implementation will trigger the [[EVENT_BEFORE_LOGIN]] event.
* If you override this method, make sure you call the parent implementation
* so that the event is triggered.
* @param IdentityInterface $identity the user identity information
* @param bool $cookieBased whether the login is cookie-based
* @param int $duration number of seconds that the user can remain in logged-in status.
* If 0, it means login till the user closes the browser or the session is manually destroyed.
* @return bool whether the user should continue to be logged in
*/
protected function beforeLogin($identity, $cookieBased, $duration) {
$event = new UserEvent([
'identity' => $identity,
'cookieBased' => $cookieBased,
'duration' => $duration,
]);
$this->trigger(self::EVENT_BEFORE_LOGIN, $event);
return $event->isValid;
}
/**
* This method is called after the user is successfully logged in.
* The default implementation will trigger the [[EVENT_AFTER_LOGIN]] event.
* If you override this method, make sure you call the parent implementation
* so that the event is triggered.
* @param IdentityInterface $identity the user identity information
* @param bool $cookieBased whether the login is cookie-based
* @param int $duration number of seconds that the user can remain in logged-in status.
* If 0, it means login till the user closes the browser or the session is manually destroyed.
*/
protected function afterLogin($identity, $cookieBased, $duration) {
$this->trigger(self::EVENT_AFTER_LOGIN, new UserEvent([
'identity' => $identity,
'cookieBased' => $cookieBased,
'duration' => $duration,
]));
}
/**
* This method is invoked when calling [[logout()]] to log out a user.
* The default implementation will trigger the [[EVENT_BEFORE_LOGOUT]] event.
* If you override this method, make sure you call the parent implementation
* so that the event is triggered.
* @param IdentityInterface $identity the user identity information
* @return bool whether the user should continue to be logged out
*/
protected function beforeLogout($identity) {
$event = new UserEvent([
'identity' => $identity,
]);
$this->trigger(self::EVENT_BEFORE_LOGOUT, $event);
return $event->isValid;
}
/**
* This method is invoked right after a user is logged out via [[logout()]].
* The default implementation will trigger the [[EVENT_AFTER_LOGOUT]] event.
* If you override this method, make sure you call the parent implementation
* so that the event is triggered.
* @param IdentityInterface $identity the user identity information
*/
protected function afterLogout($identity) {
$this->trigger(self::EVENT_AFTER_LOGOUT, new UserEvent([
'identity' => $identity,
]));
}
/**
* Renews the identity cookie.
* This method will set the expiration time of the identity cookie to be the current time
* plus the originally specified cookie duration.
*/
protected function renewIdentityCookie() {
$name = $this->identityCookie['name'];
$value = Yii::$app->getRequest()->getCookies()->getValue($name);
if ($value !== null) {
$data = json_decode($value, true);
if (is_array($data) && isset($data[2])) {
$cookie = Yii::createObject(array_merge($this->identityCookie, [
'class' => 'yii\web\Cookie',
'value' => $value,
'expire' => time() + (int) $data[2],
]));
Yii::$app->getResponse()->getCookies()->add($cookie);
}
}
}
/**
* Sends an identity cookie.
* This method is used when [[enableAutoLogin]] is true.
* It saves [[id]], [[IdentityInterface::getAuthKey()|auth key]], and the duration of cookie-based login
* information in the cookie.
* @param IdentityInterface $identity
* @param int $duration number of seconds that the user can remain in logged-in status.
* @see loginByCookie()
*/
protected function sendIdentityCookie($identity, $duration) {
$cookie = Yii::createObject(array_merge($this->identityCookie, [
'class' => 'yii\web\Cookie',
'value' => json_encode([
$identity->getId(),
$identity->getAuthKey(),
$duration,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'expire' => time() + $duration,
]));
Yii::$app->getResponse()->getCookies()->add($cookie);
}
/**
* Determines if an identity cookie has a valid format and contains a valid auth key.
* This method is used when [[enableAutoLogin]] is true.
* This method attempts to authenticate a user using the information in the identity cookie.
* @return array|null Returns an array of 'identity' and 'duration' if valid, otherwise null.
* @see loginByCookie()
* @since 2.0.9
*/
protected function getIdentityAndDurationFromCookie() {
$value = Yii::$app->getRequest()->getCookies()->getValue($this->identityCookie['name']);
if ($value === null) {
return null;
}
$data = json_decode($value, true);
if (is_array($data) && count($data) == 3) {
list($id, $authKey, $duration) = $data;
/* @var $class IdentityInterface */
$class = $this->identityClass;
$identity = $class::findIdentity($id);
if ($identity !== null) {
if (!$identity instanceof IdentityInterface) {
throw new InvalidValueException("$class::findIdentity() must return an object implementing IdentityInterface.");
} elseif (!$identity->validateAuthKey($authKey)) {
Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__);
} else {
return ['identity' => $identity, 'duration' => $duration];
}
}
}
$this->removeIdentityCookie();
return null;
}
/**
* Removes the identity cookie.
* This method is used when [[enableAutoLogin]] is true.
* @since 2.0.9
*/
protected function removeIdentityCookie() {
Yii::$app->getResponse()->getCookies()->remove(Yii::createObject(array_merge($this->identityCookie, [
'class' => 'yii\web\Cookie',
])));
}
/**
* Switches to a new identity for the current user.
*
* When [[enableSession]] is true, this method may use session and/or cookie to store the user identity information,
* according to the value of `$duration`. Please refer to [[login()]] for more details.
*
* This method is mainly called by [[login()]], [[logout()]] and [[loginByCookie()]]
* when the current user needs to be associated with the corresponding identity information.
*
* @param IdentityInterface|null $identity the identity information to be associated with the current user.
* If null, it means switching the current user to be a guest.
* @param int $duration number of seconds that the user can remain in logged-in status.
* This parameter is used only when `$identity` is not null.
*/
public function switchIdentity($identity, $duration = 0) {
$this->setIdentity($identity);
if (!$this->enableSession) {
return;
}
/* Ensure any existing identity cookies are removed. */
if ($this->enableAutoLogin && ($this->autoRenewCookie || $identity === null)) {
$this->removeIdentityCookie();
}
$session = Yii::$app->getSession();
if (!YII_ENV_TEST) {
$session->regenerateID(true);
}
$session->remove($this->idParam);
$session->remove($this->authTimeoutParam);
if ($identity) {
$session->set($this->idParam, $identity->getId());
if ($this->authTimeout !== null) {
$session->set($this->authTimeoutParam, time() + $this->authTimeout);
}
if ($this->absoluteAuthTimeout !== null) {
$session->set($this->absoluteAuthTimeoutParam, time() + $this->absoluteAuthTimeout);
}
if ($this->enableAutoLogin && $duration > 0) {
$this->sendIdentityCookie($identity, $duration);
}
}
}
/**
* Updates the authentication status using the information from session and cookie.
*
* This method will try to determine the user identity using the [[idParam]] session variable.
*
* If [[authTimeout]] is set, this method will refresh the timer.
*
* If the user identity cannot be determined by session, this method will try to [[loginByCookie()|login by cookie]]
* if [[enableAutoLogin]] is true.
*/
protected function renewAuthStatus() {
$session = Yii::$app->getSession();
$id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;
if ($id === null) {
$identity = null;
} else {
/* @var $class IdentityInterface */
$class = $this->identityClass;
$identity = $class::findIdentity($id);
}
$this->setIdentity($identity);
if ($identity !== null && ($this->authTimeout !== null || $this->absoluteAuthTimeout !== null)) {
$expire = $this->authTimeout !== null ? $session->get($this->authTimeoutParam) : null;
$expireAbsolute = $this->absoluteAuthTimeout !== null ? $session->get($this->absoluteAuthTimeoutParam) : null;
if ($expire !== null && $expire < time() || $expireAbsolute !== null && $expireAbsolute < time()) {
$this->logout(false);
} elseif ($this->authTimeout !== null) {
$session->set($this->authTimeoutParam, time() + $this->authTimeout);
}
}
if ($this->enableAutoLogin) {
if ($this->getIsGuest()) {
$this->loginByCookie();
} elseif ($this->autoRenewCookie) {
$this->renewIdentityCookie();
}
}
}
/**
* Checks if the user can perform the operation as specified by the given permission.
*
* Note that you must configure "authManager" application component in order to use this method.
* Otherwise it will always return false.
*
* @param string $permissionName the name of the permission (e.g. "edit post") that needs access check.
* @param array $params name-value pairs that would be passed to the rules associated
* with the roles and permissions assigned to the user.
* @param bool $allowCaching whether to allow caching the result of access check.
* When this parameter is true (default), if the access check of an operation was performed
* before, its result will be directly returned when calling this method to check the same
* operation. If this parameter is false, this method will always call
* [[\yii\rbac\CheckAccessInterface::checkAccess()]] to obtain the up-to-date access result. Note that this
* caching is effective only within the same request and only works when `$params = []`.
* @return bool whether the user can perform the operation as specified by the given permission.
*/
public function can($permissionName, $params = [], $allowCaching = true) {
if ($allowCaching && empty($params) && isset($this->_access[$permissionName])) {
return $this->_access[$permissionName];
}
if (($accessChecker = $this->getAccessChecker()) === null) {
return false;
}
$access = $accessChecker->checkAccess($this->getId(), $permissionName, $params);
if ($allowCaching && empty($params)) {
$this->_access[$permissionName] = $access;
}
return $access;
}
/**
* Checks if the `Accept` header contains a content type that allows redirection to the login page.
* The login page is assumed to serve `text/html` or `application/xhtml+xml` by default. You can change acceptable
* content types by modifying [[acceptableRedirectTypes]] property.
* @return bool whether this request may be redirected to the login page.
* @see acceptableRedirectTypes
* @since 2.0.8
*/
protected function checkRedirectAcceptable() {
$acceptableTypes = Yii::$app->getRequest()->getAcceptableContentTypes();
if (empty($acceptableTypes) || count($acceptableTypes) === 1 && array_keys($acceptableTypes)[0] === '*/*') {
return true;
}
foreach ($acceptableTypes as $type => $params) {
if (in_array($type, $this->acceptableRedirectTypes, true)) {
return true;
}
}
return false;
}
/**
* Returns auth manager associated with the user component.
*
* By default this is the `authManager` application component.
* You may override this method to return a different auth manager instance if needed.
* @return \yii\rbac\ManagerInterface
* @since 2.0.6
* @deprecated since version 2.0.9, to be removed in 2.1. Use [[getAccessChecker()]] instead.
*/
protected function getAuthManager() {
return Yii::$app->getAuthManager();
}
/**
* Returns the access checker used for checking access.
* @return CheckAccessInterface
* @since 2.0.9
*/
protected function getAccessChecker() {
return $this->accessChecker !== null ? $this->accessChecker : $this->getAuthManager();
}
}

40
vendor/yiisoft/yii2/web/UserEvent.php vendored Normal file
View File

@@ -0,0 +1,40 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\Event;
/**
* This event class is used for Events triggered by the [[User]] class.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UserEvent extends Event
{
/**
* @var IdentityInterface the identity object associated with this event
*/
public $identity;
/**
* @var bool whether the login is cookie-based. This property is only meaningful
* for [[User::EVENT_BEFORE_LOGIN]] and [[User::EVENT_AFTER_LOGIN]] events.
*/
public $cookieBased;
/**
* @var int number of seconds that the user can remain in logged-in status.
* If 0, it means login till the user closes the browser or the session is manually destroyed.
*/
public $duration;
/**
* @var bool whether the login or logout should proceed.
* Event handlers may modify this property to determine whether the login or logout should proceed.
* This property is only meaningful for [[User::EVENT_BEFORE_LOGIN]] and [[User::EVENT_BEFORE_LOGOUT]] events.
*/
public $isValid = true;
}

639
vendor/yiisoft/yii2/web/View.php vendored Normal file
View File

@@ -0,0 +1,639 @@
<?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\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* View represents a view object in the MVC pattern.
*
* View provides a set of methods (e.g. [[render()]]) for rendering purpose.
*
* View is configured as an application component in [[\yii\base\Application]] by default.
* You can access that instance via `Yii::$app->view`.
*
* You can modify its configuration by adding an array to your application config under `components`
* as it is shown in the following example:
*
* ```php
* 'view' => [
* 'theme' => 'app\themes\MyTheme',
* 'renderers' => [
* // you may add Smarty or Twig renderer here
* ]
* // ...
* ]
* ```
*
* For more details and usage information on View, see the [guide article on views](guide:structure-views).
*
* @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application
* component.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class View extends \yii\base\View
{
/**
* @event Event an event that is triggered by [[beginBody()]].
*/
const EVENT_BEGIN_BODY = 'beginBody';
/**
* @event Event an event that is triggered by [[endBody()]].
*/
const EVENT_END_BODY = 'endBody';
/**
* The location of registered JavaScript code block or files.
* This means the location is in the head section.
*/
const POS_HEAD = 1;
/**
* The location of registered JavaScript code block or files.
* This means the location is at the beginning of the body section.
*/
const POS_BEGIN = 2;
/**
* The location of registered JavaScript code block or files.
* This means the location is at the end of the body section.
*/
const POS_END = 3;
/**
* The location of registered JavaScript code block.
* This means the JavaScript code block will be enclosed within `jQuery(document).ready()`.
*/
const POS_READY = 4;
/**
* The location of registered JavaScript code block.
* This means the JavaScript code block will be enclosed within `jQuery(window).load()`.
*/
const POS_LOAD = 5;
/**
* This is internally used as the placeholder for receiving the content registered for the head section.
*/
const PH_HEAD = '<![CDATA[YII-BLOCK-HEAD]]>';
/**
* This is internally used as the placeholder for receiving the content registered for the beginning of the body section.
*/
const PH_BODY_BEGIN = '<![CDATA[YII-BLOCK-BODY-BEGIN]]>';
/**
* This is internally used as the placeholder for receiving the content registered for the end of the body section.
*/
const PH_BODY_END = '<![CDATA[YII-BLOCK-BODY-END]]>';
/**
* @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values
* are the registered [[AssetBundle]] objects.
* @see registerAssetBundle()
*/
public $assetBundles = [];
/**
* @var string the page title
*/
public $title;
/**
* @var array the registered meta tags.
* @see registerMetaTag()
*/
public $metaTags = [];
/**
* @var array the registered link tags.
* @see registerLinkTag()
*/
public $linkTags = [];
/**
* @var array the registered CSS code blocks.
* @see registerCss()
*/
public $css = [];
/**
* @var array the registered CSS files.
* @see registerCssFile()
*/
public $cssFiles = [];
/**
* @var array the registered JS code blocks
* @see registerJs()
*/
public $js = [];
/**
* @var array the registered JS files.
* @see registerJsFile()
*/
public $jsFiles = [];
private $_assetManager;
/**
* Marks the position of an HTML head section.
*/
public function head()
{
echo self::PH_HEAD;
}
/**
* Marks the beginning of an HTML body section.
*/
public function beginBody()
{
echo self::PH_BODY_BEGIN;
$this->trigger(self::EVENT_BEGIN_BODY);
}
/**
* Marks the ending of an HTML body section.
*/
public function endBody()
{
$this->trigger(self::EVENT_END_BODY);
echo self::PH_BODY_END;
foreach (array_keys($this->assetBundles) as $bundle) {
$this->registerAssetFiles($bundle);
}
}
/**
* Marks the ending of an HTML page.
* @param bool $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
*/
public function endPage($ajaxMode = false)
{
$this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean();
echo strtr($content, [
self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
]);
$this->clear();
}
/**
* Renders a view in response to an AJAX request.
*
* This method is similar to [[render()]] except that it will surround the view being rendered
* with the calls of [[beginPage()]], [[head()]], [[beginBody()]], [[endBody()]] and [[endPage()]].
* By doing so, the method is able to inject into the rendering result with JS/CSS scripts and files
* that are registered with the view.
*
* @param string $view the view name. Please refer to [[render()]] on how to specify this parameter.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @return string the rendering result
* @see render()
*/
public function renderAjax($view, $params = [], $context = null)
{
$viewFile = $this->findViewFile($view, $context);
ob_start();
ob_implicit_flush(false);
$this->beginPage();
$this->head();
$this->beginBody();
echo $this->renderFile($viewFile, $params, $context);
$this->endBody();
$this->endPage(true);
return ob_get_clean();
}
/**
* Registers the asset manager being used by this view object.
* @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component.
*/
public function getAssetManager()
{
return $this->_assetManager ?: Yii::$app->getAssetManager();
}
/**
* Sets the asset manager.
* @param \yii\web\AssetManager $value the asset manager
*/
public function setAssetManager($value)
{
$this->_assetManager = $value;
}
/**
* Clears up the registered meta tags, link tags, css/js scripts and files.
*/
public function clear()
{
$this->metaTags = [];
$this->linkTags = [];
$this->css = [];
$this->cssFiles = [];
$this->js = [];
$this->jsFiles = [];
$this->assetBundles = [];
}
/**
* Registers all files provided by an asset bundle including depending bundles files.
* Removes a bundle from [[assetBundles]] once files are registered.
* @param string $name name of the bundle to register
*/
protected function registerAssetFiles($name)
{
if (!isset($this->assetBundles[$name])) {
return;
}
$bundle = $this->assetBundles[$name];
if ($bundle) {
foreach ($bundle->depends as $dep) {
$this->registerAssetFiles($dep);
}
$bundle->registerAssetFiles($this);
}
unset($this->assetBundles[$name]);
}
/**
* Registers the named asset bundle.
* All dependent asset bundles will be registered.
* @param string $name the class name of the asset bundle (without the leading backslash)
* @param int|null $position if set, this forces a minimum position for javascript files.
* This will adjust depending assets javascript file position or fail if requirement can not be met.
* If this is null, asset bundles position settings will not be changed.
* See [[registerJsFile]] for more details on javascript position.
* @return AssetBundle the registered asset bundle instance
* @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
*/
public function registerAssetBundle($name, $position = null)
{
if (!isset($this->assetBundles[$name])) {
$am = $this->getAssetManager();
$bundle = $am->getBundle($name);
$this->assetBundles[$name] = false;
// register dependencies
$pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
}
$this->assetBundles[$name] = $bundle;
} elseif ($this->assetBundles[$name] === false) {
throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
} else {
$bundle = $this->assetBundles[$name];
}
if ($position !== null) {
$pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
if ($pos === null) {
$bundle->jsOptions['position'] = $pos = $position;
} elseif ($pos > $position) {
throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'.");
}
// update position for all dependencies
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
}
}
return $bundle;
}
/**
* Registers a meta tag.
*
* For example, a description meta tag can be added like the following:
*
* ```php
* $view->registerMetaTag([
* 'name' => 'description',
* 'content' => 'This website is about funny raccoons.'
* ]);
* ```
*
* will result in the meta tag `<meta name="description" content="This website is about funny raccoons.">`.
*
* @param array $options the HTML attributes for the meta tag.
* @param string $key the key that identifies the meta tag. If two meta tags are registered
* with the same key, the latter will overwrite the former. If this is null, the new meta tag
* will be appended to the existing ones.
*/
public function registerMetaTag($options, $key = null)
{
if ($key === null) {
$this->metaTags[] = Html::tag('meta', '', $options);
} else {
$this->metaTags[$key] = Html::tag('meta', '', $options);
}
}
/**
* Registers CSRF meta tags.
* They are rendered dynamically to retrieve a new CSRF token for each request.
*
* ```php
* $view->registerCsrfMetaTags();
* ```
*
* The above code will result in `<meta name="csrf-param" content="[yii\web\Request::$csrfParam]">`
* and `<meta name="csrf-token" content="tTNpWKpdy-bx8ZmIq9R72...K1y8IP3XGkzZA==">` added to the page.
*
* Note: Hidden CSRF input of ActiveForm will be automatically refreshed by calling `window.yii.refreshCsrfToken()`
* from `yii.js`.
*
* @since 2.0.13
*/
public function registerCsrfMetaTags()
{
$this->metaTags['csrf_meta_tags'] = $this->renderDynamic('return yii\helpers\Html::csrfMetaTags();');
}
/**
* Registers a link tag.
*
* For example, a link tag for a custom [favicon](http://www.w3.org/2005/10/howto-favicon)
* can be added like the following:
*
* ```php
* $view->registerLinkTag(['rel' => 'icon', 'type' => 'image/png', 'href' => '/myicon.png']);
* ```
*
* which will result in the following HTML: `<link rel="icon" type="image/png" href="/myicon.png">`.
*
* **Note:** To register link tags for CSS stylesheets, use [[registerCssFile()]] instead, which
* has more options for this kind of link tag.
*
* @param array $options the HTML attributes for the link tag.
* @param string $key the key that identifies the link tag. If two link tags are registered
* with the same key, the latter will overwrite the former. If this is null, the new link tag
* will be appended to the existing ones.
*/
public function registerLinkTag($options, $key = null)
{
if ($key === null) {
$this->linkTags[] = Html::tag('link', '', $options);
} else {
$this->linkTags[$key] = Html::tag('link', '', $options);
}
}
/**
* Registers a CSS code block.
* @param string $css the content of the CSS code block to be registered
* @param array $options the HTML attributes for the `<style>`-tag.
* @param string $key the key that identifies the CSS code block. If null, it will use
* $css as the key. If two CSS code blocks are registered with the same key, the latter
* will overwrite the former.
*/
public function registerCss($css, $options = [], $key = null)
{
$key = $key ?: md5($css);
$this->css[$key] = Html::style($css, $options);
}
/**
* Registers a CSS file.
*
* This method should be used for simple registration of CSS files. If you want to use features of
* [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]]
* and [[registerAssetBundle()]] instead.
*
* @param string $url the CSS file to be registered.
* @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for
* the supported options. The following options are specially handled and are not treated as HTML attributes:
*
* - `depends`: array, specifies the names of the asset bundles that this CSS file depends on.
*
* @param string $key the key that identifies the CSS script file. If null, it will use
* $url as the key. If two CSS files are registered with the same key, the latter
* will overwrite the former.
*/
public function registerCssFile($url, $options = [], $key = null)
{
$url = Yii::getAlias($url);
$key = $key ?: $url;
$depends = ArrayHelper::remove($options, 'depends', []);
if (empty($depends)) {
$this->cssFiles[$key] = Html::cssFile($url, $options);
} else {
$this->getAssetManager()->bundles[$key] = Yii::createObject([
'class' => AssetBundle::className(),
'baseUrl' => '',
'css' => [strncmp($url, '//', 2) === 0 ? $url : ltrim($url, '/')],
'cssOptions' => $options,
'depends' => (array) $depends,
]);
$this->registerAssetBundle($key);
}
}
/**
* Registers a JS code block.
* @param string $js the JS code block to be registered
* @param int $position the position at which the JS script tag should be inserted
* in a page. The possible values are:
*
* - [[POS_HEAD]]: in the head section
* - [[POS_BEGIN]]: at the beginning of the body section
* - [[POS_END]]: at the end of the body section
* - [[POS_LOAD]]: enclosed within jQuery(window).load().
* Note that by using this position, the method will automatically register the jQuery js file.
* - [[POS_READY]]: enclosed within jQuery(document).ready(). This is the default value.
* Note that by using this position, the method will automatically register the jQuery js file.
*
* @param string $key the key that identifies the JS code block. If null, it will use
* $js as the key. If two JS code blocks are registered with the same key, the latter
* will overwrite the former.
*/
public function registerJs($js, $position = self::POS_READY, $key = null)
{
$key = $key ?: md5($js);
$this->js[$position][$key] = $js;
if ($position === self::POS_READY || $position === self::POS_LOAD) {
JqueryAsset::register($this);
}
}
/**
* Registers a JS file.
*
* This method should be used for simple registration of JS files. If you want to use features of
* [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]]
* and [[registerAssetBundle()]] instead.
*
* @param string $url the JS file to be registered.
* @param array $options the HTML attributes for the script tag. The following options are specially handled
* and are not treated as HTML attributes:
*
* - `depends`: array, specifies the names of the asset bundles that this JS file depends on.
* - `position`: specifies where the JS script tag should be inserted in a page. The possible values are:
* * [[POS_HEAD]]: in the head section
* * [[POS_BEGIN]]: at the beginning of the body section
* * [[POS_END]]: at the end of the body section. This is the default value.
*
* Please refer to [[Html::jsFile()]] for other supported options.
*
* @param string $key the key that identifies the JS script file. If null, it will use
* $url as the key. If two JS files are registered with the same key at the same position, the latter
* will overwrite the former. Note that position option takes precedence, thus files registered with the same key,
* but different position option will not override each other.
*/
public function registerJsFile($url, $options = [], $key = null)
{
$url = Yii::getAlias($url);
$key = $key ?: $url;
$depends = ArrayHelper::remove($options, 'depends', []);
if (empty($depends)) {
$position = ArrayHelper::remove($options, 'position', self::POS_END);
$this->jsFiles[$position][$key] = Html::jsFile($url, $options);
} else {
$this->getAssetManager()->bundles[$key] = Yii::createObject([
'class' => AssetBundle::className(),
'baseUrl' => '',
'js' => [strncmp($url, '//', 2) === 0 ? $url : ltrim($url, '/')],
'jsOptions' => $options,
'depends' => (array) $depends,
]);
$this->registerAssetBundle($key);
}
}
/**
* Registers a JS code block defining a variable. The name of variable will be
* used as key, preventing duplicated variable names.
*
* @param string $name Name of the variable
* @param array|string $value Value of the variable
* @param int $position the position in a page at which the JavaScript variable should be inserted.
* The possible values are:
*
* - [[POS_HEAD]]: in the head section. This is the default value.
* - [[POS_BEGIN]]: at the beginning of the body section.
* - [[POS_END]]: at the end of the body section.
* - [[POS_LOAD]]: enclosed within jQuery(window).load().
* Note that by using this position, the method will automatically register the jQuery js file.
* - [[POS_READY]]: enclosed within jQuery(document).ready().
* Note that by using this position, the method will automatically register the jQuery js file.
*
* @since 2.0.14
*/
public function registerJsVar($name, $value, $position = self::POS_HEAD)
{
$js = sprintf('var %s = %s;', $name, \yii\helpers\Json::htmlEncode($value));
$this->registerJs($js, $position, $name);
}
/**
* Renders the content to be inserted in the head section.
* The content is rendered using the registered meta tags, link tags, CSS/JS code blocks and files.
* @return string the rendered content
*/
protected function renderHeadHtml()
{
$lines = [];
if (!empty($this->metaTags)) {
$lines[] = implode("\n", $this->metaTags);
}
if (!empty($this->linkTags)) {
$lines[] = implode("\n", $this->linkTags);
}
if (!empty($this->cssFiles)) {
$lines[] = implode("\n", $this->cssFiles);
}
if (!empty($this->css)) {
$lines[] = implode("\n", $this->css);
}
if (!empty($this->jsFiles[self::POS_HEAD])) {
$lines[] = implode("\n", $this->jsFiles[self::POS_HEAD]);
}
if (!empty($this->js[self::POS_HEAD])) {
$lines[] = Html::script(implode("\n", $this->js[self::POS_HEAD]));
}
return empty($lines) ? '' : implode("\n", $lines);
}
/**
* Renders the content to be inserted at the beginning of the body section.
* The content is rendered using the registered JS code blocks and files.
* @return string the rendered content
*/
protected function renderBodyBeginHtml()
{
$lines = [];
if (!empty($this->jsFiles[self::POS_BEGIN])) {
$lines[] = implode("\n", $this->jsFiles[self::POS_BEGIN]);
}
if (!empty($this->js[self::POS_BEGIN])) {
$lines[] = Html::script(implode("\n", $this->js[self::POS_BEGIN]));
}
return empty($lines) ? '' : implode("\n", $lines);
}
/**
* Renders the content to be inserted at the end of the body section.
* The content is rendered using the registered JS code blocks and files.
* @param bool $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
* @return string the rendered content
*/
protected function renderBodyEndHtml($ajaxMode)
{
$lines = [];
if (!empty($this->jsFiles[self::POS_END])) {
$lines[] = implode("\n", $this->jsFiles[self::POS_END]);
}
if ($ajaxMode) {
$scripts = [];
if (!empty($this->js[self::POS_END])) {
$scripts[] = implode("\n", $this->js[self::POS_END]);
}
if (!empty($this->js[self::POS_READY])) {
$scripts[] = implode("\n", $this->js[self::POS_READY]);
}
if (!empty($this->js[self::POS_LOAD])) {
$scripts[] = implode("\n", $this->js[self::POS_LOAD]);
}
if (!empty($scripts)) {
$lines[] = Html::script(implode("\n", $scripts));
}
} else {
if (!empty($this->js[self::POS_END])) {
$lines[] = Html::script(implode("\n", $this->js[self::POS_END]));
}
if (!empty($this->js[self::POS_READY])) {
$js = "jQuery(function ($) {\n" . implode("\n", $this->js[self::POS_READY]) . "\n});";
$lines[] = Html::script($js);
}
if (!empty($this->js[self::POS_LOAD])) {
$js = "jQuery(window).on('load', function () {\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});";
$lines[] = Html::script($js);
}
}
return empty($lines) ? '' : implode("\n", $lines);
}
}

131
vendor/yiisoft/yii2/web/ViewAction.php vendored Normal file
View File

@@ -0,0 +1,131 @@
<?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\Action;
use yii\base\ViewNotFoundException;
/**
* ViewAction represents an action that displays a view according to a user-specified parameter.
*
* By default, the view being displayed is specified via the `view` GET parameter.
* The name of the GET parameter can be customized via [[viewParam]].
*
* Users specify a view in the format of `path/to/view`, which translates to the view name
* `ViewPrefix/path/to/view` where `ViewPrefix` is given by [[viewPrefix]]. The view will then
* be rendered by the [[\yii\base\Controller::render()|render()]] method of the currently active controller.
*
* Note that the user-specified view name must start with a word character and can only contain
* word characters, forward slashes, dots and dashes.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ViewAction extends Action
{
/**
* @var string the name of the GET parameter that contains the requested view name.
*/
public $viewParam = 'view';
/**
* @var string the name of the default view when [[\yii\web\ViewAction::$viewParam]] GET parameter is not provided
* by user. Defaults to 'index'. This should be in the format of 'path/to/view', similar to that given in the
* GET parameter.
* @see \yii\web\ViewAction::$viewPrefix
*/
public $defaultView = 'index';
/**
* @var string a string to be prefixed to the user-specified view name to form a complete view name.
* For example, if a user requests for `tutorial/chap1`, the corresponding view name will
* be `pages/tutorial/chap1`, assuming the prefix is `pages`.
* The actual view file is determined by [[\yii\base\View::findViewFile()]].
* @see \yii\base\View::findViewFile()
*/
public $viewPrefix = 'pages';
/**
* @var mixed the name of the layout to be applied to the requested view.
* This will be assigned to [[\yii\base\Controller::$layout]] before the view is rendered.
* Defaults to null, meaning the controller's layout will be used.
* If false, no layout will be applied.
*/
public $layout;
/**
* Runs the action.
* This method displays the view requested by the user.
* @throws NotFoundHttpException if the view file cannot be found
*/
public function run()
{
$viewName = $this->resolveViewName();
$this->controller->actionParams[$this->viewParam] = Yii::$app->request->get($this->viewParam);
$controllerLayout = null;
if ($this->layout !== null) {
$controllerLayout = $this->controller->layout;
$this->controller->layout = $this->layout;
}
try {
$output = $this->render($viewName);
if ($controllerLayout) {
$this->controller->layout = $controllerLayout;
}
} catch (ViewNotFoundException $e) {
if ($controllerLayout) {
$this->controller->layout = $controllerLayout;
}
if (YII_DEBUG) {
throw new NotFoundHttpException($e->getMessage());
}
throw new NotFoundHttpException(
Yii::t('yii', 'The requested view "{name}" was not found.', ['name' => $viewName])
);
}
return $output;
}
/**
* Renders a view.
*
* @param string $viewName view name
* @return string result of the rendering
*/
protected function render($viewName)
{
return $this->controller->render($viewName);
}
/**
* Resolves the view name currently being requested.
*
* @return string the resolved view name
* @throws NotFoundHttpException if the specified view name is invalid
*/
protected function resolveViewName()
{
$viewName = Yii::$app->request->get($this->viewParam, $this->defaultView);
if (!is_string($viewName) || !preg_match('~^\w(?:(?!\/\.{0,2}\/)[\w\/\-\.])*$~', $viewName)) {
if (YII_DEBUG) {
throw new NotFoundHttpException("The requested view \"$viewName\" must start with a word character, must not contain /../ or /./, can contain only word characters, forward slashes, dots and dashes.");
}
throw new NotFoundHttpException(Yii::t('yii', 'The requested view "{name}" was not found.', ['name' => $viewName]));
}
return empty($this->viewPrefix) ? $viewName : $this->viewPrefix . '/' . $viewName;
}
}

View File

@@ -0,0 +1,185 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use DOMDocument;
use DOMElement;
use DOMException;
use DOMText;
use yii\base\Arrayable;
use yii\base\Component;
use yii\helpers\StringHelper;
/**
* XmlResponseFormatter formats the given data into an XML response content.
*
* It is used by [[Response]] to format response data.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class XmlResponseFormatter extends Component implements ResponseFormatterInterface
{
/**
* @var string the Content-Type header for the response
*/
public $contentType = 'application/xml';
/**
* @var string the XML version
*/
public $version = '1.0';
/**
* @var string the XML encoding. If not set, it will use the value of [[Response::charset]].
*/
public $encoding;
/**
* @var string the name of the root element. If set to false, null or is empty then no root tag should be added.
*/
public $rootTag = 'response';
/**
* @var string the name of the elements that represent the array elements with numeric keys.
*/
public $itemTag = 'item';
/**
* @var bool whether to interpret objects implementing the [[\Traversable]] interface as arrays.
* Defaults to `true`.
* @since 2.0.7
*/
public $useTraversableAsArray = true;
/**
* @var bool if object tags should be added
* @since 2.0.11
*/
public $useObjectTags = true;
/**
* Formats the specified response.
* @param Response $response the response to be formatted.
*/
public function format($response)
{
$charset = $this->encoding === null ? $response->charset : $this->encoding;
if (stripos($this->contentType, 'charset') === false) {
$this->contentType .= '; charset=' . $charset;
}
$response->getHeaders()->set('Content-Type', $this->contentType);
if ($response->data !== null) {
$dom = new DOMDocument($this->version, $charset);
if (!empty($this->rootTag)) {
$root = new DOMElement($this->rootTag);
$dom->appendChild($root);
$this->buildXml($root, $response->data);
} else {
$this->buildXml($dom, $response->data);
}
$response->content = $dom->saveXML();
}
}
/**
* @param DOMElement $element
* @param mixed $data
*/
protected function buildXml($element, $data)
{
if (is_array($data) ||
($data instanceof \Traversable && $this->useTraversableAsArray && !$data instanceof Arrayable)
) {
foreach ($data as $name => $value) {
if (is_int($name) && is_object($value)) {
$this->buildXml($element, $value);
} elseif (is_array($value) || is_object($value)) {
$child = new DOMElement($this->getValidXmlElementName($name));
$element->appendChild($child);
$this->buildXml($child, $value);
} else {
$child = new DOMElement($this->getValidXmlElementName($name));
$element->appendChild($child);
$child->appendChild(new DOMText($this->formatScalarValue($value)));
}
}
} elseif (is_object($data)) {
if ($this->useObjectTags) {
$child = new DOMElement(StringHelper::basename(get_class($data)));
$element->appendChild($child);
} else {
$child = $element;
}
if ($data instanceof Arrayable) {
$this->buildXml($child, $data->toArray());
} else {
$array = [];
foreach ($data as $name => $value) {
$array[$name] = $value;
}
$this->buildXml($child, $array);
}
} else {
$element->appendChild(new DOMText($this->formatScalarValue($data)));
}
}
/**
* Formats scalar value to use in XML text node.
*
* @param int|string|bool|float $value a scalar value.
* @return string string representation of the value.
* @since 2.0.11
*/
protected function formatScalarValue($value)
{
if ($value === true) {
return 'true';
}
if ($value === false) {
return 'false';
}
if (is_float($value)) {
return StringHelper::floatToString($value);
}
return (string) $value;
}
/**
* Returns element name ready to be used in DOMElement if
* name is not empty, is not int and is valid.
*
* Falls back to [[itemTag]] otherwise.
*
* @param mixed $name
* @return string
* @since 2.0.12
*/
protected function getValidXmlElementName($name)
{
if (empty($name) || is_int($name) || !$this->isValidXmlName($name)) {
return $this->itemTag;
}
return $name;
}
/**
* Checks if name is valid to be used in XML.
*
* @param mixed $name
* @return bool
* @see http://stackoverflow.com/questions/2519845/how-to-check-if-string-is-a-valid-xml-element-name/2519943#2519943
* @since 2.0.12
*/
protected function isValidXmlName($name)
{
try {
new DOMElement($name);
return true;
} catch (DOMException $e) {
return false;
}
}
}

25
vendor/yiisoft/yii2/web/YiiAsset.php vendored Normal file
View File

@@ -0,0 +1,25 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* This asset bundle provides the base JavaScript files for the Yii Framework.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class YiiAsset extends AssetBundle
{
public $sourcePath = '@yii/assets';
public $js = [
'yii.js',
];
public $depends = [
'yii\web\JqueryAsset',
];
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
use yii\db\Migration;
/**
* Initializes Session tables.
*
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0.8
*/
class m160313_153426_session_init extends Migration
{
/**
* {@inheritdoc}
*/
public function up()
{
$dataType = $this->binary();
$tableOptions = null;
switch ($this->db->driverName) {
case 'mysql':
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
break;
case 'sqlsrv':
case 'mssql':
case 'dblib':
$dataType = $this->text();
break;
}
$this->createTable('{{%session}}', [
'id' => $this->string()->notNull(),
'expire' => $this->integer(),
'data' => $dataType,
'PRIMARY KEY ([[id]])',
], $tableOptions);
}
/**
* {@inheritdoc}
*/
public function down()
{
$this->dropTable('{{%session}}');
}
}

View File

@@ -0,0 +1,21 @@
/**
* Database schema required by \yii\web\DbSession.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0.8
*/
if object_id('[session]', 'U') is not null
drop table [session];
create table [session]
(
[id] varchar(256) not null,
[expire] integer,
[data] nvarchar(max),
primary key ([id])
);

View File

@@ -0,0 +1,20 @@
/**
* Database schema required by \yii\web\DbSession.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0.8
*/
drop table if exists `session`;
create table `session`
(
`id` varchar(256) not null,
`expire` integer,
`data` LONGBLOB,
primary key (`id`)
) engine InnoDB;

View File

@@ -0,0 +1,20 @@
/**
* Database schema required by \yii\web\DbSession.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0.8
*/
drop table if exists "session";
create table "session"
(
"id" varchar(256) not null,
"expire" integer,
"data" BYTEA,
primary key ("id")
);

View File

@@ -0,0 +1,20 @@
/**
* Database schema required by \yii\web\DbSession.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0.8
*/
drop table if exists "session";
create table "session"
(
"id" varchar(256) not null,
"expire" integer,
"data" bytea,
primary key ("id")
);

View File

@@ -0,0 +1,20 @@
/**
* Database schema required by \yii\web\DbSession.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0.8
*/
drop table if exists "session";
create table "session"
(
"id" varchar(256) not null,
"expire" integer,
"data" BLOB,
primary key ("id")
);