Browse Source

Merge branch 'upstream' into 313-Inflector-Helper

* upstream:
  Enhanced the detection of secure connection.
  Refactored Modal.
  < PHP 5.3 compatibility for req checker
  code style and UI improvements to requirements checker
  readded accidentally removed .gitignore file
  Changed Yii.php case in some files where it was wrong
  Finished bootstrap Widget and Modal.
  PHP Intl extension has been added to default Yii requirements.
  moved optional packages to "suggest", updated platform requirements
  "vendor-dir": "vendor" is default, removed
  fixed auth manager unit test to not expect generic exception
  fixed range requests, tests improved
tags/2.0.0-beta
Antonio Ramirez 12 years ago
parent
commit
3a5f01cb6e
  1. 1
      apps/bootstrap/assets/.gitignore
  2. 3
      apps/bootstrap/composer.json
  3. 2
      apps/bootstrap/www/index.php
  4. 2
      apps/bootstrap/yii
  5. 10
      tests/unit/framework/rbac/ManagerTestBase.php
  6. 32
      tests/unit/framework/web/ResponseTest.php
  7. 2
      yii/base/View.php
  8. 359
      yii/bootstrap/Modal.php
  9. 127
      yii/bootstrap/Widget.php
  10. 14
      yii/composer.json
  11. 32
      yii/requirements/YiiRequirementChecker.php
  12. 11
      yii/requirements/requirements.php
  13. 26
      yii/requirements/views/web/index.php
  14. 3
      yii/web/Request.php
  15. 11
      yii/web/Response.php

1
apps/bootstrap/assets/.gitignore vendored

@ -0,0 +1 @@
*

3
apps/bootstrap/composer.json

@ -12,9 +12,6 @@
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"config": {
"vendor-dir": "vendor"
},
"minimum-stability": "dev",
"require": {
"php": ">=5.3.0",

2
apps/bootstrap/www/index.php

@ -3,7 +3,7 @@
// comment out the following line to disable debug mode
defined('YII_DEBUG') or define('YII_DEBUG', true);
require(__DIR__ . '/../vendor/yiisoft/yii2/yii.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/../vendor/autoload.php');
$config = require(__DIR__ . '/../config/main.php');

2
apps/bootstrap/yii

@ -13,7 +13,7 @@ defined('YII_DEBUG') or define('YII_DEBUG', true);
// fcgi doesn't have STDIN defined by default
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
require(__DIR__ . '/vendor/yiisoft/yii2/yii.php');
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/vendor/autoload.php');
$config = require(__DIR__ . '/config/console.php');

10
tests/unit/framework/rbac/ManagerTestBase.php

@ -32,7 +32,7 @@ abstract class ManagerTestBase extends TestCase
$this->assertEquals($item2->type, Item::TYPE_ROLE);
// test adding an item with the same name
$this->setExpectedException('Exception');
$this->setExpectedException('\yii\base\Exception');
$this->auth->createItem($name, $type, $description, $bizRule, $data);
}
@ -69,14 +69,14 @@ abstract class ManagerTestBase extends TestCase
$this->auth->addItemChild('createPost', 'updatePost');
// test adding upper level item to lower one
$this->setExpectedException('Exception');
$this->setExpectedException('\yii\base\Exception');
$this->auth->addItemChild('readPost', 'reader');
}
public function testAddItemChild2()
{
// test adding inexistent items
$this->setExpectedException('Exception');
$this->setExpectedException('\yii\base\Exception');
$this->assertFalse($this->auth->addItemChild('createPost2', 'updatePost'));
}
@ -105,7 +105,7 @@ abstract class ManagerTestBase extends TestCase
$this->assertEquals($auth->bizRule, 'rule');
$this->assertEquals($auth->data, 'data');
$this->setExpectedException('Exception');
$this->setExpectedException('\yii\base\Exception');
$this->auth->assign('new user', 'createPost2', 'rule', 'data');
}
@ -158,7 +158,7 @@ abstract class ManagerTestBase extends TestCase
public function testDetectLoop()
{
$this->setExpectedException('Exception');
$this->setExpectedException('\yii\base\Exception');
$this->auth->addItemChild('readPost', 'readPost');
}

