mirror of
https://github.com/yiisoft/yii.git
synced 2026-02-19 17:11:23 +01:00
Fixes #4191: Fixed multiple PHP 7.2 issues, added a way to exclude classes from autoloader
This commit is contained in:
committed by
Alexander Makarov
parent
1385c5ad39
commit
2ebe9b6513
@@ -9,6 +9,9 @@ Version 1.1.20 under development
|
||||
- Chg #4160: Updated HTMLPurifier to version 4.9.3 (takobell)
|
||||
- Bug #4162: Adjusted Zend Escaper to be compatible with PHP <5.3 and fixed usage of non-existing Exceptions (cebe)
|
||||
- Bug #4168: Fixed `CDbHttpSession` PHP 7.1 compatibility (csears123)
|
||||
- Enh #4191: Added option for filter classes loaded by YiiBase autoloader (daniel1302)
|
||||
- Bug #4191: Fixed "Headers already sent." error in CHttpSession (daniel1302)
|
||||
- Bug #4191: Fixed "CHtml::value() behaves differently for objects" for PHP 7.2 (daniel1302)
|
||||
|
||||
Version 1.1.19 June 8, 2017
|
||||
---------------------------
|
||||
|
||||
@@ -53,6 +53,13 @@ defined('YII_ZII_PATH') or define('YII_ZII_PATH',YII_PATH.DIRECTORY_SEPARATOR.'z
|
||||
*/
|
||||
class YiiBase
|
||||
{
|
||||
/**
|
||||
* @var array filters for autoloading mechanism.
|
||||
* It should be callable. For callable function autoloader pass className.
|
||||
* If filter function returns true Yii autoloader will be skipped.
|
||||
* @since 1.1.20
|
||||
*/
|
||||
public static $autoloaderFilters=array();
|
||||
/**
|
||||
* @var array class map used by the Yii autoloading mechanism.
|
||||
* The array keys are the class names and the array values are the corresponding class file paths.
|
||||
@@ -399,6 +406,30 @@ class YiiBase
|
||||
*/
|
||||
public static function autoload($className,$classMapOnly=false)
|
||||
{
|
||||
foreach (self::$autoloaderFilters as $filter)
|
||||
{
|
||||
if (is_array($filter)
|
||||
&& isset($filter[0]) && isset($filter[1])
|
||||
&& is_string($filter[0]) && is_string($filter[1])
|
||||
&& true === call_user_func(array($filter[0], $filter[1]), $className)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
elseif (is_string($filter)
|
||||
&& true === call_user_func($filter, $className)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
elseif (is_callable($filter)
|
||||
&& true === $filter($className)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// use include so that the error PHP file may appear
|
||||
if(isset(self::$classMap[$className]))
|
||||
include(self::$classMap[$className]);
|
||||
|
||||
@@ -76,6 +76,12 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public $autoStart=true;
|
||||
|
||||
/**
|
||||
* @var array Store frozen session data for ini_set in PHP7.2+
|
||||
* @since 1.1.20
|
||||
*/
|
||||
protected static $frozenData = array();
|
||||
|
||||
/**
|
||||
* Initializes the application component.
|
||||
* This method is required by IApplicationComponent and is invoked by application.
|
||||
@@ -270,18 +276,24 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
{
|
||||
if($value==='none')
|
||||
{
|
||||
$this->freeze();
|
||||
ini_set('session.use_cookies','0');
|
||||
ini_set('session.use_only_cookies','0');
|
||||
$this->unfreeze();
|
||||
}
|
||||
elseif($value==='allow')
|
||||
{
|
||||
$this->freeze();
|
||||
ini_set('session.use_cookies','1');
|
||||
ini_set('session.use_only_cookies','0');
|
||||
$this->unfreeze();
|
||||
}
|
||||
elseif($value==='only')
|
||||
{
|
||||
$this->freeze();
|
||||
ini_set('session.use_cookies','1');
|
||||
ini_set('session.use_only_cookies','1');
|
||||
$this->unfreeze();
|
||||
}
|
||||
else
|
||||
throw new CException(Yii::t('yii','CHttpSession.cookieMode can only be "none", "allow" or "only".'));
|
||||
@@ -303,9 +315,11 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
{
|
||||
if($value>=0 && $value<=100)
|
||||
{
|
||||
$this->freeze();
|
||||
// percent * 21474837 / 2147483647 ≈ percent * 0.01
|
||||
ini_set('session.gc_probability',floor($value*21474836.47));
|
||||
ini_set('session.gc_divisor',2147483647);
|
||||
$this->unfreeze();
|
||||
}
|
||||
else
|
||||
throw new CException(Yii::t('yii','CHttpSession.gcProbability "{value}" is invalid. It must be a float between 0 and 100.',
|
||||
@@ -573,4 +587,53 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
{
|
||||
unset($_SESSION[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* In PHP7.2 if session is started we cannot edit session ini settings.
|
||||
* This function save session data to temporary variable and stop session.
|
||||
*
|
||||
* @see CHttpSession::unfreeze();
|
||||
* @since 1.1.20
|
||||
*/
|
||||
protected function freeze()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '7.2.0', '<'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->getIsStarted())
|
||||
{
|
||||
self::$frozenData = $_SESSION;
|
||||
$this->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$frozenData = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start session and restore data from temporary variable
|
||||
*
|
||||
* @see CHttpSession::freeze();
|
||||
* @since 1.1.20
|
||||
*/
|
||||
protected function unfreeze()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '7.2.0', '<'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (self::$frozenData !== null)
|
||||
{
|
||||
@session_start();
|
||||
$_SESSION = self::$frozenData;
|
||||
}
|
||||
|
||||
self::$frozenData = array();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -996,13 +996,13 @@ class CHtml
|
||||
* The 'empty' option can also be an array of value-label pairs.
|
||||
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
|
||||
* <li>options: array, specifies additional attributes for each OPTION tag.
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
@@ -1064,13 +1064,13 @@ class CHtml
|
||||
* The 'empty' option can also be an array of value-label pairs.
|
||||
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
|
||||
* <li>options: array, specifies additional attributes for each OPTION tag.
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
@@ -1970,13 +1970,13 @@ EOD;
|
||||
* The 'empty' option can also be an array of value-label pairs.
|
||||
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
|
||||
* <li>options: array, specifies additional attributes for each OPTION tag.
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
@@ -2037,13 +2037,13 @@ EOD;
|
||||
* The 'empty' option can also be an array of value-label pairs.
|
||||
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
|
||||
* <li>options: array, specifies additional attributes for each OPTION tag.
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
@@ -2348,8 +2348,21 @@ EOD;
|
||||
if(is_scalar($attribute) || $attribute===null)
|
||||
foreach(explode('.',$attribute) as $name)
|
||||
{
|
||||
if(is_object($model) && isset($model->$name))
|
||||
$model=$model->$name;
|
||||
if(is_object($model))
|
||||
{
|
||||
if ((version_compare(PHP_VERSION, '7.2.0', '>=')
|
||||
&& is_numeric($name))
|
||||
|| !isset($model->$name)
|
||||
)
|
||||
{
|
||||
return $defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$model=$model->$name;
|
||||
}
|
||||
}
|
||||
|
||||
elseif(is_array($model) && isset($model[$name]))
|
||||
$model=$model[$name];
|
||||
else
|
||||
@@ -2485,13 +2498,13 @@ EOD;
|
||||
* The 'empty' option can also be an array of value-label pairs.
|
||||
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
|
||||
* <li>options: array, specifies additional attributes for each OPTION tag.
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* The array keys must be the option values, and the array values are the extra
|
||||
* OPTION tag attributes in the name-value pairs. For example,
|
||||
* <pre>
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* array(
|
||||
* 'value1'=>array('disabled'=>true,'label'=>'value 1'),
|
||||
* 'value2'=>array('label'=>'value 2'),
|
||||
* );
|
||||
* </pre>
|
||||
* </li>
|
||||
* <li>key: string, specifies the name of key attribute of the selection object(s).
|
||||
|
||||
62
tests/TestAutoloader.php
Normal file
62
tests/TestAutoloader.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
class TestAutoloader extends CTestCase
|
||||
{
|
||||
public function testAutoloaderForAnonymousCallableFilter()
|
||||
{
|
||||
Yii::$autoloaderFilters['smarty1'] = function($className)
|
||||
{
|
||||
if (strpos($className, 'Smarty') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$this->assertTrue(Yii::autoload('SmartyFunctionMeta'));
|
||||
$this->assertTrue(Yii::autoload('Smarty_Function_Meta'));
|
||||
}
|
||||
|
||||
public function testAutoloaderForFunction()
|
||||
{
|
||||
function exampleFilter($className)
|
||||
{
|
||||
if (strpos($className, 'Zend') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Yii::$autoloaderFilters['zend'] = 'exampleFilter';
|
||||
|
||||
$this->assertTrue(Yii::autoload('ZendFunctionMeta'));
|
||||
$this->assertTrue(Yii::autoload('Zend_Function_Meta'));
|
||||
}
|
||||
|
||||
public function testAutoloaderForStaticMethod()
|
||||
{
|
||||
eval('Class SmartyAutoloader {
|
||||
public static function exampleFilter($className)
|
||||
{
|
||||
if (strpos($className, \'Smarty\') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}');
|
||||
|
||||
|
||||
Yii::$autoloaderFilters['smarty2'] = array('SmartyAutoloader', 'exampleFilter');
|
||||
|
||||
$this->assertTrue(Yii::autoload('SmartyFunctionMeta'));
|
||||
$this->assertTrue(Yii::autoload('Smarty_Function_Meta'));
|
||||
}
|
||||
|
||||
public function testAutoloaderWithoutFilter()
|
||||
{
|
||||
Yii::$enableIncludePath = false;
|
||||
$this->assertFalse(Yii::autoload('SomeClass'));
|
||||
$this->assertTrue(Yii::autoload('Yii'));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ class CHttpSessionTest extends CTestCase {
|
||||
/**
|
||||
* @covers CHttpSession::getGCProbability
|
||||
* @covers CHttpSession::setGCProbability
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testSetGet() {
|
||||
Yii::app()->setComponents(array('session' => array(
|
||||
@@ -24,9 +26,10 @@ class CHttpSessionTest extends CTestCase {
|
||||
'timeout' => 5,
|
||||
)));
|
||||
/** @var $sm CHttpSession */
|
||||
|
||||
$this->checkProb(1);
|
||||
|
||||
$this->checkProb(0);
|
||||
|
||||
$gcProb = 1.0;
|
||||
while ($gcProb > 1 / 2147483647) {
|
||||
$this->checkProb($gcProb);
|
||||
|
||||
Reference in New Issue
Block a user