mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-01 03:26:36 +08:00 
			
		
		
		
	Merge branch 'master' into 13920-validation-marks-valid-field-as-invalid
This commit is contained in:
		| @ -373,7 +373,7 @@ $query->orderBy([ | ||||
| ``` | ||||
|  | ||||
| В данном коде, ключи массива - это имена столбцов, а значения массива - это соответствующее направление сортировки. | ||||
| PHP константа `SORT_ASC` определяет сортировку по возрастанию и `SORT_DESC` сортировка по умолчанию. | ||||
| PHP константа `SORT_ASC` определяет сортировку по возрастанию и `SORT_DESC` сортировку по убыванию. | ||||
|  | ||||
| Если `ORDER BY` содержит только простые имена столбцов, вы можете определить их с помощью столбцов, также | ||||
| как и при написании обычного SQL. Например, | ||||
|  | ||||
| @ -68,7 +68,7 @@ class BaseYii | ||||
|      */ | ||||
|     public static $classMap = []; | ||||
|     /** | ||||
|      * @var \yii\console\Application|\yii\web\Application|\yii\base\Application the application instance | ||||
|      * @var \yii\console\Application|\yii\web\Application the application instance | ||||
|      */ | ||||
|     public static $app; | ||||
|     /** | ||||
|  | ||||
| @ -5,6 +5,7 @@ Yii Framework 2 Change Log | ||||
| ------------------------ | ||||
|  | ||||
| - Bug #13920: Fixed erroneous validation for specific cases (tim-fischer-maschinensucher) | ||||
| - Bug #19872: Fixed the definition of dirty attributes in AR properties for a non-associative array in case of changing the order of elements (eegusakov) | ||||
| - Bug #19899: Fixed `GridView` in some cases calling `Model::generateAttributeLabel()` to generate label values that are never used (PowerGamer1) | ||||
| - Bug #9899: Fix caching a MSSQL query with BLOB data type (terabytesoftw) | ||||
| - Bug #16208: Fix `yii\log\FileTarget` to not export empty messages (terabytesoftw) | ||||
| @ -16,6 +17,8 @@ Yii Framework 2 Change Log | ||||
| - Enh #19884: Added support Enums in Query Builder (sk1t0n) | ||||
| - Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh) | ||||
| - Bug #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh) | ||||
| - Bug #19914: Fixed `ArrayHelper::keyExists()` and  `::remove()` functions when the key is a float and the value is `null` (rhertogh) | ||||
| - Enh #19920: Broadened the accepted type of `Cookie::$expire` from `int` to `int|string|\DateTimeInterface|null` (rhertogh) | ||||
|  | ||||
|  | ||||
| 2.0.48.1 May 24, 2023 | ||||
|  | ||||
| @ -282,7 +282,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|      */ | ||||
|     public function __get($name) | ||||
|     { | ||||
|         if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) { | ||||
|         if (array_key_exists($name, $this->_attributes)) { | ||||
|             return $this->_attributes[$name]; | ||||
|         } | ||||
|  | ||||
| @ -290,7 +290,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) { | ||||
|         if (array_key_exists($name, $this->_related)) { | ||||
|             return $this->_related[$name]; | ||||
|         } | ||||
|         $value = parent::__get($name); | ||||
| @ -1774,7 +1774,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|      */ | ||||
|     private function isValueDifferent($newValue, $oldValue) | ||||
|     { | ||||
|         if (is_array($newValue) && is_array($oldValue) && !ArrayHelper::isAssociative($oldValue)) { | ||||
|         if (is_array($newValue) && is_array($oldValue) && ArrayHelper::isAssociative($oldValue)) { | ||||
|             $newValue = ArrayHelper::recursiveSort($newValue); | ||||
|             $oldValue = ArrayHelper::recursiveSort($oldValue); | ||||
|         } | ||||
|  | ||||
| @ -327,7 +327,12 @@ class BaseArrayHelper | ||||
|      */ | ||||
|     public static function remove(&$array, $key, $default = null) | ||||
|     { | ||||
|         if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { | ||||
|         // ToDo: This check can be removed when the minimum PHP version is >= 8.1 (Yii2.2) | ||||
|         if (is_float($key)) { | ||||
|             $key = (int)$key; | ||||
|         } | ||||
|  | ||||
|         if (is_array($array) && array_key_exists($key, $array)) { | ||||
|             $value = $array[$key]; | ||||
|             unset($array[$key]); | ||||
|  | ||||
| @ -608,17 +613,20 @@ class BaseArrayHelper | ||||
|      * Checks if the given array contains the specified key. | ||||
|      * This method enhances the `array_key_exists()` function by supporting case-insensitive | ||||
|      * key comparison. | ||||
|      * @param string $key the key to check | ||||
|      * @param string|int $key the key to check | ||||
|      * @param array|ArrayAccess $array the array with keys to check | ||||
|      * @param bool $caseSensitive whether the key comparison should be case-sensitive | ||||
|      * @return bool whether the array contains the specified key | ||||
|      */ | ||||
|     public static function keyExists($key, $array, $caseSensitive = true) | ||||
|     { | ||||
|         // ToDo: This check can be removed when the minimum PHP version is >= 8.1 (Yii2.2) | ||||
|         if (is_float($key)) { | ||||
|             $key = (int)$key; | ||||
|         } | ||||
|  | ||||
|         if ($caseSensitive) { | ||||
|             // Function `isset` checks key faster but skips `null`, `array_key_exists` handles this case | ||||
|             // https://www.php.net/manual/en/function.array-key-exists.php#107786 | ||||
|             if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { | ||||
|             if (is_array($array) && array_key_exists($key, $array)) { | ||||
|                 return true; | ||||
|             } | ||||
|             // Cannot use `array_has_key` on Objects for PHP 7.4+, therefore we need to check using [[ArrayAccess::offsetExists()]] | ||||
|  | ||||
| @ -57,8 +57,8 @@ class Cookie extends \yii\base\BaseObject | ||||
|      */ | ||||
|     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". | ||||
|      * @var int|string|\DateTimeInterface|null the timestamp or date at which the cookie expires. This is the server timestamp. | ||||
|      * Defaults to 0, meaning "until the browser is closed" (the same applies to `null`). | ||||
|      */ | ||||
|     public $expire = 0; | ||||
|     /** | ||||
|  | ||||
| @ -51,7 +51,7 @@ class CookieCollection extends BaseObject implements \IteratorAggregate, \ArrayA | ||||
|      * 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. | ||||
|      * @return ArrayIterator<string, Cookie> an iterator for traversing the cookies in the collection. | ||||
|      */ | ||||
|     #[\ReturnTypeWillChange] | ||||
|     public function getIterator() | ||||
| @ -113,7 +113,18 @@ class CookieCollection extends BaseObject implements \IteratorAggregate, \ArrayA | ||||
|     public function has($name) | ||||
|     { | ||||
|         return isset($this->_cookies[$name]) && $this->_cookies[$name]->value !== '' | ||||
|             && ($this->_cookies[$name]->expire === null || $this->_cookies[$name]->expire === 0 || $this->_cookies[$name]->expire >= time()); | ||||
|             && ($this->_cookies[$name]->expire === null | ||||
|                 || $this->_cookies[$name]->expire === 0 | ||||
|                 || ( | ||||
|                     (is_string($this->_cookies[$name]->expire) && strtotime($this->_cookies[$name]->expire) >= time()) | ||||
|                     || ( | ||||
|                         interface_exists('\\DateTimeInterface') | ||||
|                         && $this->_cookies[$name]->expire instanceof \DateTimeInterface | ||||
|                         && $this->_cookies[$name]->expire->getTimestamp() >= time() | ||||
|                     ) | ||||
|                     || $this->_cookies[$name]->expire >= time() | ||||
|                 ) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @ -174,7 +185,7 @@ class CookieCollection extends BaseObject implements \IteratorAggregate, \ArrayA | ||||
|  | ||||
|     /** | ||||
|      * Returns the collection as a PHP array. | ||||
|      * @return array the array representation of the collection. | ||||
|      * @return Cookie[] the array representation of the collection. | ||||
|      * The array keys are cookie names, and the array values are the corresponding cookie objects. | ||||
|      */ | ||||
|     public function toArray() | ||||
|  | ||||
| @ -401,12 +401,21 @@ class Response extends \yii\base\Response | ||||
|         } | ||||
|         foreach ($this->getCookies() as $cookie) { | ||||
|             $value = $cookie->value; | ||||
|             if ($cookie->expire != 1 && isset($validationKey)) { | ||||
|             $expire = $cookie->expire; | ||||
|             if (is_string($expire)) { | ||||
|                 $expire = strtotime($expire); | ||||
|             } elseif (interface_exists('\\DateTimeInterface') && $expire instanceof \DateTimeInterface) { | ||||
|                 $expire = $expire->getTimestamp(); | ||||
|             } | ||||
|             if ($expire === null || $expire === false) { | ||||
|                 $expire = 0; | ||||
|             } | ||||
|             if ($expire != 1 && isset($validationKey)) { | ||||
|                 $value = Yii::$app->getSecurity()->hashData(serialize([$cookie->name, $value]), $validationKey); | ||||
|             } | ||||
|             if (PHP_VERSION_ID >= 70300) { | ||||
|                 setcookie($cookie->name, $value, [ | ||||
|                     'expires' => $cookie->expire, | ||||
|                     'expires' => $expire, | ||||
|                     'path' => $cookie->path, | ||||
|                     'domain' => $cookie->domain, | ||||
|                     'secure' => $cookie->secure, | ||||
| @ -420,7 +429,7 @@ class Response extends \yii\base\Response | ||||
|                 if (!is_null($cookie->sameSite)) { | ||||
|                     $cookiePath .= '; samesite=' . $cookie->sameSite; | ||||
|                 } | ||||
|                 setcookie($cookie->name, $value, $cookie->expire, $cookiePath, $cookie->domain, $cookie->secure, $cookie->httpOnly); | ||||
|                 setcookie($cookie->name, $value, $expire, $cookiePath, $cookie->domain, $cookie->secure, $cookie->httpOnly); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
							
								
								
									
										42
									
								
								tests/framework/db/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								tests/framework/db/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| namespace yiiunit\framework\db; | ||||
|  | ||||
| use yiiunit\data\ar\ActiveRecord; | ||||
|  | ||||
| abstract class BaseActiveRecordTest extends DatabaseTestCase | ||||
| { | ||||
|     protected function setUp() | ||||
|     { | ||||
|         parent::setUp(); | ||||
|         ActiveRecord::$db = $this->getConnection(); | ||||
|     } | ||||
|  | ||||
|     public function provideArrayValueWithChange() | ||||
|     { | ||||
|         return [ | ||||
|             'not an associative array with data change' => [ | ||||
|                 [1, 2, 3], | ||||
|                 [1, 3, 2], | ||||
|             ], | ||||
|  | ||||
|             'associative array with data change case 1' => [ | ||||
|                 ['pineapple' => 2, 'apple' => 5, 'banana' => 1], | ||||
|                 ['apple' => 5, 'pineapple' => 1, 'banana' => 3], | ||||
|             ], | ||||
|             'associative array with data change case 2' => [ | ||||
|                 ['pineapple' => 2, 'apple' => 5, 'banana' => 1], | ||||
|                 ['pineapple' => 2, 'apple' => 3, 'banana' => 1], | ||||
|             ], | ||||
|  | ||||
|             'filling an empty array' => [ | ||||
|                 [], | ||||
|                 ['pineapple' => 3, 'apple' => 1, 'banana' => 1], | ||||
|             ], | ||||
|             'zeroing the array' => [ | ||||
|                 ['pineapple' => 3, 'apple' => 1, 'banana' => 17], | ||||
|                 [], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										37
									
								
								tests/framework/db/mysql/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/framework/db/mysql/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| <?php | ||||
|  | ||||
| namespace yiiunit\framework\db\mysql; | ||||
|  | ||||
| use yiiunit\data\ar\Storage; | ||||
|  | ||||
| class BaseActiveRecordTest extends \yiiunit\framework\db\BaseActiveRecordTest | ||||
| { | ||||
|     public $driverName = 'mysql'; | ||||
|  | ||||
|     /** | ||||
|      * @see https://github.com/yiisoft/yii2/issues/19872 | ||||
|      * | ||||
|      * @dataProvider provideArrayValueWithChange | ||||
|      */ | ||||
|     public function testJsonDirtyAttributesWithDataChange($actual, $modified) | ||||
|     { | ||||
|         if (version_compare($this->getConnection()->getSchema()->getServerVersion(), '5.7', '<')) { | ||||
|             $this->markTestSkipped('JSON columns are not supported in MySQL < 5.7'); | ||||
|         } | ||||
|         if (version_compare(PHP_VERSION, '5.6', '<')) { | ||||
|             $this->markTestSkipped('JSON columns are not supported in PDO for PHP < 5.6'); | ||||
|         } | ||||
|  | ||||
|         $createdStorage = new Storage(['data' => $actual]); | ||||
|  | ||||
|         $createdStorage->save(); | ||||
|  | ||||
|         $foundStorage = Storage::find()->limit(1)->one(); | ||||
|  | ||||
|         $this->assertNotNull($foundStorage); | ||||
|  | ||||
|         $foundStorage->data = $modified; | ||||
|  | ||||
|         $this->assertSame(['data' => $modified], $foundStorage->getDirtyAttributes()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										46
									
								
								tests/framework/db/pgsql/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								tests/framework/db/pgsql/BaseActiveRecordTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| <?php | ||||
|  | ||||
| namespace yiiunit\framework\db\pgsql; | ||||
|  | ||||
| use yii\db\JsonExpression; | ||||
| use yiiunit\data\ar\ActiveRecord; | ||||
|  | ||||
| class BaseActiveRecordTest extends \yiiunit\framework\db\BaseActiveRecordTest | ||||
| { | ||||
|     public $driverName = 'pgsql'; | ||||
|  | ||||
|     /** | ||||
|      * @see https://github.com/yiisoft/yii2/issues/19872 | ||||
|      * | ||||
|      * @dataProvider provideArrayValueWithChange | ||||
|      */ | ||||
|     public function testJsonDirtyAttributesWithDataChange($actual, $modified) | ||||
|     { | ||||
|         $createdStorage = new ArrayAndJsonType([ | ||||
|             'json_col' => new JsonExpression($actual), | ||||
|         ]); | ||||
|  | ||||
|         $createdStorage->save(); | ||||
|  | ||||
|         $foundStorage = ArrayAndJsonType::find()->limit(1)->one(); | ||||
|  | ||||
|         $this->assertNotNull($foundStorage); | ||||
|  | ||||
|         $foundStorage->json_col = $modified; | ||||
|  | ||||
|         $this->assertSame(['json_col' => $modified], $foundStorage->getDirtyAttributes()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * {@inheritdoc} | ||||
|  * @property array id | ||||
|  * @property array json_col | ||||
|  */ | ||||
| class ArrayAndJsonType extends ActiveRecord | ||||
| { | ||||
|     public static function tableName() | ||||
|     { | ||||
|         return '{{%array_and_json_types}}'; | ||||
|     } | ||||
| } | ||||
| @ -135,6 +135,29 @@ class ArrayHelperTest extends TestCase | ||||
|         $this->assertEquals('defaultValue', $default); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return void | ||||
|      */ | ||||
|     public function testRemoveWithFloat() | ||||
|     { | ||||
|         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||
|             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||
|         } | ||||
|  | ||||
|         $array = ['name' => 'b', 'age' => 3, 1.1 => null]; | ||||
|  | ||||
|         $name = ArrayHelper::remove($array, 'name'); | ||||
|         $this->assertEquals($name, 'b'); | ||||
|         $this->assertEquals($array, ['age' => 3, 1.1 => null]); | ||||
|  | ||||
|         $floatVal = ArrayHelper::remove($array, 1.1); | ||||
|         $this->assertNull($floatVal); | ||||
|         $this->assertEquals($array, ['age' => 3]); | ||||
|  | ||||
|         $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue'); | ||||
|         $this->assertEquals('defaultValue', $default); | ||||
|     } | ||||
|  | ||||
|     public function testRemoveValueMultiple() | ||||
|     { | ||||
|         $array = [ | ||||
| @ -506,14 +529,21 @@ class ArrayHelperTest extends TestCase | ||||
|     /** | ||||
|      * @see https://github.com/yiisoft/yii2/pull/11549 | ||||
|      */ | ||||
|     public function test() | ||||
|     public function testGetValueWithFloatKeys() | ||||
|     { | ||||
|         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||
|             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||
|         } | ||||
|  | ||||
|         $array = []; | ||||
|         $array[1.0] = 'some value'; | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 1.0); | ||||
|         $array[1.1] = 'some value'; | ||||
|         $array[2.1] = null; | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 1.2); | ||||
|         $this->assertEquals('some value', $result); | ||||
|  | ||||
|         $result = ArrayHelper::getValue($array, 2.2); | ||||
|         $this->assertNull($result); | ||||
|     } | ||||
|  | ||||
|     public function testIndex() | ||||
| @ -712,6 +742,7 @@ class ArrayHelperTest extends TestCase | ||||
|             'a' => 1, | ||||
|             'B' => 2, | ||||
|         ]; | ||||
|  | ||||
|         $this->assertTrue(ArrayHelper::keyExists('a', $array)); | ||||
|         $this->assertFalse(ArrayHelper::keyExists('b', $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists('B', $array)); | ||||
| @ -723,6 +754,27 @@ class ArrayHelperTest extends TestCase | ||||
|         $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); | ||||
|     } | ||||
|  | ||||
|     public function testKeyExistsWithFloat() | ||||
|     { | ||||
|         if (version_compare(PHP_VERSION, '8.1.0', '>=')) { | ||||
|             $this->markTestSkipped('Using floats as array key is deprecated.'); | ||||
|         } | ||||
|  | ||||
|         $array = [ | ||||
|             1 => 3, | ||||
|             2.2 => 4, // Note: Floats are cast to ints, which means that the fractional part will be truncated. | ||||
|             3.3 => null, | ||||
|         ]; | ||||
|  | ||||
|         $this->assertTrue(ArrayHelper::keyExists(1, $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists(1.1, $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists(2, $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists('2', $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists(2.2, $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists(3, $array)); | ||||
|         $this->assertTrue(ArrayHelper::keyExists(3.3, $array)); | ||||
|     } | ||||
|  | ||||
|     public function testKeyExistsArrayAccess() | ||||
|     { | ||||
|         $array = new TraversableArrayAccessibleObject([ | ||||
|  | ||||
| @ -380,21 +380,116 @@ class ResponseTest extends \yiiunit\TestCase | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function testSameSiteCookie() | ||||
|     /** | ||||
|      * @dataProvider cookiesTestProvider | ||||
|      */ | ||||
|     public function testCookies($cookieConfig, $expected) | ||||
|     { | ||||
|         $response = new Response(); | ||||
|         $response->cookies->add(new Cookie([ | ||||
|             'name'     => 'test', | ||||
|             'value'    => 'testValue', | ||||
|             'sameSite' => Cookie::SAME_SITE_STRICT, | ||||
|         ])); | ||||
|         $response->cookies->add(new Cookie(array_merge( | ||||
|             [ | ||||
|                 'name'     => 'test', | ||||
|                 'value'    => 'testValue', | ||||
|             ], | ||||
|             $cookieConfig | ||||
|         ))); | ||||
|  | ||||
|         ob_start(); | ||||
|         $response->send(); | ||||
|         $content = ob_get_clean(); | ||||
|  | ||||
|         // Only way to test is that it doesn't create any errors | ||||
|         $this->assertEquals('', $content); | ||||
|         $cookies = $this->parseHeaderCookies(); | ||||
|         if ($cookies === false) { | ||||
|             // Unable to resolve cookies, only way to test is that it doesn't create any errors | ||||
|             $this->assertEquals('', $content); | ||||
|         } else { | ||||
|             $testCookie = $cookies['test']; | ||||
|             $actual = array_intersect_key($testCookie, $expected); | ||||
|             ksort($actual); | ||||
|             ksort($expected); | ||||
|             $this->assertEquals($expected, $actual); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function cookiesTestProvider() | ||||
|     { | ||||
|         $expireInt = time() + 3600; | ||||
|         $expireString = date('D, d-M-Y H:i:s', $expireInt) . ' GMT'; | ||||
|  | ||||
|         $testCases = [ | ||||
|             'same-site' => [ | ||||
|                 ['sameSite' => Cookie::SAME_SITE_STRICT], | ||||
|                 ['samesite' => Cookie::SAME_SITE_STRICT], | ||||
|             ], | ||||
|             'expire-as-int' => [ | ||||
|                 ['expire' => $expireInt], | ||||
|                 ['expires' => $expireString], | ||||
|             ], | ||||
|             'expire-as-string' => [ | ||||
|                 ['expire' => $expireString], | ||||
|                 ['expires' => $expireString], | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|         if (version_compare(PHP_VERSION, '5.5.0', '>=')) { | ||||
|             $testCases = array_merge($testCases, [ | ||||
|                 'expire-as-date_time' => [ | ||||
|                     ['expire' => new \DateTime('@' . $expireInt)], | ||||
|                     ['expires' => $expireString], | ||||
|                 ], | ||||
|                 'expire-as-date_time_immutable' => [ | ||||
|                     ['expire' => new \DateTimeImmutable('@' . $expireInt)], | ||||
|                     ['expires' => $expireString], | ||||
|                 ], | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         return $testCases; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Tries to parse cookies set in the response headers. | ||||
|      * When running PHP on the CLI headers are not available (the `headers_list()` function always returns an | ||||
|      * empty array). If possible use xDebug: http://xdebug.org/docs/all_functions#xdebug_get_headers | ||||
|      * @param $name | ||||
|      * @return array|false | ||||
|      */ | ||||
|     protected function parseHeaderCookies() { | ||||
|  | ||||
|         if (!function_exists('xdebug_get_headers')) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $cookies = []; | ||||
|         foreach(xdebug_get_headers() as $header) { | ||||
|             if (strpos($header, 'Set-Cookie: ') !== 0) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $name = null; | ||||
|             $params = []; | ||||
|             $pairs = explode(';', substr($header, 12)); | ||||
|             foreach ($pairs as  $index => $pair) { | ||||
|                 $pair = trim($pair); | ||||
|                 if (strpos($pair, '=') === false) { | ||||
|                     $params[strtolower($pair)] = true; | ||||
|                 } else { | ||||
|                     list($paramName, $paramValue) = explode('=', $pair, 2); | ||||
|                     if ($index === 0) { | ||||
|                         $name = $paramName; | ||||
|                         $params['value'] = urldecode($paramValue); | ||||
|                     } else { | ||||
|                         $params[strtolower($paramName)] = urldecode($paramValue); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if ($name === null) { | ||||
|                 throw new \Exception('Could not determine cookie name for header "' . $header . '".'); | ||||
|             } | ||||
|             $cookies[$name] = $params; | ||||
|         } | ||||
|  | ||||
|         return $cookies; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Alexander Makarov
					Alexander Makarov