32
tests/unit/framework/web/ResponseTest.php

@ -41,7 +41,7 @@ class ResponseTest extends \yiiunit\TestCase
static::$httpResponseCode = 200;
}
public function ranges()
public function rightRanges()
{
// TODO test more cases for range requests and check for rfc compatibility
// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
@ -53,14 +53,14 @@ class ResponseTest extends \yiiunit\TestCase
}
/**
* @dataProvider ranges
* @dataProvider rightRanges
*/
public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedFile)
{
$content = $this->generateTestFileContent();
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
$sent = $this->runSendFile('testFile.txt', $content, null);
$this->assertEquals($expectedFile, $sent);
$this->assertTrue(in_array('HTTP/1.1 206 Partial Content', static::$headers));
$this->assertTrue(in_array('Accept-Ranges: bytes', static::$headers));
@ -69,6 +69,30 @@ class ResponseTest extends \yiiunit\TestCase
$this->assertTrue(in_array('Content-Length: ' . $length, static::$headers));
}
public function wrongRanges()
{
// TODO test more cases for range requests and check for rfc compatibility
// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
return array(
array('1-2,3-5,6-10'), // multiple range request not supported
array('5-1'), // last-byte-pos value is less than its first-byte-pos value
array('-100000'), // last-byte-pos bigger then content length
array('10000-'), // first-byte-pos bigger then content length
);
}
/**
* @dataProvider wrongRanges
*/
public function testSendFileWrongRanges($rangeHeader)
{
$this->setExpectedException('yii\base\HttpException', 'Requested Range Not Satisfiable');
$content = $this->generateTestFileContent();
$_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader;
$this->runSendFile('testFile.txt', $content, null);
}
protected function generateTestFileContent()
{
return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?';
@ -83,4 +107,4 @@ class ResponseTest extends \yiiunit\TestCase
$file = ob_get_clean();
return $file;
}
}
}

2
yii/base/View.php

@ -741,7 +741,7 @@ class View extends Component
$lines[] = Html::script(implode("\n", $this->js[self::POS_END]), array('type' => 'text/javascript'));
}
if (!empty($this->js[self::POS_READY])) {
$js = "jQuery(document).ready(function(){\n{" . implode("\n", $this->js[self::POS_READY]) . "}\n});";
$js = "jQuery(document).ready(function(){\n" . implode("\n", $this->js[self::POS_READY]) . "\n});";
$lines[] = Html::script($js, array('type' => 'text/javascript'));
}
return empty($lines) ? '' : implode("\n", $lines) . "\n";

359
yii/bootstrap/Modal.php

