diff --git a/apps/bootstrap/assets/.gitignore b/apps/bootstrap/assets/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/apps/bootstrap/assets/.gitignore @@ -0,0 +1 @@ +* diff --git a/apps/bootstrap/composer.json b/apps/bootstrap/composer.json index 86e399b..b2300b2 100644 --- a/apps/bootstrap/composer.json +++ b/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", diff --git a/apps/bootstrap/www/index.php b/apps/bootstrap/www/index.php index 7938c85..0875881 100644 --- a/apps/bootstrap/www/index.php +++ b/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'); diff --git a/apps/bootstrap/yii b/apps/bootstrap/yii index fa8db10..e35ae3a 100755 --- a/apps/bootstrap/yii +++ b/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'); diff --git a/tests/unit/framework/rbac/ManagerTestBase.php b/tests/unit/framework/rbac/ManagerTestBase.php index 1ab7d52..1476f9d 100644 --- a/tests/unit/framework/rbac/ManagerTestBase.php +++ b/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'); } diff --git a/tests/unit/framework/web/ResponseTest.php b/tests/unit/framework/web/ResponseTest.php index b3d9080..2fde63d 100644 --- a/tests/unit/framework/web/ResponseTest.php +++ b/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; } -} \ No newline at end of file +} diff --git a/yii/base/View.php b/yii/base/View.php index cf92741..8bede3d 100644 --- a/yii/base/View.php +++ b/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"; diff --git a/yii/bootstrap/Modal.php b/yii/bootstrap/Modal.php index 5e287c5..1a70209 100644 --- a/yii/bootstrap/Modal.php +++ b/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' => '

Hello world

', + * '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' => '

One fine body...

', - * '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' => '

Hello world

', + * 'toggleButton' => array( + * 'label' => 'click me', + * ), * )); - * ``` + * + * echo 'Say hello...'; + * + * Modal::end(); + * ~~~ + * * @see http://twitter.github.io/bootstrap/javascript.html#modals * @author Antonio Ramirez + * @author Qiang Xue * @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: - * - * - * 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 = '×'; - + 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 '×'. + * + * 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', '×'); + 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']; + } + } } - -} \ No newline at end of file +} diff --git a/yii/bootstrap/Widget.php b/yii/bootstrap/Widget.php index c50349f..405cd19 100644 --- a/yii/bootstrap/Widget.php +++ b/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 + * @author Qiang Xue * @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; + } } -} \ No newline at end of file +} diff --git a/yii/composer.json b/yii/composer.json index eb4c734..c8c0dd3 100644 --- a/yii/composer.json +++ b/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." } } diff --git a/yii/requirements/YiiRequirementChecker.php b/yii/requirements/YiiRequirementChecker.php index 03413d1..160a5db 100644 --- a/yii/requirements/YiiRequirementChecker.php +++ b/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 * ) * */ - 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; diff --git a/yii/requirements/requirements.php b/yii/requirements/requirements.php index a703fde..846eafc 100644 --- a/yii/requirements/requirements.php +++ b/yii/requirements/requirements.php @@ -1,7 +1,9 @@ 'Multibyte string processing', 'memo' => 'Required for multibyte encoding string processing.' ), + array( + 'name' => 'Intl extension', + 'mandatory' => false, + 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2'), + 'by' => 'Internationalization support', + 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use IDN-feature of EmailValidator or UrlValidator.' + ), ); \ No newline at end of file diff --git a/yii/requirements/views/web/index.php b/yii/requirements/views/web/index.php index 2f8da15..6cd2594 100644 --- a/yii/requirements/views/web/index.php +++ b/yii/requirements/views/web/index.php @@ -8,7 +8,7 @@ Yii Application Requirement Checker - renderViewFile(dirname(__FILE__).DIRECTORY_SEPARATOR.'css.php'); ?> + renderViewFile(dirname(__FILE__) . '/css.php'); ?>
@@ -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.

+

+ 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. +

Conclusion

- 0): ?> - Unfortunately your server configuration does not satisfy the requirements by this application. - 0): ?> - 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. + 0): ?> +
+ Unfortunately your server configuration does not satisfy the requirements by this application.
Please refer to the table below for detailed explanation.
+
+ 0): ?> +
+ Your server configuration satisfies the minimum requirements by this application.
Please pay attention to the warnings listed below and check if your application will use the corresponding features.
+
- Congratulations! Your server configuration satisfies all requirements. +
+ Congratulations! Your server configuration satisfies all requirements. +

Details

@@ -62,7 +74,7 @@
diff --git a/yii/web/Request.php b/yii/web/Request.php index 2f4568a..5cd6912 100644 --- a/yii/web/Request.php +++ b/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'; } /** diff --git a/yii/web/Response.php b/yii/web/Response.php index 954c999..d37c66a 100644 --- a/yii/web/Response.php +++ b/yii/web/Response.php @@ -15,6 +15,7 @@ use yii\helpers\StringHelper; /** * @author Qiang Xue + * @author Carsten Brandt * @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);