@ -8,279 +8,234 @@
namespace yii\bootstrap;
use Yii;
use yii\helpers\Html;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* Modal renders a bootstrap modal on the page for its use on your application.
* Modal renders a modal window that can be toggled by clicking on a button.
*
* For example,
*
* Basic usage:
* ~~~php
* echo Modal::widget(array(
* 'header' => '<h2>Hello world</h2>',
* 'body' => 'Say hello...',
* 'toggleButton' => array(
* 'label' => 'click me',
* ),
* ));
* ~~~
*
* The following example will show the content enclosed between the [[begin()]]
* and [[end()]] calls within the modal window:
*
* ```php
* $this->widget(Modal::className(), array(
* 'id' => 'myModal',
* 'header' => 'Modal Heading',
* 'content' => '<p>One fine body...</p>',
* 'footer' => 'Modal Footer',
* // if we wish to display a modal button
* 'buttonOptions' => array(
* 'label' => 'Show Modal',
* 'class' => 'btn btn-primary'
* )
* ~~~php
* Modal::begin(array(
* 'header' => '<h2>Hello world</h2>',
* 'toggleButton' => array(
* 'label' => 'click me',
* ),
* ));
* ```
*
* echo 'Say hello...';
*
* Modal::end();
* ~~~
*
* @see http://twitter.github.io/bootstrap/javascript.html#modals
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Modal extends Widget
{
/**
* @var array The additional HTML attributes of the button that will show the modal. If empty array, only
* the markup of the modal will be rendered on the page, so users can easily call the modal manually with their own
* scripts. The following special attributes are available:
* <ul>
* <li>label: string, the label of the button</li>
* </ul>
*
* For available options of the button trigger, see http://twitter.github.com/bootstrap/javascript.html#modals.
*/
public $buttonOptions = array();
/**
* @var boolean indicates whether the modal should use transitions. Defaults to 'true'.
*/
public $fade = true;
/**
* @var bool $keyboard, closes the modal when escape key is pressed.
*/
public $keyboard = true;
/**
* @var bool $show, shows the modal when initialized.
*/
public $show = false;
/**
* @var mixed includes a modal-backdrop element. Alternatively, specify `static` for a backdrop which doesn't close
* the modal on click.
*/
public $backdrop = true;
/**
* @var mixed the remote url. If a remote url is provided, content will be loaded via jQuery's load method and
* injected into the .modal-body of the modal.
* @var string the header content in the modal window.
*/
public $remote;
/**
* @var string a javascript function that will be invoked immediately when the `show` instance method is called.
*/
public $onShow;
/**
* @var string a javascript function that will be invoked when the modal has been made visible to the user
* (will wait for css transitions to complete).
*/
public $onShown;
/**
* @var string a javascript function that will be invoked immediately when the hide instance method has been called.
*/
public $onHide;
/**
* @var string a javascript function that will be invoked when the modal has finished being hidden from the user
* (will wait for css transitions to complete).
*/
public $onHidden;
/**
* @var string[] the Javascript event handlers.
*/
protected $events = array();
public $header;
/**
* @var array $pluginOptions the plugin options.
* @var string the body content in the modal window. Note that anything between
* the [[begin()]] and [[end()]] calls of the Modal widget will also be treated
* as the body content, and will be rendered before this.
*/
protected $pluginOptions = array();
public $body;
/**
* @var string
* @var string the footer content in the modal window.
*/
public $closeText = '&times;';
public $footer;
/**
* @var string header content. Header can also be a path to a view file.
* @var array the options for rendering the close button tag.
* The close button is displayed in the header of the modal window. Clicking
* on the button will hide the modal window. If this is null, no close button will be rendered.
*
* The following special options are supported:
*
* - tag: string, the tag name of the button. Defaults to 'button'.
* - label: string, the label of the button. Defaults to '&times;'.
*
* The rest of the options will be rendered as the HTML attributes of the button tag.
* Please refer to the [Modal plugin help](http://twitter.github.com/bootstrap/javascript.html#modals)
* for the supported HTML attributes.
*/
public $header;
public $closeButton = array();
/**
* @var string body of modal. Body can also be a path to a view file.
* @var array the options for rendering the toggle button tag.
* The toggle button is used to toggle the visibility of the modal window.
* If this property is null, no toggle button will be rendered.
*
* The following special options are supported:
*
* - tag: string, the tag name of the button. Defaults to 'button'.
* - label: string, the label of the button. Defaults to 'Show'.
*
* The rest of the options will be rendered as the HTML attributes of the button tag.
* Please refer to the [Modal plugin help](http://twitter.github.com/bootstrap/javascript.html#modals)
* for the supported HTML attributes.
*/
public $content;
public $toggleButton;
/**
* @var string footer content. Content can also be a path to a view file.
*/
public $footer;
/**
* Widget's init method
* Initializes the widget.
*/
public function init()
{
parent::init();
$this->name = 'modal';
$this->defaultOption('id', $this->getId());
$this->defaultOption('role', 'dialog');
$this->defaultOption('tabindex', '-1');
$this->addClassName('modal');
$this->addClassName('hide');
if ($this->fade)
$this->addClassName('fade');
$this->initOptions();
$this->initPluginOptions();
$this->initPluginEvents();
echo $this->renderToggleButton() . "\n";
echo Html::beginTag('div', $this->options) . "\n";
echo $this->renderHeader() . "\n";
echo $this->renderBodyBegin() . "\n";
}
/**
* Initialize plugin events if any
* Renders the widget.
*/
public function initPluginEvents()
{
foreach (array('onShow', 'onShown', 'onHide', 'onHidden') as $event) {
if ($this->{$event} !== null) {
$modalEvent = strtolower(substr($event, 2));
if ($this->{$event} instanceof JsExpression)
$this->events[$modalEvent] = $this->$event;
else
$this->events[$modalEvent] = new JsExpression($this->{$event});
}
}
}
/**
* Initialize plugin options.
* ***Important***: The display of the button overrides the initialization of the modal bootstrap widget.
*/
public function initPluginOptions()
public function run()
{
if (null !== $this->remote)
$this->pluginOptions['remote'] = Html::url($this->remote);
echo "\n" . $this->renderBodyEnd();
echo "\n" . $this->renderFooter();
echo "\n" . Html::endTag('div');
foreach (array('backdrop', 'keyboard', 'show') as $option) {
$this->pluginOptions[$option] = isset($this->pluginOptions[$option])
? $this->pluginOptions[$option]
: $this->{$option};
}
$this->registerPlugin('modal');
}
/**
* Widget's run method
* Renders the header HTML markup of the modal
* @return string the rendering result
*/
public function run()
protected function renderHeader()
{
$this->renderModal();
$this->renderButton();
$this->registerScript();
$button = $this->renderCloseButton();
if ($button !== null) {
$this->header = $button . "\n" . $this->header;
}
if ($this->header !== null) {
return Html::tag('div', "\n" . $this->header . "\n", array('class' => 'modal-header'));
} else {
return null;
}
}
/**
* Renders the button that will open the modal if its options have been configured
* Renders the opening tag of the modal body.
* @return string the rendering result
*/
public function renderButton()
protected function renderBodyBegin()
{
if (!empty($this->buttonOptions)) {
$this->buttonOptions['data-toggle'] = isset($this->buttonOptions['data-toggle'])
? $this->buttonOptions['data-toggle']
: 'modal';
if ($this->remote !== null && !isset($this->buttonOptions['data-remote']))
$this->buttonOptions['data-remote'] = Html::url($this->remote);
$label = ArrayHelper::remove($this->buttonOptions, 'label', 'Button');
$name = ArrayHelper::remove($this->buttonOptions, 'name');
$value = ArrayHelper::remove($this->buttonOptions, 'value');
$attr = isset($this->buttonOptions['data-remote'])
? 'data-target'
: 'href';
$this->buttonOptions[$attr] = isset($this->buttonOptions[$attr])
? $this->buttonOptions[$attr]
: '#' . ArrayHelper::getValue($this->options, 'id');
echo Html::button($label, $name, $value, $this->buttonOptions);
}
return Html::beginTag('div', array('class' => 'modal-body'));
}
/**
* Renders the modal markup
* Renders the closing tag of the modal body.
* @return string the rendering result
*/
public function renderModal()
protected function renderBodyEnd()
{
echo Html::beginTag('div', $this->options);
$this->renderModalHeader();
$this->renderModalBody();
$this->renderModalFooter();
echo Html::endTag('div');
return $this->body . "\n" . Html::endTag('div');
}
/**
* Renders the header HTML markup of the modal
* Renders the HTML markup for the footer of the modal
* @return string the rendering result
*/
public function renderModalHeader()
protected function renderFooter()
{
echo Html::beginTag('div', array('class'=>'modal-header'));
if ($this->closeText)
echo Html::button($this->closeText, null, null, array('data-dismiss' => 'modal', 'class'=>'close'));
echo $this->header;
echo Html::endTag('div');
if ($this->footer !== null) {
return Html::tag('div', "\n" . $this->footer . "\n", array('class' => 'modal-footer'));
} else {
return null;
}
}
/**
* Renders the HTML markup for the body of the modal
* Renders the toggle button.
* @return string the rendering result
*/
public function renderModalBody()
protected function renderToggleButton()
{
echo Html::beginTag('div', array('class'=>'modal-body'));
echo $this->content;
echo Html::endTag('div');
if ($this->toggleButton !== null) {
$tag = ArrayHelper::remove($this->toggleButton, 'tag', 'button');
$label = ArrayHelper::remove($this->toggleButton, 'label', 'Show');
if ($tag === 'button' && !isset($this->toggleButton['type'])) {
$this->toggleButton['type'] = 'button';
}
return Html::tag($tag, $label, $this->toggleButton);
} else {
return null;
}
}
/**
* Renders the HTML markup for the footer of the modal
* Renders the close button.
* @return string the rendering result
*/
public function renderModalFooter()
protected function renderCloseButton()
{
echo Html::beginTag('div', array('class'=>'modal-footer'));
echo $this->footer;
echo Html::endTag('div');
if ($this->closeButton !== null) {
$tag = ArrayHelper::remove($this->closeButton, 'tag', 'button');
$label = ArrayHelper::remove($this->closeButton, 'label', '&times;');
if ($tag === 'button' && !isset($this->closeButton['type'])) {
$this->closeButton['type'] = 'button';
}
return Html::tag($tag, $label, $this->closeButton);
} else {
return null;
}
}
/**
* Registers client scripts
* Initializes the widget options.
* This method sets the default values for various options.
*/
public function registerScript()
protected function initOptions()
{
// do we render a button? If so, bootstrap will handle its behavior through its
// mark-up, otherwise, register the plugin.
if(empty($this->buttonOptions))
$this->registerPlugin('modal', $this->pluginOptions);
$this->options = array_merge(array(
'class' => 'modal hide',
), $this->options);
$this->addCssClass($this->options, 'modal');
$this->pluginOptions = array_merge(array(
'show' => false,
), $this->pluginOptions);
if ($this->closeButton !== null) {
$this->closeButton = array_merge(array(
'data-dismiss' => 'modal',
'aria-hidden' => 'true',
'class' => 'close',
), $this->closeButton);
}
// register events
$this->registerEvents($this->events);
if ($this->toggleButton !== null) {
$this->toggleButton = array_merge(array(
'data-toggle' => 'modal',
), $this->toggleButton);
if (!isset($this->toggleButton['data-target']) && !isset($this->toggleButton['href'])) {
$this->toggleButton['data-target'] = '#' . $this->options['id'];
}
}
}
}
}

127
yii/bootstrap/Widget.php

@ -9,19 +9,20 @@ namespace yii\bootstrap;
use Yii;
use yii\base\View;
use yii\helpers\Json;
/**
* Bootstrap is the base class for bootstrap widgets.
* \yii\bootstrap\Widget is the base class for all bootstrap widgets.
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Widget extends \yii\base\Widget
{
/**
* @var bool whether to register the asset
* @var boolean whether to use the responsive version of Bootstrap.
*/
public static $responsive = true;
@ -29,95 +30,75 @@ class Widget extends \yii\base\Widget
* @var array the HTML attributes for the widget container tag.
*/
public $options = array();
/**
* Initializes the widget.
* @var array the options for the underlying Bootstrap JS plugin.
* Please refer to the corresponding Bootstrap plugin Web page for possible options.
* For example, [this page](http://twitter.github.io/bootstrap/javascript.html#modals) shows
* how to use the "Modal" plugin and the supported options (e.g. "remote").
*/
public function init()
{
// ensure bundle
$this->registerBundle(static::$responsive);
}
public $pluginOptions = array();
/**
* Registers plugin events with the API.
* @param string $selector the CSS selector.
* @param string[] $events the JavaScript event configuration (name=>handler).
* @return boolean whether the events were registered.
* @todo To be discussed
* @var array the event handlers for the underlying Bootstrap JS plugin.
* Please refer to the corresponding Bootstrap plugin Web page for possible events.
* For example, [this page](http://twitter.github.io/bootstrap/javascript.html#modals) shows
* how to use the "Modal" plugin and the supported events (e.g. "shown").
*/
protected function registerEvents($selector, $events = array())
{
if (empty($events))
return;
$script = '';
foreach ($events as $name => $handler) {
$handler = ($handler instanceof JsExpression)
? $handler
: new JsExpression($handler);
public $pluginEvents = array();
$script .= ";jQuery('{$selector}').on('{$name}', {$handler});";
}
if (!empty($script))
$this->view->registerJs($script);
}
/**
* Registers a specific Bootstrap plugin using the given selector and options.
*
* @param string $name the name of the javascript widget to initialize
* @param array $options the Javascript options for the plugin
* Initializes the widget.
* This method will register the bootstrap asset bundle. If you override this method,
* make sure you call the parent implementation first.
*/
public function registerPlugin($name, $options = array())
public function init()
{
$selector = '#' . ArrayHelper::getValue($this->options, 'id');
$options = !empty($options) ? Json::encode($options) : '';
$script = ";jQuery('{$selector}').{$name}({$options});";
$this->view->registerJs($script);
parent::init();
if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId();
}
}
/**
* Registers bootstrap bundle
* @param bool $responsive
* Registers a specific Bootstrap plugin and the related events
* @param string $name the name of the Bootstrap plugin
*/
public function registerBundle($responsive = false)
protected function registerPlugin($name)
{
$bundle = $responsive ? 'yii/bootstrap-responsive' : 'yii/bootstrap';
$this->view->registerAssetBundle($bundle);
}
$id = $this->options['id'];
$view = $this->getView();
$bundle = static::$responsive ? 'yii/bootstrap-responsive' : 'yii/bootstrap';
$view->registerAssetBundle($bundle);
/**
* Adds a new class to options. If the class key does not exists, it will create one, if it exists it will append
* the value and also makes sure the uniqueness of them.
*
* @param string $class
* @return array
*/
protected function addClassName($class)
{
if (isset($this->options['class'])) {
if (!is_array($this->options['class']))
$this->options['class'] = explode(' ', $this->options['class']);
$this->options['class'][] = $class;
$this->options['class'] = array_unique($this->options['class']);
$this->options['class'] = implode(' ', $this->options['class']);
} else
$this->options['class'] = $class;
return $this->options;
if ($this->pluginOptions !== false) {
$options = empty($this->pluginOptions) ? '' : Json::encode($this->pluginOptions);
$js = "jQuery('#$id').$name($options);";
$view->registerJs($js);
}
if (!empty($this->pluginEvents)) {
$js = array();
foreach ($this->pluginEvents as $event => $handler) {
$js[] = "jQuery('#$id').on('$event', $handler);";
}
$view->registerJs(implode("\n", $js));
}
}
/**
* Sets the default value for an item if not set.
* @param string $key the name of the item.
* @param mixed $value the default value.
* @return array
* Adds a CSS class to the specified options.
* This method will ensure that the CSS class is unique and the "class" option is properly formatted.
* @param array $options the options to be modified.
* @param string $class the CSS class to be added
*/
protected function defaultOption($key, $value)
protected function addCssClass(&$options, $class)
{
if (!isset($this->options[$key]))
$this->options[$key] = $value;
return $this->options;
if (isset($options['class'])) {
$classes = preg_split('/\s+/', $options['class'] . ' ' . $class, -1, PREG_SPLIT_NO_EMPTY);
$options['class'] = implode(' ', array_unique($classes));
} else {
$options['class'] = $class;
}
}
}
}

14
yii/composer.json

@ -64,10 +64,14 @@
"source": "https://github.com/yiisoft/yii2"
},
"require": {
"php": ">=5.3.0",
"michelf/php-markdown": "1.3",
"twig/twig": "1.12.*",
"smarty/smarty": "3.1.*",
"ezyang/htmlpurifier": "v4.5.0"
"php": ">=5.3.11",
"ext-mbstring": "*",
"lib-pcre": "*"
},
"suggest": {
"michelf/php-markdown": "Required for Markdown helper.",
"twig/twig": "Required for TwigViewRenderer.",
"smarty/smarty": "Required for SmartyViewRenderer.",
"ezyang/htmlpurifier": "Required for Purifier helper."
}
}

32
yii/requirements/YiiRequirementChecker.php

@ -16,7 +16,7 @@ if (version_compare(PHP_VERSION, '4.3', '<')) {
*
* Example:
*
* ~~~
* ~~~php
* require_once('path/to/YiiRequirementChecker.php');
* $requirementsChecker = new YiiRequirementChecker();
* $requirements = array(
@ -62,7 +62,7 @@ class YiiRequirementChecker
* If a string, it is treated as the path of the file, which contains the requirements;
* @return YiiRequirementChecker self instance.
*/
function check($requirements)
public function check($requirements)
{
if (is_string($requirements)) {
$requirements = require($requirements);
@ -132,7 +132,7 @@ class YiiRequirementChecker
* )
* </code>
*/
function getResult()
public function getResult()
{
if (isset($this->result)) {
return $this->result;
@ -145,7 +145,7 @@ class YiiRequirementChecker
* Renders the requirements check result.
* The output will vary depending is a script running from web or from console.
*/
function render()
public function render()
{
if (!isset($this->result)) {
$this->usageError('Nothing to render!');
@ -166,7 +166,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='
* @return boolean if PHP extension version matches.
*/
function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
public function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
{
if (!extension_loaded($extensionName)) {
return false;
@ -183,7 +183,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is on.
*/
function checkPhpIniOn($name)
public function checkPhpIniOn($name)
{
$value = ini_get($name);
if (empty($value)) {
@ -197,7 +197,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is off.
*/
function checkPhpIniOff($name)
public function checkPhpIniOff($name)
{
$value = ini_get($name);
if (empty($value)) {
@ -214,7 +214,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='.
* @return boolean comparison result.
*/
function compareByteSize($a, $b, $compare = '>=')
public function compareByteSize($a, $b, $compare = '>=')
{
$compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
return $this->evaluateExpression($compareExpression);
@ -226,7 +226,7 @@ class YiiRequirementChecker
* @param string $verboseSize verbose size representation.
* @return integer actual size in bytes.
*/
function getByteSize($verboseSize)
public function getByteSize($verboseSize)
{
if (empty($verboseSize)) {
return 0;
@ -265,7 +265,7 @@ class YiiRequirementChecker
* @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
* @return boolean success.
*/
function checkUploadMaxFileSize($min = null, $max = null)
public function checkUploadMaxFileSize($min = null, $max = null)
{
$postMaxSize = ini_get('post_max_size');
$uploadMaxFileSize = ini_get('upload_max_filesize');
@ -292,7 +292,7 @@ class YiiRequirementChecker
* @param boolean $_return_ whether the rendering result should be returned as a string
* @return string the rendering result. Null if the rendering result is not required.
*/
function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
public function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
{
// we use special variable names here to avoid conflict when extracting data
if (is_array($_data_)) {
@ -316,7 +316,7 @@ class YiiRequirementChecker
* @param int $requirementKey requirement key in the list.
* @return array normalized requirement.
*/
function normalizeRequirement($requirement, $requirementKey = 0)
public function normalizeRequirement($requirement, $requirementKey = 0)
{
if (!is_array($requirement)) {
$this->usageError('Requirement must be an array!');
@ -354,7 +354,7 @@ class YiiRequirementChecker
* This method will then terminate the execution of the current application.
* @param string $message the error message
*/
function usageError($message)
public function usageError($message)
{
echo "Error: $message\n\n";
exit(1);
@ -365,7 +365,7 @@ class YiiRequirementChecker
* @param string $expression a PHP expression to be evaluated.
* @return mixed the expression result.
*/
function evaluateExpression($expression)
public function evaluateExpression($expression)
{
return eval('return ' . $expression . ';');
}
@ -374,7 +374,7 @@ class YiiRequirementChecker
* Returns the server information.
* @return string server information.
*/
function getServerInfo()
public function getServerInfo()
{
$info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
return $info;
@ -384,7 +384,7 @@ class YiiRequirementChecker
* Returns the now date if possible in string representation.
* @return string now date.
*/
function getNowDate()
public function getNowDate()
{
$nowDate = @strftime('%Y-%m-%d %H:%M', time());
return $nowDate;

11
yii/requirements/requirements.php

@ -1,7 +1,9 @@
<?php
/**
* This is the Yii core requirements for the [[YiiRequirementChecker]] instance.
* These are the Yii core requirements for the [[YiiRequirementChecker]] instance.
* These requirements are mandatory for any Yii application.
*
* @var $this YiiRequirementChecker
*/
return array(
array(
@ -36,4 +38,11 @@ return array(
'by' => '<a href="http://www.php.net/manual/en/book.mbstring.php">Multibyte string</a> processing',
'memo' => 'Required for multibyte encoding string processing.'
),
array(
'name' => 'Intl extension',
'mandatory' => false,
'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2'),
'by' => '<a href="http://www.php.net/manual/en/book.intl.php">Internationalization</a> support',
'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use <abbr title="Internationalized domain names">IDN</abbr>-feature of EmailValidator or UrlValidator.'
),
);

26
yii/requirements/views/web/index.php

@ -8,7 +8,7 @@
<head>
<meta charset="utf-8"/>
<title>Yii Application Requirement Checker</title>
<?php $this->renderViewFile(dirname(__FILE__).DIRECTORY_SEPARATOR.'css.php'); ?>
<?php $this->renderViewFile(dirname(__FILE__) . '/css.php'); ?>
</head>
<body>
<div class="container">
@ -25,14 +25,26 @@
It checks if the server is running the right version of PHP,
if appropriate PHP extensions have been loaded, and if php.ini file settings are correct.
</p>
<p>
There are two kinds of requirements being checked. Mandatory requirements are those that have to be met
to allow Yii to work as expected. There are also some optional requirements beeing checked which will
show you a warning when they do not meet. You can use Yii framework without them but some specific
functionality may be not available in this case.
</p>
<h3>Conclusion</h3>
<?php if ($summary['errors']>0): ?>
<strong class="text-error">Unfortunately your server configuration does not satisfy the requirements by this application.</strong>
<?php elseif ($summary['warnings']>0): ?>
<strong class="text-warning">Your server configuration satisfies the minimum requirements by this application. Please pay attention to the warnings listed below if your application will use the corresponding features.</strong>
<?php if ($summary['errors'] > 0): ?>
<div class="alert alert-error">
<strong>Unfortunately your server configuration does not satisfy the requirements by this application.<br>Please refer to the table below for detailed explanation.</strong>
</div>
<?php elseif ($summary['warnings'] > 0): ?>
<div class="alert alert-info">
<strong>Your server configuration satisfies the minimum requirements by this application.<br>Please pay attention to the warnings listed below and check if your application will use the corresponding features.</strong>
</div>
<?php else: ?>
<strong class="text-success">Congratulations! Your server configuration satisfies all requirements.</strong>
<div class="alert alert-success">
<strong>Congratulations! Your server configuration satisfies all requirements.</strong>
</div>
<?php endif; ?>
<h3>Details</h3>
@ -62,7 +74,7 @@
<hr>
<div class="footer">
<p>Server: <?php echo $this->getServerInfo().' '.$this->getNowDate(); ?></p>
<p>Server: <?php echo $this->getServerInfo() . ' ' . $this->getNowDate(); ?></p>
<p>Powered by <a href="http://www.yiiframework.com/" rel="external">Yii Framework</a></p>
</div>
</div>

3
yii/web/Request.php

@ -533,7 +533,8 @@ class Request extends \yii\base\Request
*/
public function getIsSecureConnection()
{
return !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off');
return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off')
|| isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']==='https';
}
/**

11
yii/web/Response.php

@ -15,6 +15,7 @@ use yii\helpers\StringHelper;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Response extends \yii\base\Response
@ -50,7 +51,7 @@ class Response extends \yii\base\Response
if (isset($_SERVER['HTTP_RANGE'])) {
// client sent us a multibyte range, can not hold this one for now
if (strpos(',', $_SERVER['HTTP_RANGE']) !== false) {
if (strpos($_SERVER['HTTP_RANGE'],',') !== false) {
header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
throw new HttpException(416, 'Requested Range Not Satisfiable');
}
@ -63,14 +64,18 @@ class Response extends \yii\base\Response
} else {
$range = explode('-', $range);
$contentStart = $range[0];
$contentEnd = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $fileSize - 1;
// check if the last-byte-pos presents in header
if ((isset($range[1]) && is_numeric($range[1]))) {
$contentEnd = $range[1];
}
}
/* Check the range and make sure it's treated according to the specs.
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
*/
// End bytes can not be larger than $end.
$contentEnd = ($contentEnd > $fileSize) ? $fileSize : $contentEnd;
$contentEnd = ($contentEnd > $fileSize) ? $fileSize -1 : $contentEnd;
// Validate the requested range and return an error if it's not correct.
$wrongContentStart = ($contentStart > $contentEnd || $contentStart > $fileSize - 1 || $contentStart < 0);

Loading…
Cancel
Save