From d91059460b99da0e9ee50ce516c197d13f1464b0 Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Sat, 5 Aug 2017 22:15:10 +0200 Subject: [PATCH 01/44] Improved performance of CakeFixtureManager. --- lib/Cake/TestSuite/Fixture/CakeFixtureManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php b/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php index 57d1df3c6d7..31808c64706 100644 --- a/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php +++ b/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php @@ -175,7 +175,7 @@ protected function _loadFixtures($fixtures) { } /** - * Runs the drop and create commands on the fixtures if necessary. + * Runs the drop, create and truncate commands on the fixtures if necessary. * * @param CakeTestFixture $fixture the fixture object to create * @param DataSource $db the datasource instance to use @@ -191,6 +191,7 @@ protected function _setupTable($fixture, $db = null, $drop = true) { } } if (!empty($fixture->created) && in_array($db->configKeyName, $fixture->created)) { + $fixture->truncate($db); return; } @@ -205,6 +206,7 @@ protected function _setupTable($fixture, $db = null, $drop = true) { $fixture->create($db); } else { $fixture->created[] = $db->configKeyName; + $fixture->truncate($db); } } @@ -229,7 +231,6 @@ public function load(CakeTestCase $test) { $db = ConnectionManager::getDataSource($fixture->useDbConfig); $db->begin(); $this->_setupTable($fixture, $db, $test->dropTables); - $fixture->truncate($db); $fixture->insert($db); $db->commit(); } @@ -274,7 +275,6 @@ public function loadSingle($name, $db = null, $dropTables = true) { $db = ConnectionManager::getDataSource($fixture->useDbConfig); } $this->_setupTable($fixture, $db, $dropTables); - $fixture->truncate($db); $fixture->insert($db); } else { throw new UnexpectedValueException(__d('cake_dev', 'Referenced fixture class %s not found', $name)); From 95e0a2143934abed3baf33885032eefcf9081605 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 7 Aug 2017 21:21:35 -0400 Subject: [PATCH 02/44] Update version number to 2.10.1 --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index e3ff573ec9b..69c5fdc0337 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.10.0 +2.10.1 From 90f14bc07bf8386f0e76a3a9dc923ca425654b09 Mon Sep 17 00:00:00 2001 From: Luis Cano Date: Tue, 8 Aug 2017 12:28:57 -0400 Subject: [PATCH 03/44] fixes cakephp/cakephp#11016 --- lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index c868580f70a..75def3eb4d0 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -265,7 +265,19 @@ public function paintFail($message, $test) { echo "
" . $this->_htmlEntities($message->toString());
 
 		if ((is_string($actualMsg) && is_string($expectedMsg)) || (is_array($actualMsg) && is_array($expectedMsg))) {
-			echo "
" . $this->_htmlEntities(PHPUnit_Util_Diff::diff($expectedMsg, $actualMsg)); + + $diffs = ""; + + // PHPUnit 3.7.38 support + if(class_exists('PHPUnit_Util_Diff')) { + $diffs = PHPUnit_Util_Diff::diff($expectedMsg, $actualMsg); + + // PHPUnit 4.x and 5.x support + }else if(class_exists('SebastianBergmann\Diff\Differ')){ + $diffs = (new SebastianBergmann\Diff\Differ())->diff($expectedMsg, $actualMsg); + } + + echo "
" . $this->_htmlEntities($diffs); } echo "
\n"; From 9f175f22f4ce7bdf97a4594990640d8e2b792213 Mon Sep 17 00:00:00 2001 From: Luis Cano Date: Tue, 8 Aug 2017 12:59:33 -0400 Subject: [PATCH 04/44] Abiding to code standards --- lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index 75def3eb4d0..2c04d5215e8 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -267,13 +267,9 @@ public function paintFail($message, $test) { if ((is_string($actualMsg) && is_string($expectedMsg)) || (is_array($actualMsg) && is_array($expectedMsg))) { $diffs = ""; - - // PHPUnit 3.7.38 support - if(class_exists('PHPUnit_Util_Diff')) { + if (class_exists('PHPUnit_Util_Diff')) { $diffs = PHPUnit_Util_Diff::diff($expectedMsg, $actualMsg); - - // PHPUnit 4.x and 5.x support - }else if(class_exists('SebastianBergmann\Diff\Differ')){ + } elseif (class_exists('SebastianBergmann\Diff\Differ')) { $diffs = (new SebastianBergmann\Diff\Differ())->diff($expectedMsg, $actualMsg); } From 3307665cbb7a6b4d6d9f558e4c71cd54847b2bed Mon Sep 17 00:00:00 2001 From: Luis Cano Date: Tue, 8 Aug 2017 14:28:11 -0400 Subject: [PATCH 05/44] Fixed syntax to work with PHP5.3 --- lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index 2c04d5215e8..9106d17bd55 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -270,7 +270,8 @@ public function paintFail($message, $test) { if (class_exists('PHPUnit_Util_Diff')) { $diffs = PHPUnit_Util_Diff::diff($expectedMsg, $actualMsg); } elseif (class_exists('SebastianBergmann\Diff\Differ')) { - $diffs = (new SebastianBergmann\Diff\Differ())->diff($expectedMsg, $actualMsg); + $differ = new SebastianBergmann\Diff\Differ(); + $diffs = $differ->diff($expectedMsg, $actualMsg); } echo "
" . $this->_htmlEntities($diffs); From 1e5ea2451a27c1571452f15e0276253e76730acc Mon Sep 17 00:00:00 2001 From: Luis Cano Date: Tue, 8 Aug 2017 14:42:57 -0400 Subject: [PATCH 06/44] Fixes "Whitespace found at end of line" --- lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index 9106d17bd55..8c07e9b458d 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -265,7 +265,7 @@ public function paintFail($message, $test) { echo "
" . $this->_htmlEntities($message->toString());
 
 		if ((is_string($actualMsg) && is_string($expectedMsg)) || (is_array($actualMsg) && is_array($expectedMsg))) {
-			
+
 			$diffs = "";
 			if (class_exists('PHPUnit_Util_Diff')) {
 				$diffs = PHPUnit_Util_Diff::diff($expectedMsg, $actualMsg);
@@ -273,7 +273,7 @@ public function paintFail($message, $test) {
 				$differ = new SebastianBergmann\Diff\Differ();
 				$diffs = $differ->diff($expectedMsg, $actualMsg);
 			}
-			
+
 			echo "
" . $this->_htmlEntities($diffs); } From be534eacef221f221a290f1fff4c3a186fdb240b Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 8 Aug 2017 22:02:07 -0400 Subject: [PATCH 07/44] Fix hiddenField option not working for radio. The hiddenField option was not working as documented for radio buttons. Instead of using the provided value, the hidden input's value was hardcoded to '' Refs #11002 --- .../Test/Case/View/Helper/FormHelperTest.php | 24 +++++++++++++++++++ lib/Cake/View/Helper/FormHelper.php | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 78c5c452673..40a1477828b 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -4944,6 +4944,30 @@ public function testRadioHiddenInputDisabling() { $this->assertTags($result, $expected); } +/** + * test setting a hiddenField value + * + * @return void + */ + public function testRadioHiddenFieldValue() { + $result = $this->Form->input('Model.1.field', array( + 'type' => 'radio', + 'options' => array('option A'), + 'hiddenField' => 'N' + ) + ); + $expected = array( + 'div' => array('class' => 'input radio'), + array('input' => array('type' => 'hidden', 'name' => 'data[Model][1][field]', 'value' => 'N', 'id' => 'Model1Field_')), + array('input' => array('type' => 'radio', 'name' => 'data[Model][1][field]', 'value' => '0', 'id' => 'Model1Field0')), + 'label' => array('for' => 'Model1Field0'), + 'option A', + '/label', + '/div' + ); + $this->assertTags($result, $expected); + } + /** * test adding an empty option for radio buttons * diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 61ec241c3f8..8a15e1d7a67 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1674,7 +1674,7 @@ public function radio($fieldName, $options = array(), $attributes = array()) { $hidden = $this->hidden($fieldName, array( 'form' => isset($attributes['form']) ? $attributes['form'] : null, 'id' => $attributes['id'] . '_', - 'value' => '', + 'value' => $hiddenField === true ? '' : $hiddenField, 'name' => $attributes['name'] )); } From 0b658697f2ad58ce96247d09e5b31b1c06dbee8a Mon Sep 17 00:00:00 2001 From: Mike Fellows Date: Wed, 16 Aug 2017 11:23:42 -0700 Subject: [PATCH 08/44] Sqlserver DboSource does not allow the persistent option to be true. This is backported from CakePHP 3. The SQL Server PHP PDO driver does not support the PDO::ATTR_PERSISTENT attribute. So throw an exception if the 'persistent' option is set in the database config. Also removes that option from the Sqlserver base config. --- lib/Cake/Model/Datasource/Database/Sqlserver.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index 806ec914493..03e9f909182 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -72,7 +72,6 @@ class Sqlserver extends DboSource { * @var array */ protected $_baseConfig = array( - 'persistent' => true, 'host' => 'localhost\SQLEXPRESS', 'login' => '', 'password' => '', @@ -118,15 +117,24 @@ class Sqlserver extends DboSource { /** * Connects to the database using options in the given configuration array. * + * Please note that the PDO::ATTR_PERSISTENT attribute is not supported by + * the SQL Server PHP PDO drivers. As a result you cannot use the + * persistent config option when connecting to a SQL Server (for more + * information see: https://github.com/Microsoft/msphpsql/issues/65). + * * @return bool True if the database could be connected, else false + * @throws InvalidArgumentException if an unsupported setting is in the database config * @throws MissingConnectionException */ public function connect() { $config = $this->config; $this->connected = false; + if (isset($config['persistent']) && $config['persistent']) { + throw new InvalidArgumentException('Config setting "persistent" cannot be set to true, as the Sqlserver PDO driver does not support PDO::ATTR_PERSISTENT'); + } + $flags = $config['flags'] + array( - PDO::ATTR_PERSISTENT => $config['persistent'], PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); From 2e75f12a4f05450b8be062999f0c2157cb80922e Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 22 Aug 2017 10:06:37 -0500 Subject: [PATCH 09/44] Fixed SessionHelper not handling stacked messages --- .../Case/View/Helper/SessionHelperTest.php | 34 ++++++----- lib/Cake/View/Helper/SessionHelper.php | 58 ++++++++++++------- 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php b/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php index ab3e0a773fd..f373218a7e6 100644 --- a/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php @@ -47,24 +47,32 @@ public function setUp() { 'test' => 'info', 'Message' => array( 'flash' => array( - 'element' => 'default', - 'params' => array(), - 'message' => 'This is a calling' + array( + 'element' => 'default', + 'params' => array(), + 'message' => 'This is a calling' + ), ), 'notification' => array( - 'element' => 'session_helper', - 'params' => array('title' => 'Notice!', 'name' => 'Alert!'), - 'message' => 'This is a test of the emergency broadcasting system', + array( + 'element' => 'session_helper', + 'params' => array('title' => 'Notice!', 'name' => 'Alert!'), + 'message' => 'This is a test of the emergency broadcasting system', + ), ), 'classy' => array( - 'element' => 'default', - 'params' => array('class' => 'positive'), - 'message' => 'Recorded' + array( + 'element' => 'default', + 'params' => array('class' => 'positive'), + 'message' => 'Recorded' + ), ), 'bare' => array( - 'element' => null, - 'message' => 'Bare message', - 'params' => array(), + array( + 'element' => null, + 'message' => 'Bare message', + 'params' => array(), + ), ), ), 'Deeply' => array('nested' => array('key' => 'value')), @@ -104,7 +112,7 @@ public function testRead() { public function testCheck() { $this->assertTrue($this->Session->check('test')); - $this->assertTrue($this->Session->check('Message.flash.element')); + $this->assertTrue($this->Session->check('Message.flash.0.element')); $this->assertFalse($this->Session->check('Does.not.exist')); diff --git a/lib/Cake/View/Helper/SessionHelper.php b/lib/Cake/View/Helper/SessionHelper.php index 6a97dbddd1e..fd340843d19 100644 --- a/lib/Cake/View/Helper/SessionHelper.php +++ b/lib/Cake/View/Helper/SessionHelper.php @@ -134,30 +134,14 @@ public function flash($key = 'flash', $attrs = array()) { if (CakeSession::check('Message.' . $key)) { $flash = CakeSession::read('Message.' . $key); CakeSession::delete('Message.' . $key); - $message = $flash['message']; - unset($flash['message']); - if (!empty($attrs)) { - $flash = array_merge($flash, $attrs); - } - - if ($flash['element'] === 'default') { - $class = 'message'; - if (!empty($flash['params']['class'])) { - $class = $flash['params']['class']; + $out = ''; + foreach ($flash as $flashArray) { + if (!empty($attrs)) { + $flashArray = array_merge($flashArray, $attrs); } - $out = '
' . $message . '
'; - } elseif (!$flash['element']) { - $out = $message; - } else { - $options = array(); - if (isset($flash['params']['plugin'])) { - $options['plugin'] = $flash['params']['plugin']; - } - $tmpVars = $flash['params']; - $tmpVars['message'] = $message; - $tmpVars['key'] = $key; - $out = $this->_View->element($flash['element'], $tmpVars, $options); + $flashArray['key'] = $key; + $out .= $this->_render($flashArray); } } return $out; @@ -173,4 +157,34 @@ public function valid() { return CakeSession::valid(); } +/** + * Renders a flash message + * + * @param array $flash Flash message array + * @return string + */ + protected function _render($flash) { + $message = $flash['message']; + unset($flash['message']); + + if ($flash['element'] === 'default') { + $class = 'message'; + if (!empty($flash['params']['class'])) { + $class = $flash['params']['class']; + } + $out = '
' . $message . '
'; + } elseif (!$flash['element']) { + $out = $message; + } else { + $options = array(); + if (isset($flash['params']['plugin'])) { + $options['plugin'] = $flash['params']['plugin']; + } + $tmpVars = $flash['params']; + $tmpVars['message'] = $message; + $tmpVars['key'] = $flash['key']; + $out = $this->_View->element($flash['element'], $tmpVars, $options); + } + return $out; + } } From 81d824077a2d70b7a50acc664a30df49054dd31a Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 29 Aug 2017 21:19:36 -0400 Subject: [PATCH 10/44] Update version number to 2.10.2 --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index 69c5fdc0337..c3b4d26390f 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.10.1 +2.10.2 From f9f06e68b1c59f5a0119ae2969c0d7ce70d5c321 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Wed, 30 Aug 2017 10:06:56 -0500 Subject: [PATCH 11/44] Stacking messages in SessionComponent::setFlash --- lib/Cake/Controller/Component/SessionComponent.php | 8 +++++++- .../Case/Controller/Component/SessionComponentTest.php | 9 +++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Controller/Component/SessionComponent.php b/lib/Cake/Controller/Component/SessionComponent.php index 4c7b467da2d..f66f5be6255 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -136,7 +136,13 @@ public function error() { * @deprecated 3.0.0 Since 2.7, use the FlashComponent instead. */ public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') { - CakeSession::write('Message.' . $key, compact('message', 'element', 'params')); + $messages = (array)CakeSession::read('Message.' . $key); + $messages[] = [ + 'message' => $message, + 'element' => $element, + 'params' => $params, + ]; + CakeSession::write('Message.' . $key, $messages); } /** diff --git a/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php index dd0df58c736..8814a491fbe 100644 --- a/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php @@ -247,16 +247,13 @@ public function testSessionFlash() { $this->assertNull($Session->read('Message.flash')); $Session->setFlash('This is a test message'); - $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.flash')); + $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.flash.0')); $Session->setFlash('This is a test message', 'test', array('name' => 'Joel Moss')); - $this->assertEquals(array('message' => 'This is a test message', 'element' => 'test', 'params' => array('name' => 'Joel Moss')), $Session->read('Message.flash')); + $this->assertEquals(array('message' => 'This is a test message', 'element' => 'test', 'params' => array('name' => 'Joel Moss')), $Session->read('Message.flash.1')); $Session->setFlash('This is a test message', 'default', array(), 'myFlash'); - $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.myFlash')); - - $Session->setFlash('This is a test message', 'non_existing_layout'); - $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.myFlash')); + $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.myFlash.0')); $Session->delete('Message'); } From 0558c253f61dc1adb6d1c4f9c83278a0fedfa4d7 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 31 Aug 2017 09:02:08 -0500 Subject: [PATCH 12/44] Replaced short array syntax with longer form --- lib/Cake/Controller/Component/SessionComponent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Controller/Component/SessionComponent.php b/lib/Cake/Controller/Component/SessionComponent.php index f66f5be6255..4057885ca74 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -137,11 +137,11 @@ public function error() { */ public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') { $messages = (array)CakeSession::read('Message.' . $key); - $messages[] = [ + $messages[] = array( 'message' => $message, 'element' => $element, 'params' => $params, - ]; + ); CakeSession::write('Message.' . $key, $messages); } From 715dca87014a42721a640e821e60b2c19fd90fcd Mon Sep 17 00:00:00 2001 From: LustyRain Date: Fri, 15 Sep 2017 11:42:54 +0900 Subject: [PATCH 13/44] fixed basic.php The return value is incorrect --- lib/Cake/basics.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/basics.php b/lib/Cake/basics.php index 75010f02394..61ca6f04758 100644 --- a/lib/Cake/basics.php +++ b/lib/Cake/basics.php @@ -196,7 +196,7 @@ function sortByKey(&$array, $sortBy, $order = 'asc', $type = SORT_NUMERIC) { * implement a `__toString` method. Otherwise the class name will be used. * @param bool $double Encode existing html entities * @param string $charset Character set to use when escaping. Defaults to config value in 'App.encoding' or 'UTF-8' - * @return string Wrapped text + * @return string|array|object Wrapped text, Wrapped Array or Wrapped Object * @link https://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#h */ function h($text, $double = true, $charset = null) { From c3a612aa94d30a4c51653f40f55ce07177300307 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 17 Sep 2017 22:12:29 -0400 Subject: [PATCH 14/44] Update version number to 2.10.3 --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index c3b4d26390f..2e9e56b553d 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.10.2 +2.10.3 From 0bea90a5a26593521f140f1b96495e41a857ace3 Mon Sep 17 00:00:00 2001 From: Ionut-Mihai Burlacu Date: Thu, 21 Sep 2017 14:30:51 +0300 Subject: [PATCH 15/44] Fixes --- lib/Cake/Network/Email/CakeEmail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 5946e31af3b..bb4b47f6586 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -70,7 +70,7 @@ class CakeEmail { * * @var string */ - const EMAIL_PATTERN = '/^((?:[\p{L}0-9.!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-.]+)$/ui'; + const EMAIL_PATTERN = '/^((?:[\p{L}0-9.!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-_.]+)$/ui'; /** * Recipient of the email From 3bc55f6341a8bc7dfad07f36160251a5603532d0 Mon Sep 17 00:00:00 2001 From: Ionut-Mihai Burlacu Date: Thu, 21 Sep 2017 14:33:10 +0300 Subject: [PATCH 16/44] Fixes #11221 --- lib/Cake/Network/Email/CakeEmail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 5946e31af3b..bb4b47f6586 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -70,7 +70,7 @@ class CakeEmail { * * @var string */ - const EMAIL_PATTERN = '/^((?:[\p{L}0-9.!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-.]+)$/ui'; + const EMAIL_PATTERN = '/^((?:[\p{L}0-9.!#$%&\'*+\/=?^_`{|}~-]+)*@[\p{L}0-9-_.]+)$/ui'; /** * Recipient of the email From 5540569fccefdf1e4b50b6f988f401c2ca9fd290 Mon Sep 17 00:00:00 2001 From: Ionut-Mihai Burlacu Date: Fri, 22 Sep 2017 11:39:39 +0300 Subject: [PATCH 17/44] Test Case --- lib/Cake/Test/Case/Network/Email/CakeEmailTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php index b84b35950c8..9c7fcf66aa3 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -275,6 +275,10 @@ public function testTo() { $expected = array('cake@cakephp.org' => 'CakePHP'); $this->assertSame($expected, $this->CakeEmail->to()); + $this->CakeEmail->to('cake@cake_php.org', 'CakePHPUnderscore'); + $expected = array('cake@cake_php.org', 'CakePHPUnderscore'); + $this->assertSame($expected, $this->CakeEmail->to()); + $list = array( 'root@localhost' => 'root', 'bjørn@hammeröath.com' => 'Bjorn', From 31ed2d5dfb499eabd8c80d23c5cd7b7321a24dc5 Mon Sep 17 00:00:00 2001 From: Ionut-Mihai Burlacu Date: Fri, 22 Sep 2017 11:45:38 +0300 Subject: [PATCH 18/44] Test Case --- lib/Cake/Test/Case/Network/Email/CakeEmailTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php index 9c7fcf66aa3..a0d15bec87d 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -276,7 +276,7 @@ public function testTo() { $this->assertSame($expected, $this->CakeEmail->to()); $this->CakeEmail->to('cake@cake_php.org', 'CakePHPUnderscore'); - $expected = array('cake@cake_php.org', 'CakePHPUnderscore'); + $expected = array('cake@cake_php.org' => 'CakePHPUnderscore'); $this->assertSame($expected, $this->CakeEmail->to()); $list = array( From bececc421df18000663dea0bc9c5ce4d8d68abcb Mon Sep 17 00:00:00 2001 From: LustyRain Date: Mon, 2 Oct 2017 15:40:48 +0900 Subject: [PATCH 19/44] Fix: void unreturn --- lib/Cake/Controller/Component/SessionComponent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Controller/Component/SessionComponent.php b/lib/Cake/Controller/Component/SessionComponent.php index 4057885ca74..b298e420dbb 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -153,7 +153,7 @@ public function setFlash($message, $element = 'default', $params = array(), $key * @return void */ public function renew() { - return CakeSession::renew(); + CakeSession::renew(); } /** @@ -176,7 +176,7 @@ public function valid() { * @link https://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::destroy */ public function destroy() { - return CakeSession::destroy(); + CakeSession::destroy(); } /** From 31b13edf8a381cfe908890141c5387b3b45bc78f Mon Sep 17 00:00:00 2001 From: LustyRain Date: Wed, 4 Oct 2017 00:22:42 +0900 Subject: [PATCH 20/44] Fix: phpdoc miss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## did - void unReturn - miss return void - add return type - type miss typing - add param type and return type - string → string|array - change ClassName --- lib/Cake/Console/ConsoleErrorHandler.php | 4 ++-- lib/Cake/Console/Shell.php | 8 ++++---- lib/Cake/Controller/Component/Acl/DbAcl.php | 2 +- lib/Cake/Controller/Component/Auth/DigestAuthenticate.php | 2 +- lib/Cake/Controller/Component/AuthComponent.php | 2 +- lib/Cake/Controller/Component/CookieComponent.php | 6 +++--- lib/Cake/Controller/Component/EmailComponent.php | 2 +- lib/Cake/Event/CakeEvent.php | 2 +- lib/Cake/Event/CakeEventManager.php | 3 ++- lib/Cake/Model/Behavior/TranslateBehavior.php | 6 +++--- lib/Cake/Model/BehaviorCollection.php | 6 +++--- lib/Cake/Model/Datasource/Database/Sqlite.php | 2 +- lib/Cake/Model/ModelValidator.php | 2 +- lib/Cake/Network/Http/HttpSocket.php | 2 +- lib/Cake/Network/Http/HttpSocketResponse.php | 2 +- lib/Cake/Utility/File.php | 4 ++-- lib/Cake/Utility/Folder.php | 2 +- lib/Cake/Utility/Sanitize.php | 4 ++-- 18 files changed, 31 insertions(+), 30 deletions(-) diff --git a/lib/Cake/Console/ConsoleErrorHandler.php b/lib/Cake/Console/ConsoleErrorHandler.php index 3df0bf73455..b12560e301c 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -60,7 +60,7 @@ public function handleException($exception) { )); $code = $exception->getCode(); $code = ($code && is_int($code)) ? $code : 1; - return $this->_stop($code); + $this->_stop($code); } /** @@ -88,7 +88,7 @@ public function handleError($code, $description, $file = null, $line = null, $co } if ($log === LOG_ERR) { - return $this->_stop(1); + $this->_stop(1); } } diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php index e4ce01f3cf6..90ee0eb3853 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -415,7 +415,7 @@ public function dispatchShell() { * @param string $command The command name to run on this shell. If this argument is empty, * and the shell has a `main()` method, that will be called instead. * @param array $argv Array of arguments to run the shell with. This array should be missing the shell name. - * @return void + * @return int|bool * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand */ public function runCommand($command, $argv) { @@ -469,7 +469,7 @@ public function runCommand($command, $argv) { * Display the help in the correct format * * @param string $command The command to get help for. - * @return void + * @return int|bool */ protected function _displayHelp($command) { $format = 'text'; @@ -571,7 +571,7 @@ public function in($prompt, $options = null, $default = null) { * @param string $prompt Prompt text. * @param string|array $options Array or string of options. * @param string $default Default input value. - * @return Either the default value, or the user-provided input. + * @return string|int the default value, or the user-provided input. */ protected function _getInput($prompt, $options, $default) { if (!is_array($options)) { @@ -726,7 +726,7 @@ public function hr($newlines = 0, $width = 63) { * * @param string $title Title of the error * @param string $message An optional error message - * @return void + * @return int * @link https://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error */ public function error($title, $message = null) { diff --git a/lib/Cake/Controller/Component/Acl/DbAcl.php b/lib/Cake/Controller/Component/Acl/DbAcl.php index eb420709c73..dbbb30fef4a 100644 --- a/lib/Cake/Controller/Component/Acl/DbAcl.php +++ b/lib/Cake/Controller/Component/Acl/DbAcl.php @@ -52,7 +52,7 @@ public function __construct() { /** * Initializes the containing component and sets the Aro/Aco objects to it. * - * @param AclComponent $component The AclComponent instance. + * @param Component $component The AclComponent instance. * @return void */ public function initialize(Component $component) { diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index f1ba711cda8..86fdac616ae 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -136,7 +136,7 @@ public function getUser(CakeRequest $request) { /** * Gets the digest headers from the request/environment. * - * @return array Array of digest information. + * @return array|bool|null Array of digest information. */ protected function _getDigest() { $digest = env('PHP_AUTH_DIGEST'); diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php index 9fe60e68392..e21f6e08507 100644 --- a/lib/Cake/Controller/Component/AuthComponent.php +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -761,7 +761,7 @@ public function redirectUrl($url = null) { * * @param CakeRequest $request The request that contains authentication data. * @param CakeResponse $response The response - * @return array User record data, or false, if the user could not be identified. + * @return array|bool User record data, or false, if the user could not be identified. */ public function identify(CakeRequest $request, CakeResponse $response) { if (empty($this->_authenticateObjects)) { diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index af46d5e9e41..4332dac8121 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -494,7 +494,7 @@ protected function _encrypt($value) { * Decrypts $value using public $type method in Security class * * @param array $values Values to decrypt - * @return string decrypted string + * @return array decrypted string */ protected function _decrypt($values) { $decrypted = array(); @@ -516,7 +516,7 @@ protected function _decrypt($values) { * Decodes and decrypts a single value. * * @param string $value The value to decode & decrypt. - * @return string Decoded value. + * @return string|array Decoded value. */ protected function _decode($value) { $prefix = 'Q2FrZQ==.'; @@ -552,7 +552,7 @@ protected function _implode(array $array) { * Maintains reading backwards compatibility with 1.x CookieComponent::_implode(). * * @param string $string A string containing JSON encoded data, or a bare string. - * @return array Map of key and values + * @return string|array Map of key and values */ protected function _explode($string) { $first = substr($string, 0, 1); diff --git a/lib/Cake/Controller/Component/EmailComponent.php b/lib/Cake/Controller/Component/EmailComponent.php index 47e91d2b084..4fd96dfb7f5 100644 --- a/lib/Cake/Controller/Component/EmailComponent.php +++ b/lib/Cake/Controller/Component/EmailComponent.php @@ -282,7 +282,7 @@ public function initialize(Controller $controller) { * If you are rendering a template this variable will be sent to the templates as `$content` * @param string $template Template to use when sending email * @param string $layout Layout to use to enclose email body - * @return bool Success + * @return array Success */ public function send($content = null, $template = null, $layout = null) { $lib = new CakeEmail(); diff --git a/lib/Cake/Event/CakeEvent.php b/lib/Cake/Event/CakeEvent.php index 322fac19dc4..4a23756efc1 100644 --- a/lib/Cake/Event/CakeEvent.php +++ b/lib/Cake/Event/CakeEvent.php @@ -111,7 +111,7 @@ public function subject() { /** * Stops the event from being used anymore * - * @return void + * @return bool */ public function stopPropagation() { return $this->_stopped = true; diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index e2d9276e67c..e4b74a09614 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -166,7 +166,8 @@ protected function _extractCallable($function, $object) { */ public function detach($callable, $eventKey = null) { if ($callable instanceof CakeEventListener) { - return $this->_detachSubscriber($callable, $eventKey); + $this->_detachSubscriber($callable, $eventKey); + return ; } if (empty($eventKey)) { foreach (array_keys($this->_listeners) as $eventKey) { diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index 740fcccadf9..1b9b51116a8 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -432,7 +432,7 @@ public function beforeSave(Model $Model, $options = array()) { * is disabled. * * @param Model $Model Model using this behavior. - * @return void + * @return bool true. */ protected function _setRuntimeData(Model $Model) { $locale = $this->_getLocale($Model); @@ -465,7 +465,7 @@ protected function _setRuntimeData(Model $Model) { * This solves issues with saveAssociated and validate = first. * * @param Model $Model Model using this behavior. - * @return void + * @return bool true. */ public function afterValidate(Model $Model) { $Model->data[$Model->alias] = array_merge( @@ -481,7 +481,7 @@ public function afterValidate(Model $Model) { * @param Model $Model Model the callback is called on * @param bool $created Whether or not the save created a record. * @param array $options Options passed from Model::save(). - * @return void + * @return bool true. */ public function afterSave(Model $Model, $created, $options = array()) { if (!isset($this->runtime[$Model->alias]['beforeValidate']) && !isset($this->runtime[$Model->alias]['beforeSave'])) { diff --git a/lib/Cake/Model/BehaviorCollection.php b/lib/Cake/Model/BehaviorCollection.php index d137cb22230..db10a8762ff 100644 --- a/lib/Cake/Model/BehaviorCollection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -73,7 +73,7 @@ public function init($modelName, $behaviors = array()) { * * @param string $behavior Behavior name. * @param array $config Configuration options. - * @return void + * @return bool true. * @deprecated 3.0.0 Will be removed in 3.0. Replaced with load(). */ public function attach($behavior, $config = array()) { @@ -97,7 +97,7 @@ public function attach($behavior, $config = array()) { * * @param string $behavior CamelCased name of the behavior to load * @param array $config Behavior configuration parameters - * @return bool True on success, false on failure + * @return bool True on success. * @throws MissingBehaviorException when a behavior could not be found. */ public function load($behavior, $config = array()) { @@ -204,7 +204,7 @@ public function unload($name) { * @deprecated 3.0.0 Will be removed in 3.0. Use unload instead. */ public function detach($name) { - return $this->unload($name); + $this->unload($name); } /** diff --git a/lib/Cake/Model/Datasource/Database/Sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php index 9a9e4c1c33f..2cf39c35690 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlite.php +++ b/lib/Cake/Model/Datasource/Database/Sqlite.php @@ -212,7 +212,7 @@ public function describe($model) { * @param array $fields The fields to update. * @param array $values The values to set columns to. * @param mixed $conditions array of conditions to use. - * @return array + * @return bool */ public function update(Model $model, $fields = array(), $values = null, $conditions = null) { if (empty($values) && !empty($fields)) { diff --git a/lib/Cake/Model/ModelValidator.php b/lib/Cake/Model/ModelValidator.php index bcf6b9e4414..f968e2cfff5 100644 --- a/lib/Cake/Model/ModelValidator.php +++ b/lib/Cake/Model/ModelValidator.php @@ -234,7 +234,7 @@ public function validateMany(&$data, $options = array()) { * actually run validation rules over data, not just return the messages. * * @param string $options An optional array of custom options to be made available in the beforeValidate callback - * @return array Array of invalid fields + * @return array|bool Array of invalid fields * @triggers Model.afterValidate $model * @see ModelValidator::validates() */ diff --git a/lib/Cake/Network/Http/HttpSocket.php b/lib/Cake/Network/Http/HttpSocket.php index 8aacde4ef53..1643bcbfd2c 100644 --- a/lib/Cake/Network/Http/HttpSocket.php +++ b/lib/Cake/Network/Http/HttpSocket.php @@ -760,7 +760,7 @@ protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pa * * @param string|array $uri URI to parse * @param bool|array $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc. - * @return array Parsed URI + * @return array|bool Parsed URI */ protected function _parseUri($uri = null, $base = array()) { $uriBase = array( diff --git a/lib/Cake/Network/Http/HttpSocketResponse.php b/lib/Cake/Network/Http/HttpSocketResponse.php index 3be02126a3b..69c6da725da 100644 --- a/lib/Cake/Network/Http/HttpSocketResponse.php +++ b/lib/Cake/Network/Http/HttpSocketResponse.php @@ -259,7 +259,7 @@ protected function _decodeChunkedBody($body) { * Parses an array based header. * * @param array $header Header as an indexed array (field => value) - * @return array Parsed header + * @return array|bool Parsed header */ protected function _parseHeader($header) { if (is_array($header)) { diff --git a/lib/Cake/Utility/File.php b/lib/Cake/Utility/File.php index 6c4bed1070a..06ecf6c6510 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -581,10 +581,10 @@ public function mime() { */ public function clearStatCache($all = false) { if ($all === false && version_compare(PHP_VERSION, '5.3.0') >= 0) { - return clearstatcache(true, $this->path); + clearstatcache(true, $this->path); } - return clearstatcache(); + clearstatcache(); } /** diff --git a/lib/Cake/Utility/Folder.php b/lib/Cake/Utility/Folder.php index 2ee5ad30b18..62fef677a16 100644 --- a/lib/Cake/Utility/Folder.php +++ b/lib/Cake/Utility/Folder.php @@ -323,7 +323,7 @@ public static function isAbsolute($path) { * Returns true if given $path is a registered stream wrapper. * * @param string $path Path to check - * @return boo true If path is registered stream wrapper. + * @return bool true If path is registered stream wrapper. */ public static function isRegisteredStreamWrapper($path) { if (preg_match('/^[A-Z]+(?=:\/\/)/i', $path, $matches) && diff --git a/lib/Cake/Utility/Sanitize.php b/lib/Cake/Utility/Sanitize.php index 450d061f6ac..0f8b5e073fe 100644 --- a/lib/Cake/Utility/Sanitize.php +++ b/lib/Cake/Utility/Sanitize.php @@ -34,9 +34,9 @@ class Sanitize { /** * Removes any non-alphanumeric characters. * - * @param string $string String to sanitize + * @param string|array $string String to sanitize * @param array $allowed An array of additional characters that are not to be removed. - * @return string Sanitized string + * @return string|array Sanitized string */ public static function paranoid($string, $allowed = array()) { $allow = null; From 8bb07c0fd764d313d5bbe4c7c7f0f5dfc7c4d478 Mon Sep 17 00:00:00 2001 From: LustyRain Date: Wed, 4 Oct 2017 11:39:31 +0900 Subject: [PATCH 21/44] Fix called twice --- lib/Cake/Utility/File.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Cake/Utility/File.php b/lib/Cake/Utility/File.php index 06ecf6c6510..344e00df9a3 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -582,6 +582,7 @@ public function mime() { public function clearStatCache($all = false) { if ($all === false && version_compare(PHP_VERSION, '5.3.0') >= 0) { clearstatcache(true, $this->path); + return ; } clearstatcache(); From 1f093187245f621102393e17844945803b792dc7 Mon Sep 17 00:00:00 2001 From: LustyRain Date: Wed, 4 Oct 2017 20:40:57 +0900 Subject: [PATCH 22/44] Fix delete space, restored return --- lib/Cake/Console/ConsoleErrorHandler.php | 2 +- lib/Cake/Utility/File.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/ConsoleErrorHandler.php b/lib/Cake/Console/ConsoleErrorHandler.php index b12560e301c..6a07d0128bf 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -60,7 +60,7 @@ public function handleException($exception) { )); $code = $exception->getCode(); $code = ($code && is_int($code)) ? $code : 1; - $this->_stop($code); + return $this->_stop($code); } /** diff --git a/lib/Cake/Utility/File.php b/lib/Cake/Utility/File.php index 344e00df9a3..a2e704143e0 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -582,7 +582,7 @@ public function mime() { public function clearStatCache($all = false) { if ($all === false && version_compare(PHP_VERSION, '5.3.0') >= 0) { clearstatcache(true, $this->path); - return ; + return; } clearstatcache(); From 0f00d73c707d720a9819796296c16a27bfc5b628 Mon Sep 17 00:00:00 2001 From: LustyRain Date: Wed, 4 Oct 2017 21:02:48 +0900 Subject: [PATCH 23/44] Fix delete space, restored return --- lib/Cake/Console/ConsoleErrorHandler.php | 2 +- lib/Cake/Event/CakeEventManager.php | 2 +- lib/Cake/Model/BehaviorCollection.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Console/ConsoleErrorHandler.php b/lib/Cake/Console/ConsoleErrorHandler.php index 6a07d0128bf..3df0bf73455 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -88,7 +88,7 @@ public function handleError($code, $description, $file = null, $line = null, $co } if ($log === LOG_ERR) { - $this->_stop(1); + return $this->_stop(1); } } diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index e4b74a09614..ef53ea4c17c 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -167,7 +167,7 @@ protected function _extractCallable($function, $object) { public function detach($callable, $eventKey = null) { if ($callable instanceof CakeEventListener) { $this->_detachSubscriber($callable, $eventKey); - return ; + return; } if (empty($eventKey)) { foreach (array_keys($this->_listeners) as $eventKey) { diff --git a/lib/Cake/Model/BehaviorCollection.php b/lib/Cake/Model/BehaviorCollection.php index db10a8762ff..faae57064f4 100644 --- a/lib/Cake/Model/BehaviorCollection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -204,7 +204,7 @@ public function unload($name) { * @deprecated 3.0.0 Will be removed in 3.0. Use unload instead. */ public function detach($name) { - $this->unload($name); + return $this->unload($name); } /** From e1e5a292f216efbed2c11b037de5c28fd341ca43 Mon Sep 17 00:00:00 2001 From: LustyRain Date: Thu, 5 Oct 2017 00:09:51 +0900 Subject: [PATCH 24/44] Fix: revert return --- lib/Cake/Event/CakeEventManager.php | 3 +-- lib/Cake/Utility/File.php | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index ef53ea4c17c..e2d9276e67c 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -166,8 +166,7 @@ protected function _extractCallable($function, $object) { */ public function detach($callable, $eventKey = null) { if ($callable instanceof CakeEventListener) { - $this->_detachSubscriber($callable, $eventKey); - return; + return $this->_detachSubscriber($callable, $eventKey); } if (empty($eventKey)) { foreach (array_keys($this->_listeners) as $eventKey) { diff --git a/lib/Cake/Utility/File.php b/lib/Cake/Utility/File.php index a2e704143e0..6c4bed1070a 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -581,11 +581,10 @@ public function mime() { */ public function clearStatCache($all = false) { if ($all === false && version_compare(PHP_VERSION, '5.3.0') >= 0) { - clearstatcache(true, $this->path); - return; + return clearstatcache(true, $this->path); } - clearstatcache(); + return clearstatcache(); } /** From 22d2564de95d7d58e7e3d091f000aa96b86bf34f Mon Sep 17 00:00:00 2001 From: kolorafa Date: Thu, 5 Oct 2017 11:45:33 +0200 Subject: [PATCH 25/44] msSQL - also handle offset as string When doing pagination you could get offset not as a int(eg. 10) but string(eg. "10") and it will not paginate at all. For example DataTables plugin pass offset from params and all params from http request are strings wrapped in numbers. Adding ctype_digit($offset) will also check the case. --- lib/Cake/Model/Datasource/Database/Sqlserver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index 03e9f909182..2e9c78fd706 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -411,7 +411,7 @@ public function limit($limit, $offset = null) { $rt = ' TOP'; } $rt .= sprintf(' %u', $limit); - if (is_int($offset) && $offset > 0) { + if ((is_int($offset) || ctype_digit($offset)) && $offset > 0) { $rt = sprintf(' OFFSET %u ROWS FETCH FIRST %u ROWS ONLY', $offset, $limit); } return $rt; From 959f45a6c68e0d0277869510b936779a43f42e8f Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Fri, 6 Oct 2017 13:32:50 +0900 Subject: [PATCH 26/44] Fix fatal error thrown when replacing scalar with array Refs #11280 --- .../Controller/Component/CookieComponent.php | 23 ++++--------------- .../Component/CookieComponentTest.php | 18 +++++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index 4332dac8121..5aeb5a36542 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -229,27 +229,14 @@ public function write($key, $value = null, $encrypt = true, $expires = null) { } foreach ($key as $name => $value) { - $names = array($name); if (strpos($name, '.') !== false) { - $names = explode('.', $name, 2); - } - $firstName = $names[0]; - $isMultiValue = (is_array($value) || count($names) > 1); - - if (!isset($this->_values[$this->name][$firstName]) && $isMultiValue) { - $this->_values[$this->name][$firstName] = array(); - } - - if (count($names) > 1) { - $this->_values[$this->name][$firstName] = Hash::insert( - $this->_values[$this->name][$firstName], - $names[1], - $value - ); + $this->_values[$this->name] = Hash::insert($this->_values[$this->name], $name, $value); + list($name) = explode('.', $name, 2); + $value = $this->_values[$this->name][$name]; } else { - $this->_values[$this->name][$firstName] = $value; + $this->_values[$this->name][$name] = $value; } - $this->_write('[' . $firstName . ']', $this->_values[$this->name][$firstName]); + $this->_write('[' . $name . ']', $value); } $this->_encrypted = true; } diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index c3fddddb379..ea2f4998bd5 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -429,6 +429,24 @@ public function testWriteMixedArray() { $this->assertEquals($expected, $result); } +/** + * Test that replacing scalar with array works. + * + * @return void + */ + public function testReplaceScalarWithArray() { + $this->Cookie->write('foo', 1); + $this->Cookie->write('foo.bar', 2); + + $data = $this->Cookie->read(); + $expected = array( + 'foo' => array( + 'bar' => 2 + ) + ); + $this->assertEquals($expected, $data); + } + /** * testReadingCookieValue * From ccf634e5f3cf1d60d9c13057455ec7164488ec35 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Fri, 6 Oct 2017 18:15:52 +0900 Subject: [PATCH 27/44] Docblock update --- lib/Cake/Utility/Hash.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Utility/Hash.php b/lib/Cake/Utility/Hash.php index 344d7bca196..6208aa4a4b5 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -91,8 +91,8 @@ public static function get(array $data, $path, $default = null) { * * - `1.User.name` Get the name of the user at index 1. * - `{n}.User.name` Get the name of every user in the set of users. - * - `{n}.User[id]` Get the name of every user with an id key. - * - `{n}.User[id>=2]` Get the name of every user with an id key greater than or equal to 2. + * - `{n}.User[id].name` Get the name of every user with an id key. + * - `{n}.User[id>=2].name` Get the name of every user with an id key greater than or equal to 2. * - `{n}.User[username=/^paul/]` Get User elements with username matching `^paul`. * * @param array $data The data to extract from. @@ -149,6 +149,7 @@ public static function extract(array $data, $path) { } return $context[$_key]; } + /** * Split token conditions * @@ -454,7 +455,7 @@ public static function combine(array $data, $keyPath, $valuePath = null, $groupP * The `$format` string can use any format options that `vsprintf()` and `sprintf()` do. * * @param array $data Source array from which to extract the data - * @param string $paths An array containing one or more Hash::extract()-style key paths + * @param array $paths An array containing one or more Hash::extract()-style key paths * @param string $format Format string into which values will be inserted, see sprintf() * @return array An array of strings extracted from `$path` and formatted with `$format` * @link https://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::format @@ -729,7 +730,7 @@ public static function numeric(array $data) { * Counts the dimensions of an array. * Only considers the dimension of the first element in the array. * - * If you have an un-even or heterogenous array, consider using Hash::maxDimensions() + * If you have an un-even or heterogeneous array, consider using Hash::maxDimensions() * to get the dimensions of the array. * * @param array $data Array to count dimensions on @@ -809,11 +810,15 @@ public static function reduce(array $data, $path, $function) { * You can easily count the results of an extract using apply(). * For example to count the comments on an Article: * - * `$count = Hash::apply($data, 'Article.Comment.{n}', 'count');` + * ``` + * $count = Hash::apply($data, 'Article.Comment.{n}', 'count'); + * ``` * * You could also use a function like `array_sum` to sum the results. * - * `$total = Hash::apply($data, '{n}.Item.price', 'array_sum');` + * ``` + * $total = Hash::apply($data, '{n}.Item.price', 'array_sum'); + * ``` * * @param array $data The data to reduce. * @param string $path The path to extract from $data. @@ -833,7 +838,7 @@ public static function apply(array $data, $path, $function) { * - `asc` Sort ascending. * - `desc` Sort descending. * - * ## Sort types + * ### Sort types * * - `regular` For regular sorting (don't change types) * - `numeric` Compare values numerically From deac8f9109b5de7768c41081281dbcf5d98dda2c Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Fri, 6 Oct 2017 22:02:37 +0900 Subject: [PATCH 28/44] Backport #7080, #8233 and #11060 --- lib/Cake/Test/Case/Utility/HashTest.php | 113 +++++++++++++++++++++++- lib/Cake/Utility/Hash.php | 46 ++++++---- 2 files changed, 139 insertions(+), 20 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/HashTest.php b/lib/Cake/Test/Case/Utility/HashTest.php index c4a43df9d65..fb5db2693c0 100644 --- a/lib/Cake/Test/Case/Utility/HashTest.php +++ b/lib/Cake/Test/Case/Utility/HashTest.php @@ -1356,7 +1356,7 @@ public function testSortNaturalIgnoreCase() { ); $this->assertEquals($expected, $result); - $result = Hash::sort($items, '{n}.Item.image', 'asc', array('type' => 'natural', 'ignoreCase' => true)); + $result = Hash::sort($items, '{n}.Item.image', 'asc', array('type' => 'NATURAL', 'ignoreCase' => true)); $expected = array( array('Item' => array('image' => 'img1.jpg')), array('Item' => array('image' => 'img2.jpg')), @@ -1529,6 +1529,58 @@ public function testSortRegularIgnoreCase() { $this->assertEquals($expected, $sorted); } +/** + * Test sorting on a nested key that is sometimes undefined. + * + * @return void + */ + public function testSortSparse() { + $data = array( + array( + 'id' => 1, + 'title' => 'element 1', + 'extra' => 1, + ), + array( + 'id' => 2, + 'title' => 'element 2', + 'extra' => 2, + ), + array( + 'id' => 3, + 'title' => 'element 3', + ), + array( + 'id' => 4, + 'title' => 'element 4', + 'extra' => 4, + ) + ); + $result = Hash::sort($data, '{n}.extra', 'desc', 'natural'); + $expected = array( + array( + 'id' => 4, + 'title' => 'element 4', + 'extra' => 4, + ), + array( + 'id' => 2, + 'title' => 'element 2', + 'extra' => 2, + ), + array( + 'id' => 1, + 'title' => 'element 1', + 'extra' => 1, + ), + array( + 'id' => 3, + 'title' => 'element 3', + ), + ); + $this->assertSame($expected, $result); + } + /** * Test insert() * @@ -1594,6 +1646,17 @@ public function testInsertMulti() { 4 => array('Item' => array('id' => 5, 'title' => 'fifth')), ); $this->assertEquals($expected, $result); + + $data[3]['testable'] = true; + $result = Hash::insert($data, '{n}[testable].Item[id=/\b2|\b4/].test', 2); + $expected = array( + 0 => array('Item' => array('id' => 1, 'title' => 'first')), + 1 => array('Item' => array('id' => 2, 'title' => 'second')), + 2 => array('Item' => array('id' => 3, 'title' => 'third')), + 3 => array('Item' => array('id' => 4, 'title' => 'fourth', 'test' => 2), 'testable' => true), + 4 => array('Item' => array('id' => 5, 'title' => 'fifth')), + ); + $this->assertEquals($expected, $result); } /** @@ -1686,6 +1749,43 @@ public function testRemove() { $this->assertEquals($expected, $result); $result = Hash::remove($array, '{n}.{n}.part'); $this->assertEquals($expected, $result); + + $array = array( + 'foo' => 'string', + ); + $expected = $array; + $result = Hash::remove($array, 'foo.bar'); + $this->assertEquals($expected, $result); + + $array = array( + 'foo' => 'string', + 'bar' => array( + 0 => 'a', + 1 => 'b', + ), + ); + $expected = array( + 'foo' => 'string', + 'bar' => array( + 1 => 'b', + ), + ); + $result = Hash::remove($array, '{s}.0'); + $this->assertEquals($expected, $result); + + $array = array( + 'foo' => array( + 0 => 'a', + 1 => 'b', + ), + ); + $expected = array( + 'foo' => array( + 1 => 'b', + ), + ); + $result = Hash::remove($array, 'foo[1=b].0'); + $this->assertEquals($expected, $result); } /** @@ -1721,6 +1821,17 @@ public function testRemoveMulti() { 4 => array('Item' => array('id' => 5, 'title' => 'fifth')), ); $this->assertEquals($expected, $result); + + $data[3]['testable'] = true; + $result = Hash::remove($data, '{n}[testable].Item[id=/\b2|\b4/].title'); + $expected = array( + 0 => array('Item' => array('id' => 1, 'title' => 'first')), + 1 => array('Item' => array('id' => 2, 'title' => 'second')), + 2 => array('Item' => array('id' => 3, 'title' => 'third')), + 3 => array('Item' => array('id' => 4), 'testable' => true), + 4 => array('Item' => array('id' => 5, 'title' => 'fifth')), + ); + $this->assertEquals($expected, $result); } /** diff --git a/lib/Cake/Utility/Hash.php b/lib/Cake/Utility/Hash.php index 6208aa4a4b5..08dd2700a52 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -275,12 +275,10 @@ public static function insert(array $data, $path, $values = null) { foreach ($data as $k => $v) { if (static::_matchToken($k, $token)) { - if ($conditions && static::_matches($v, $conditions)) { - $data[$k] = array_merge($v, $values); - continue; - } - if (!$conditions) { - $data[$k] = static::insert($v, $nextPath, $values); + if (!$conditions || static::_matches($v, $conditions)) { + $data[$k] = $nextPath + ? static::insert($v, $nextPath, $values) + : array_merge($v, (array)$values); } } } @@ -302,9 +300,6 @@ protected static function _simpleOp($op, $data, $path, $values = null) { $count = count($path); $last = $count - 1; foreach ($path as $i => $key) { - if ((is_numeric($key) && intval($key) > 0 || $key === '0') && strpos($key, '0') !== 0) { - $key = (int)$key; - } if ($op === 'insert') { if ($i === $last) { $_list[$key] = $values; @@ -319,7 +314,9 @@ protected static function _simpleOp($op, $data, $path, $values = null) { } } elseif ($op === 'remove') { if ($i === $last) { - unset($_list[$key]); + if (is_array($_list)) { + unset($_list[$key]); + } return $data; } if (!isset($_list[$key])) { @@ -359,15 +356,21 @@ public static function remove(array $data, $path) { foreach ($data as $k => $v) { $match = static::_matchToken($k, $token); if ($match && is_array($v)) { - if ($conditions && static::_matches($v, $conditions)) { - unset($data[$k]); - continue; + if ($conditions) { + if (static::_matches($v, $conditions)) { + if ($nextPath !== '') { + $data[$k] = static::remove($v, $nextPath); + } else { + unset($data[$k]); + } + } + } else { + $data[$k] = static::remove($v, $nextPath); } - $data[$k] = static::remove($v, $nextPath); if (empty($data[$k])) { unset($data[$k]); } - } elseif ($match && empty($nextPath)) { + } elseif ($match && $nextPath === '') { unset($data[$k]); } } @@ -873,12 +876,18 @@ public static function sort(array $data, $path, $dir = 'asc', $type = 'regular') $data = array_values($data); } $sortValues = static::extract($data, $path); - $sortCount = count($sortValues); $dataCount = count($data); // Make sortValues match the data length, as some keys could be missing // the sorted value path. - if ($sortCount < $dataCount) { + $missingData = count($sortValues) < $dataCount; + if ($missingData && $numeric) { + // Get the path without the leading '{n}.' + $itemPath = substr($path, 4); + foreach ($data as $key => $value) { + $sortValues[$key] = static::get($value, $itemPath); + } + } elseif ($missingData) { $sortValues = array_pad($sortValues, $dataCount, null); } $result = static::_squash($sortValues); @@ -893,9 +902,8 @@ public static function sort(array $data, $path, $dir = 'asc', $type = 'regular') $type += array('ignoreCase' => false, 'type' => 'regular'); $ignoreCase = $type['ignoreCase']; $type = $type['type']; - } else { - $type = strtolower($type); } + $type = strtolower($type); if ($type === 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) { $type = 'regular'; From 5d5e791a31299ae3678a8caba3c4f4f2577484c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20Wei=C3=9F?= Date: Fri, 6 Oct 2017 17:04:53 +0200 Subject: [PATCH 29/44] Check for session.use_trans_sid and session ID in URL in case cookies are disabled (backport of cakephp/cakephp#10828 for 2.x) --- lib/Cake/Model/Datasource/CakeSession.php | 1520 +++++++++++---------- 1 file changed, 766 insertions(+), 754 deletions(-) diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index 38ab50e920a..3fb00a46eab 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -34,759 +34,771 @@ */ class CakeSession { -/** - * True if the Session is still valid - * - * @var bool - */ - public static $valid = false; - -/** - * Error messages for this session - * - * @var array - */ - public static $error = false; - -/** - * User agent string - * - * @var string - */ - protected static $_userAgent = ''; - -/** - * Path to where the session is active. - * - * @var string - */ - public static $path = '/'; - -/** - * Error number of last occurred error - * - * @var int - */ - public static $lastError = null; - -/** - * Start time for this session. - * - * @var int - */ - public static $time = false; - -/** - * Cookie lifetime - * - * @var int - */ - public static $cookieLifeTime; - -/** - * Time when this session becomes invalid. - * - * @var int - */ - public static $sessionTime = false; - -/** - * Current Session id - * - * @var string - */ - public static $id = null; - -/** - * Hostname - * - * @var string - */ - public static $host = null; - -/** - * Session timeout multiplier factor - * - * @var int - */ - public static $timeout = null; - -/** - * Number of requests that can occur during a session time without the session being renewed. - * This feature is only used when config value `Session.autoRegenerate` is set to true. - * - * @var int - * @see CakeSession::_checkValid() - */ - public static $requestCountdown = 10; - -/** - * Whether or not the init function in this class was already called - * - * @var bool - */ - protected static $_initialized = false; - -/** - * Session cookie name - * - * @var string - */ - protected static $_cookieName = null; - -/** - * Pseudo constructor. - * - * @param string|null $base The base path for the Session - * @return void - */ - public static function init($base = null) { - static::$time = time(); - - if (env('HTTP_USER_AGENT') && !static::$_userAgent) { - static::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); - } - - static::_setPath($base); - static::_setHost(env('HTTP_HOST')); - - if (!static::$_initialized) { - register_shutdown_function('session_write_close'); - } - - static::$_initialized = true; - } - -/** - * Setup the Path variable - * - * @param string|null $base base path - * @return void - */ - protected static function _setPath($base = null) { - if (empty($base)) { - static::$path = '/'; - return; - } - if (strpos($base, 'index.php') !== false) { - $base = str_replace('index.php', '', $base); - } - if (strpos($base, '?') !== false) { - $base = str_replace('?', '', $base); - } - static::$path = $base; - } - -/** - * Set the host name - * - * @param string $host Hostname - * @return void - */ - protected static function _setHost($host) { - static::$host = $host; - if (strpos(static::$host, ':') !== false) { - static::$host = substr(static::$host, 0, strpos(static::$host, ':')); - } - } - -/** - * Starts the Session. - * - * @return bool True if session was started - */ - public static function start() { - if (static::started()) { - return true; - } - - $id = static::id(); - static::_startSession(); - if (!$id && static::started()) { - static::_checkValid(); - } - - static::$error = false; - static::$valid = true; - return static::started(); - } - -/** - * Determine if Session has been started. - * - * @return bool True if session has been started. - */ - public static function started() { - if (function_exists('session_status')) { - return isset($_SESSION) && (session_status() === PHP_SESSION_ACTIVE); - } - return isset($_SESSION) && session_id(); - } - -/** - * Returns true if given variable is set in session. - * - * @param string $name Variable name to check for - * @return bool True if variable is there - */ - public static function check($name) { - if (!static::_hasSession() || !static::start()) { - return false; - } - if (isset($_SESSION[$name])) { - return true; - } - - return Hash::get($_SESSION, $name) !== null; - } - -/** - * Returns the session id. - * Calling this method will not auto start the session. You might have to manually - * assert a started session. - * - * Passing an id into it, you can also replace the session id if the session - * has not already been started. - * Note that depending on the session handler, not all characters are allowed - * within the session id. For example, the file session handler only allows - * characters in the range a-z A-Z 0-9 , (comma) and - (minus). - * - * @param string|null $id Id to replace the current session id - * @return string Session id - */ - public static function id($id = null) { - if ($id) { - static::$id = $id; - session_id(static::$id); - } - if (static::started()) { - return session_id(); - } - return static::$id; - } - -/** - * Removes a variable from session. - * - * @param string $name Session variable to remove - * @return bool Success - */ - public static function delete($name) { - if (static::check($name)) { - static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); - return !static::check($name); - } - return false; - } - -/** - * Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself. - * - * @param array &$old Set of old variables => values - * @param array $new New set of variable => value - * @return void - */ - protected static function _overwrite(&$old, $new) { - if (!empty($old)) { - foreach ($old as $key => $var) { - if (!isset($new[$key])) { - unset($old[$key]); - } - } - } - foreach ($new as $key => $var) { - $old[$key] = $var; - } - } - -/** - * Return error description for given error number. - * - * @param int $errorNumber Error to set - * @return string Error as string - */ - protected static function _error($errorNumber) { - if (!is_array(static::$error) || !array_key_exists($errorNumber, static::$error)) { - return false; - } - return static::$error[$errorNumber]; - } - -/** - * Returns last occurred error as a string, if any. - * - * @return mixed Error description as a string, or false. - */ - public static function error() { - if (static::$lastError) { - return static::_error(static::$lastError); - } - return false; - } - -/** - * Returns true if session is valid. - * - * @return bool Success - */ - public static function valid() { - if (static::start() && static::read('Config')) { - if (static::_validAgentAndTime() && static::$error === false) { - static::$valid = true; - } else { - static::$valid = false; - static::_setError(1, 'Session Highjacking Attempted !!!'); - } - } - return static::$valid; - } - -/** - * Tests that the user agent is valid and that the session hasn't 'timed out'. - * Since timeouts are implemented in CakeSession it checks the current static::$time - * against the time the session is set to expire. The User agent is only checked - * if Session.checkAgent == true. - * - * @return bool - */ - protected static function _validAgentAndTime() { - $userAgent = static::read('Config.userAgent'); - $time = static::read('Config.time'); - $validAgent = ( - Configure::read('Session.checkAgent') === false || - isset($userAgent) && static::$_userAgent === $userAgent - ); - return ($validAgent && static::$time <= $time); - } - -/** - * Get / Set the user agent - * - * @param string|null $userAgent Set the user agent - * @return string Current user agent. - */ - public static function userAgent($userAgent = null) { - if ($userAgent) { - static::$_userAgent = $userAgent; - } - if (empty(static::$_userAgent)) { - CakeSession::init(static::$path); - } - return static::$_userAgent; - } - -/** - * Returns given session variable, or all of them, if no parameters given. - * - * @param string|null $name The name of the session variable (or a path as sent to Set.extract) - * @return mixed The value of the session variable, null if session not available, - * session not started, or provided name not found in the session, false on failure. - */ - public static function read($name = null) { - if (!static::_hasSession() || !static::start()) { - return null; - } - if ($name === null) { - return static::_returnSessionVars(); - } - $result = Hash::get($_SESSION, $name); - - if (isset($result)) { - return $result; - } - return null; - } - -/** - * Returns all session variables. - * - * @return mixed Full $_SESSION array, or false on error. - */ - protected static function _returnSessionVars() { - if (!empty($_SESSION)) { - return $_SESSION; - } - static::_setError(2, 'No Session vars set'); - return false; - } - -/** - * Writes value to given session variable name. - * - * @param string|array $name Name of variable - * @param string $value Value to write - * @return bool True if the write was successful, false if the write failed - */ - public static function write($name, $value = null) { - if (!static::start()) { - return false; - } - - $write = $name; - if (!is_array($name)) { - $write = array($name => $value); - } - foreach ($write as $key => $val) { - static::_overwrite($_SESSION, Hash::insert($_SESSION, $key, $val)); - if (Hash::get($_SESSION, $key) !== $val) { - return false; - } - } - return true; - } - -/** - * Reads and deletes a variable from session. - * - * @param string $name The key to read and remove (or a path as sent to Hash.extract). - * @return mixed The value of the session variable, null if session not available, - * session not started, or provided name not found in the session. - */ - public static function consume($name) { - if (empty($name)) { - return null; - } - $value = static::read($name); - if ($value !== null) { - static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); - } - return $value; - } - -/** - * Helper method to destroy invalid sessions. - * - * @return void - */ - public static function destroy() { - if (!static::started()) { - static::_startSession(); - } - - if (static::started()) { - if (session_id() && static::_hasSession()) { - session_write_close(); - session_start(); - } - session_destroy(); - unset($_COOKIE[static::_cookieName()]); - } - - $_SESSION = null; - static::$id = null; - static::$_cookieName = null; - } - -/** - * Clears the session. - * - * Optionally also clears the session id and renews the session. - * - * @param bool $renew If the session should also be renewed. Defaults to true. - * @return void - */ - public static function clear($renew = true) { - if (!$renew) { - $_SESSION = array(); - return; - } - - $_SESSION = null; - static::$id = null; - static::renew(); - } - -/** - * Helper method to initialize a session, based on CakePHP core settings. - * - * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared. - * - * @return void - * @throws CakeSessionException Throws exceptions when ini_set() fails. - */ - protected static function _configureSession() { - $sessionConfig = Configure::read('Session'); - - if (isset($sessionConfig['defaults'])) { - $defaults = static::_defaultConfig($sessionConfig['defaults']); - if ($defaults) { - $sessionConfig = Hash::merge($defaults, $sessionConfig); - } - } - if (!isset($sessionConfig['ini']['session.cookie_secure']) && env('HTTPS')) { - $sessionConfig['ini']['session.cookie_secure'] = 1; - } - if (isset($sessionConfig['timeout']) && !isset($sessionConfig['cookieTimeout'])) { - $sessionConfig['cookieTimeout'] = $sessionConfig['timeout']; - } - if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) { - $sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60; - } - - if (!isset($sessionConfig['ini']['session.name'])) { - $sessionConfig['ini']['session.name'] = $sessionConfig['cookie']; - } - static::$_cookieName = $sessionConfig['ini']['session.name']; - - if (!empty($sessionConfig['handler'])) { - $sessionConfig['ini']['session.save_handler'] = 'user'; - } elseif (!empty($sessionConfig['session.save_path']) && Configure::read('debug')) { - if (!is_dir($sessionConfig['session.save_path'])) { - mkdir($sessionConfig['session.save_path'], 0775, true); - } - } - - if (!isset($sessionConfig['ini']['session.gc_maxlifetime'])) { - $sessionConfig['ini']['session.gc_maxlifetime'] = $sessionConfig['timeout'] * 60; - } - if (!isset($sessionConfig['ini']['session.cookie_httponly'])) { - $sessionConfig['ini']['session.cookie_httponly'] = 1; - } - // For IE<=8 - if (!isset($sessionConfig['cacheLimiter'])) { - $sessionConfig['cacheLimiter'] = 'must-revalidate'; - } - - if (empty($_SESSION)) { - if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) { - foreach ($sessionConfig['ini'] as $setting => $value) { - if (ini_set($setting, $value) === false) { - throw new CakeSessionException(__d('cake_dev', 'Unable to configure the session, setting %s failed.', $setting)); - } - } - } - } - if (!empty($sessionConfig['handler']) && !isset($sessionConfig['handler']['engine'])) { - call_user_func_array('session_set_save_handler', $sessionConfig['handler']); - } - if (!empty($sessionConfig['handler']['engine'])) { - $handler = static::_getHandler($sessionConfig['handler']['engine']); - session_set_save_handler( - array($handler, 'open'), - array($handler, 'close'), - array($handler, 'read'), - array($handler, 'write'), - array($handler, 'destroy'), - array($handler, 'gc') - ); - } - Configure::write('Session', $sessionConfig); - static::$sessionTime = static::$time + ($sessionConfig['timeout'] * 60); - } - -/** - * Get session cookie name. - * - * @return string - */ - protected static function _cookieName() { - if (static::$_cookieName !== null) { - return static::$_cookieName; - } - - static::init(); - static::_configureSession(); - - return static::$_cookieName = session_name(); - } - -/** - * Returns whether a session exists - * - * @return bool - */ - protected static function _hasSession() { - return static::started() || isset($_COOKIE[static::_cookieName()]) || (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg'); - } - -/** - * Find the handler class and make sure it implements the correct interface. - * - * @param string $handler Handler name. - * @return void - * @throws CakeSessionException - */ - protected static function _getHandler($handler) { - list($plugin, $class) = pluginSplit($handler, true); - App::uses($class, $plugin . 'Model/Datasource/Session'); - if (!class_exists($class)) { - throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class)); - } - $handler = new $class(); - if ($handler instanceof CakeSessionHandlerInterface) { - return $handler; - } - throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); - } - -/** - * Get one of the prebaked default session configurations. - * - * @param string $name Config name. - * @return bool|array - */ - protected static function _defaultConfig($name) { - $defaults = array( - 'php' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'session.cookie_path' => static::$path - ) - ), - 'cake' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.serialize_handler' => 'php', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_path' => TMP . 'sessions', - 'session.save_handler' => 'files' - ) - ), - 'cache' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_handler' => 'user', - ), - 'handler' => array( - 'engine' => 'CacheSession', - 'config' => 'default' - ) - ), - 'database' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_handler' => 'user', - 'session.serialize_handler' => 'php', - ), - 'handler' => array( - 'engine' => 'DatabaseSession', - 'model' => 'Session' - ) - ) - ); - if (isset($defaults[$name])) { - return $defaults[$name]; - } - return false; - } - -/** - * Helper method to start a session - * - * @return bool Success - */ - protected static function _startSession() { - static::init(); - session_write_close(); - static::_configureSession(); - - if (headers_sent()) { - if (empty($_SESSION)) { - $_SESSION = array(); - } - } else { - $limit = Configure::read('Session.cacheLimiter'); - if (!empty($limit)) { - session_cache_limiter($limit); - } - session_start(); - } - return true; - } - -/** - * Helper method to create a new session. - * - * @return void - */ - protected static function _checkValid() { - $config = static::read('Config'); - if ($config) { - $sessionConfig = Configure::read('Session'); - - if (static::valid()) { - static::write('Config.time', static::$sessionTime); - if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { - $check = $config['countdown']; - $check -= 1; - static::write('Config.countdown', $check); - - if ($check < 1) { - static::renew(); - static::write('Config.countdown', static::$requestCountdown); - } - } - } else { - $_SESSION = array(); - static::destroy(); - static::_setError(1, 'Session Highjacking Attempted !!!'); - static::_startSession(); - static::_writeConfig(); - } - } else { - static::_writeConfig(); - } - } - -/** - * Writes configuration variables to the session - * - * @return void - */ - protected static function _writeConfig() { - static::write('Config.userAgent', static::$_userAgent); - static::write('Config.time', static::$sessionTime); - static::write('Config.countdown', static::$requestCountdown); - } - -/** - * Restarts this session. - * - * @return void - */ - public static function renew() { - if (session_id() === '') { - return; - } - if (isset($_COOKIE[static::_cookieName()])) { - setcookie(Configure::read('Session.cookie'), '', time() - 42000, static::$path); - } - if (!headers_sent()) { - session_write_close(); - session_start(); - session_regenerate_id(true); - } - } - -/** - * Helper method to set an internal error message. - * - * @param int $errorNumber Number of the error - * @param string $errorMessage Description of the error - * @return void - */ - protected static function _setError($errorNumber, $errorMessage) { - if (static::$error === false) { - static::$error = array(); - } - static::$error[$errorNumber] = $errorMessage; - static::$lastError = $errorNumber; - } + /** + * True if the Session is still valid + * + * @var bool + */ + public static $valid = false; + + /** + * Error messages for this session + * + * @var array + */ + public static $error = false; + + /** + * User agent string + * + * @var string + */ + protected static $_userAgent = ''; + + /** + * Path to where the session is active. + * + * @var string + */ + public static $path = '/'; + + /** + * Error number of last occurred error + * + * @var int + */ + public static $lastError = null; + + /** + * Start time for this session. + * + * @var int + */ + public static $time = false; + + /** + * Cookie lifetime + * + * @var int + */ + public static $cookieLifeTime; + + /** + * Time when this session becomes invalid. + * + * @var int + */ + public static $sessionTime = false; + + /** + * Current Session id + * + * @var string + */ + public static $id = null; + + /** + * Hostname + * + * @var string + */ + public static $host = null; + + /** + * Session timeout multiplier factor + * + * @var int + */ + public static $timeout = null; + + /** + * Number of requests that can occur during a session time without the session being renewed. + * This feature is only used when config value `Session.autoRegenerate` is set to true. + * + * @var int + * @see CakeSession::_checkValid() + */ + public static $requestCountdown = 10; + + /** + * Whether or not the init function in this class was already called + * + * @var bool + */ + protected static $_initialized = false; + + /** + * Session cookie name + * + * @var string + */ + protected static $_cookieName = null; + + /** + * Whether this session is running under a CLI environment + * + * @var bool + */ + protected static $_isCLI = false; + + /** + * Pseudo constructor. + * + * @param string|null $base The base path for the Session + * @return void + */ + public static function init($base = null) { + static::$time = time(); + + if (env('HTTP_USER_AGENT') && !static::$_userAgent) { + static::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); + } + + static::_setPath($base); + static::_setHost(env('HTTP_HOST')); + + if (!static::$_initialized) { + register_shutdown_function('session_write_close'); + } + + static::$_initialized = true; + static::$_isCLI = (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg'); + } + + /** + * Setup the Path variable + * + * @param string|null $base base path + * @return void + */ + protected static function _setPath($base = null) { + if (empty($base)) { + static::$path = '/'; + return; + } + if (strpos($base, 'index.php') !== false) { + $base = str_replace('index.php', '', $base); + } + if (strpos($base, '?') !== false) { + $base = str_replace('?', '', $base); + } + static::$path = $base; + } + + /** + * Set the host name + * + * @param string $host Hostname + * @return void + */ + protected static function _setHost($host) { + static::$host = $host; + if (strpos(static::$host, ':') !== false) { + static::$host = substr(static::$host, 0, strpos(static::$host, ':')); + } + } + + /** + * Starts the Session. + * + * @return bool True if session was started + */ + public static function start() { + if (static::started()) { + return true; + } + + $id = static::id(); + static::_startSession(); + if (!$id && static::started()) { + static::_checkValid(); + } + + static::$error = false; + static::$valid = true; + return static::started(); + } + + /** + * Determine if Session has been started. + * + * @return bool True if session has been started. + */ + public static function started() { + if (function_exists('session_status')) { + return isset($_SESSION) && (session_status() === PHP_SESSION_ACTIVE); + } + return isset($_SESSION) && session_id(); + } + + /** + * Returns true if given variable is set in session. + * + * @param string $name Variable name to check for + * @return bool True if variable is there + */ + public static function check($name) { + if (!static::_hasSession() || !static::start()) { + return false; + } + if (isset($_SESSION[$name])) { + return true; + } + + return Hash::get($_SESSION, $name) !== null; + } + + /** + * Returns the session id. + * Calling this method will not auto start the session. You might have to manually + * assert a started session. + * + * Passing an id into it, you can also replace the session id if the session + * has not already been started. + * Note that depending on the session handler, not all characters are allowed + * within the session id. For example, the file session handler only allows + * characters in the range a-z A-Z 0-9 , (comma) and - (minus). + * + * @param string|null $id Id to replace the current session id + * @return string Session id + */ + public static function id($id = null) { + if ($id) { + static::$id = $id; + session_id(static::$id); + } + if (static::started()) { + return session_id(); + } + return static::$id; + } + + /** + * Removes a variable from session. + * + * @param string $name Session variable to remove + * @return bool Success + */ + public static function delete($name) { + if (static::check($name)) { + static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); + return !static::check($name); + } + return false; + } + + /** + * Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself. + * + * @param array &$old Set of old variables => values + * @param array $new New set of variable => value + * @return void + */ + protected static function _overwrite(&$old, $new) { + if (!empty($old)) { + foreach ($old as $key => $var) { + if (!isset($new[$key])) { + unset($old[$key]); + } + } + } + foreach ($new as $key => $var) { + $old[$key] = $var; + } + } + + /** + * Return error description for given error number. + * + * @param int $errorNumber Error to set + * @return string Error as string + */ + protected static function _error($errorNumber) { + if (!is_array(static::$error) || !array_key_exists($errorNumber, static::$error)) { + return false; + } + return static::$error[$errorNumber]; + } + + /** + * Returns last occurred error as a string, if any. + * + * @return mixed Error description as a string, or false. + */ + public static function error() { + if (static::$lastError) { + return static::_error(static::$lastError); + } + return false; + } + + /** + * Returns true if session is valid. + * + * @return bool Success + */ + public static function valid() { + if (static::start() && static::read('Config')) { + if (static::_validAgentAndTime() && static::$error === false) { + static::$valid = true; + } else { + static::$valid = false; + static::_setError(1, 'Session Highjacking Attempted !!!'); + } + } + return static::$valid; + } + + /** + * Tests that the user agent is valid and that the session hasn't 'timed out'. + * Since timeouts are implemented in CakeSession it checks the current static::$time + * against the time the session is set to expire. The User agent is only checked + * if Session.checkAgent == true. + * + * @return bool + */ + protected static function _validAgentAndTime() { + $userAgent = static::read('Config.userAgent'); + $time = static::read('Config.time'); + $validAgent = ( + Configure::read('Session.checkAgent') === false || + isset($userAgent) && static::$_userAgent === $userAgent + ); + return ($validAgent && static::$time <= $time); + } + + /** + * Get / Set the user agent + * + * @param string|null $userAgent Set the user agent + * @return string Current user agent. + */ + public static function userAgent($userAgent = null) { + if ($userAgent) { + static::$_userAgent = $userAgent; + } + if (empty(static::$_userAgent)) { + CakeSession::init(static::$path); + } + return static::$_userAgent; + } + + /** + * Returns given session variable, or all of them, if no parameters given. + * + * @param string|null $name The name of the session variable (or a path as sent to Set.extract) + * @return mixed The value of the session variable, null if session not available, + * session not started, or provided name not found in the session, false on failure. + */ + public static function read($name = null) { + if (!static::_hasSession() || !static::start()) { + return null; + } + if ($name === null) { + return static::_returnSessionVars(); + } + $result = Hash::get($_SESSION, $name); + + if (isset($result)) { + return $result; + } + return null; + } + + /** + * Returns all session variables. + * + * @return mixed Full $_SESSION array, or false on error. + */ + protected static function _returnSessionVars() { + if (!empty($_SESSION)) { + return $_SESSION; + } + static::_setError(2, 'No Session vars set'); + return false; + } + + /** + * Writes value to given session variable name. + * + * @param string|array $name Name of variable + * @param string $value Value to write + * @return bool True if the write was successful, false if the write failed + */ + public static function write($name, $value = null) { + if (!static::start()) { + return false; + } + + $write = $name; + if (!is_array($name)) { + $write = array($name => $value); + } + foreach ($write as $key => $val) { + static::_overwrite($_SESSION, Hash::insert($_SESSION, $key, $val)); + if (Hash::get($_SESSION, $key) !== $val) { + return false; + } + } + return true; + } + + /** + * Reads and deletes a variable from session. + * + * @param string $name The key to read and remove (or a path as sent to Hash.extract). + * @return mixed The value of the session variable, null if session not available, + * session not started, or provided name not found in the session. + */ + public static function consume($name) { + if (empty($name)) { + return null; + } + $value = static::read($name); + if ($value !== null) { + static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); + } + return $value; + } + + /** + * Helper method to destroy invalid sessions. + * + * @return void + */ + public static function destroy() { + if (!static::started()) { + static::_startSession(); + } + + if (static::started()) { + if (session_id() && static::_hasSession()) { + session_write_close(); + session_start(); + } + session_destroy(); + unset($_COOKIE[static::_cookieName()]); + } + + $_SESSION = null; + static::$id = null; + static::$_cookieName = null; + } + + /** + * Clears the session. + * + * Optionally also clears the session id and renews the session. + * + * @param bool $renew If the session should also be renewed. Defaults to true. + * @return void + */ + public static function clear($renew = true) { + if (!$renew) { + $_SESSION = array(); + return; + } + + $_SESSION = null; + static::$id = null; + static::renew(); + } + + /** + * Helper method to initialize a session, based on CakePHP core settings. + * + * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared. + * + * @return void + * @throws CakeSessionException Throws exceptions when ini_set() fails. + */ + protected static function _configureSession() { + $sessionConfig = Configure::read('Session'); + + if (isset($sessionConfig['defaults'])) { + $defaults = static::_defaultConfig($sessionConfig['defaults']); + if ($defaults) { + $sessionConfig = Hash::merge($defaults, $sessionConfig); + } + } + if (!isset($sessionConfig['ini']['session.cookie_secure']) && env('HTTPS')) { + $sessionConfig['ini']['session.cookie_secure'] = 1; + } + if (isset($sessionConfig['timeout']) && !isset($sessionConfig['cookieTimeout'])) { + $sessionConfig['cookieTimeout'] = $sessionConfig['timeout']; + } + if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) { + $sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60; + } + + if (!isset($sessionConfig['ini']['session.name'])) { + $sessionConfig['ini']['session.name'] = $sessionConfig['cookie']; + } + static::$_cookieName = $sessionConfig['ini']['session.name']; + + if (!empty($sessionConfig['handler'])) { + $sessionConfig['ini']['session.save_handler'] = 'user'; + } elseif (!empty($sessionConfig['session.save_path']) && Configure::read('debug')) { + if (!is_dir($sessionConfig['session.save_path'])) { + mkdir($sessionConfig['session.save_path'], 0775, true); + } + } + + if (!isset($sessionConfig['ini']['session.gc_maxlifetime'])) { + $sessionConfig['ini']['session.gc_maxlifetime'] = $sessionConfig['timeout'] * 60; + } + if (!isset($sessionConfig['ini']['session.cookie_httponly'])) { + $sessionConfig['ini']['session.cookie_httponly'] = 1; + } + // For IE<=8 + if (!isset($sessionConfig['cacheLimiter'])) { + $sessionConfig['cacheLimiter'] = 'must-revalidate'; + } + + if (empty($_SESSION)) { + if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) { + foreach ($sessionConfig['ini'] as $setting => $value) { + if (ini_set($setting, $value) === false) { + throw new CakeSessionException(__d('cake_dev', 'Unable to configure the session, setting %s failed.', $setting)); + } + } + } + } + if (!empty($sessionConfig['handler']) && !isset($sessionConfig['handler']['engine'])) { + call_user_func_array('session_set_save_handler', $sessionConfig['handler']); + } + if (!empty($sessionConfig['handler']['engine'])) { + $handler = static::_getHandler($sessionConfig['handler']['engine']); + session_set_save_handler( + array($handler, 'open'), + array($handler, 'close'), + array($handler, 'read'), + array($handler, 'write'), + array($handler, 'destroy'), + array($handler, 'gc') + ); + } + Configure::write('Session', $sessionConfig); + static::$sessionTime = static::$time + ($sessionConfig['timeout'] * 60); + } + + /** + * Get session cookie name. + * + * @return string + */ + protected static function _cookieName() { + if (static::$_cookieName !== null) { + return static::$_cookieName; + } + + static::init(); + static::_configureSession(); + + return static::$_cookieName = session_name(); + } + + /** + * Returns whether a session exists + * + * @return bool + */ + protected static function _hasSession() { + return static::started() + || !ini_get('session.use_cookies') + || isset($_COOKIE[static::_cookieName()]) + || static::$_isCLI + || (ini_get('session.use_trans_sid') && isset($_GET[session_name()])); + } + + /** + * Find the handler class and make sure it implements the correct interface. + * + * @param string $handler Handler name. + * @return CakeSessionHandlerInterface + * @throws CakeSessionException + */ + protected static function _getHandler($handler) { + list($plugin, $class) = pluginSplit($handler, true); + App::uses($class, $plugin . 'Model/Datasource/Session'); + if (!class_exists($class)) { + throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class)); + } + $handler = new $class(); + if ($handler instanceof CakeSessionHandlerInterface) { + return $handler; + } + throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); + } + + /** + * Get one of the prebaked default session configurations. + * + * @param string $name Config name. + * @return bool|array + */ + protected static function _defaultConfig($name) { + $defaults = array( + 'php' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'session.cookie_path' => static::$path + ) + ), + 'cake' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.serialize_handler' => 'php', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_path' => TMP . 'sessions', + 'session.save_handler' => 'files' + ) + ), + 'cache' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_handler' => 'user', + ), + 'handler' => array( + 'engine' => 'CacheSession', + 'config' => 'default' + ) + ), + 'database' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_handler' => 'user', + 'session.serialize_handler' => 'php', + ), + 'handler' => array( + 'engine' => 'DatabaseSession', + 'model' => 'Session' + ) + ) + ); + if (isset($defaults[$name])) { + return $defaults[$name]; + } + return false; + } + + /** + * Helper method to start a session + * + * @return bool Success + */ + protected static function _startSession() { + static::init(); + session_write_close(); + static::_configureSession(); + + if (headers_sent()) { + if (empty($_SESSION)) { + $_SESSION = array(); + } + } else { + $limit = Configure::read('Session.cacheLimiter'); + if (!empty($limit)) { + session_cache_limiter($limit); + } + session_start(); + } + return true; + } + + /** + * Helper method to create a new session. + * + * @return void + */ + protected static function _checkValid() { + $config = static::read('Config'); + if ($config) { + $sessionConfig = Configure::read('Session'); + + if (static::valid()) { + static::write('Config.time', static::$sessionTime); + if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { + $check = $config['countdown']; + $check -= 1; + static::write('Config.countdown', $check); + + if ($check < 1) { + static::renew(); + static::write('Config.countdown', static::$requestCountdown); + } + } + } else { + $_SESSION = array(); + static::destroy(); + static::_setError(1, 'Session Highjacking Attempted !!!'); + static::_startSession(); + static::_writeConfig(); + } + } else { + static::_writeConfig(); + } + } + + /** + * Writes configuration variables to the session + * + * @return void + */ + protected static function _writeConfig() { + static::write('Config.userAgent', static::$_userAgent); + static::write('Config.time', static::$sessionTime); + static::write('Config.countdown', static::$requestCountdown); + } + + /** + * Restarts this session. + * + * @return void + */ + public static function renew() { + if (session_id() === '') { + return; + } + if (isset($_COOKIE[static::_cookieName()])) { + setcookie(Configure::read('Session.cookie'), '', time() - 42000, static::$path); + } + if (!headers_sent()) { + session_write_close(); + session_start(); + session_regenerate_id(true); + } + } + + /** + * Helper method to set an internal error message. + * + * @param int $errorNumber Number of the error + * @param string $errorMessage Description of the error + * @return void + */ + protected static function _setError($errorNumber, $errorMessage) { + if (static::$error === false) { + static::$error = array(); + } + static::$error[$errorNumber] = $errorMessage; + static::$lastError = $errorNumber; + } } From 7f64ea37f96b9ace5a0cb8c97832963c50b21ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20Wei=C3=9F?= Date: Fri, 6 Oct 2017 17:11:09 +0200 Subject: [PATCH 30/44] Restored formatting --- lib/Cake/Model/Datasource/CakeSession.php | 1520 ++++++++++----------- 1 file changed, 760 insertions(+), 760 deletions(-) diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index 3fb00a46eab..4f4f7e97a74 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -34,771 +34,771 @@ */ class CakeSession { - /** - * True if the Session is still valid - * - * @var bool - */ - public static $valid = false; - - /** - * Error messages for this session - * - * @var array - */ - public static $error = false; - - /** - * User agent string - * - * @var string - */ - protected static $_userAgent = ''; - - /** - * Path to where the session is active. - * - * @var string - */ - public static $path = '/'; - - /** - * Error number of last occurred error - * - * @var int - */ - public static $lastError = null; - - /** - * Start time for this session. - * - * @var int - */ - public static $time = false; - - /** - * Cookie lifetime - * - * @var int - */ - public static $cookieLifeTime; - - /** - * Time when this session becomes invalid. - * - * @var int - */ - public static $sessionTime = false; - - /** - * Current Session id - * - * @var string - */ - public static $id = null; - - /** - * Hostname - * - * @var string - */ - public static $host = null; - - /** - * Session timeout multiplier factor - * - * @var int - */ - public static $timeout = null; - - /** - * Number of requests that can occur during a session time without the session being renewed. - * This feature is only used when config value `Session.autoRegenerate` is set to true. - * - * @var int - * @see CakeSession::_checkValid() - */ - public static $requestCountdown = 10; - - /** - * Whether or not the init function in this class was already called - * - * @var bool - */ - protected static $_initialized = false; - - /** - * Session cookie name - * - * @var string - */ - protected static $_cookieName = null; - - /** - * Whether this session is running under a CLI environment - * - * @var bool - */ +/** + * True if the Session is still valid + * + * @var bool + */ + public static $valid = false; + +/** + * Error messages for this session + * + * @var array + */ + public static $error = false; + +/** + * User agent string + * + * @var string + */ + protected static $_userAgent = ''; + +/** + * Path to where the session is active. + * + * @var string + */ + public static $path = '/'; + +/** + * Error number of last occurred error + * + * @var int + */ + public static $lastError = null; + +/** + * Start time for this session. + * + * @var int + */ + public static $time = false; + +/** + * Cookie lifetime + * + * @var int + */ + public static $cookieLifeTime; + +/** + * Time when this session becomes invalid. + * + * @var int + */ + public static $sessionTime = false; + +/** + * Current Session id + * + * @var string + */ + public static $id = null; + +/** + * Hostname + * + * @var string + */ + public static $host = null; + +/** + * Session timeout multiplier factor + * + * @var int + */ + public static $timeout = null; + +/** + * Number of requests that can occur during a session time without the session being renewed. + * This feature is only used when config value `Session.autoRegenerate` is set to true. + * + * @var int + * @see CakeSession::_checkValid() + */ + public static $requestCountdown = 10; + +/** + * Whether or not the init function in this class was already called + * + * @var bool + */ + protected static $_initialized = false; + +/** + * Session cookie name + * + * @var string + */ + protected static $_cookieName = null; + +/** + * Whether this session is running under a CLI environment + * + * @var bool + */ protected static $_isCLI = false; - /** - * Pseudo constructor. - * - * @param string|null $base The base path for the Session - * @return void - */ - public static function init($base = null) { - static::$time = time(); - - if (env('HTTP_USER_AGENT') && !static::$_userAgent) { - static::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); - } - - static::_setPath($base); - static::_setHost(env('HTTP_HOST')); - - if (!static::$_initialized) { - register_shutdown_function('session_write_close'); - } - - static::$_initialized = true; - static::$_isCLI = (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg'); - } - - /** - * Setup the Path variable - * - * @param string|null $base base path - * @return void - */ - protected static function _setPath($base = null) { - if (empty($base)) { - static::$path = '/'; - return; - } - if (strpos($base, 'index.php') !== false) { - $base = str_replace('index.php', '', $base); - } - if (strpos($base, '?') !== false) { - $base = str_replace('?', '', $base); - } - static::$path = $base; - } - - /** - * Set the host name - * - * @param string $host Hostname - * @return void - */ - protected static function _setHost($host) { - static::$host = $host; - if (strpos(static::$host, ':') !== false) { - static::$host = substr(static::$host, 0, strpos(static::$host, ':')); - } - } - - /** - * Starts the Session. - * - * @return bool True if session was started - */ - public static function start() { - if (static::started()) { - return true; - } - - $id = static::id(); - static::_startSession(); - if (!$id && static::started()) { - static::_checkValid(); - } - - static::$error = false; - static::$valid = true; - return static::started(); - } - - /** - * Determine if Session has been started. - * - * @return bool True if session has been started. - */ - public static function started() { - if (function_exists('session_status')) { - return isset($_SESSION) && (session_status() === PHP_SESSION_ACTIVE); - } - return isset($_SESSION) && session_id(); - } - - /** - * Returns true if given variable is set in session. - * - * @param string $name Variable name to check for - * @return bool True if variable is there - */ - public static function check($name) { - if (!static::_hasSession() || !static::start()) { - return false; - } - if (isset($_SESSION[$name])) { - return true; - } - - return Hash::get($_SESSION, $name) !== null; - } - - /** - * Returns the session id. - * Calling this method will not auto start the session. You might have to manually - * assert a started session. - * - * Passing an id into it, you can also replace the session id if the session - * has not already been started. - * Note that depending on the session handler, not all characters are allowed - * within the session id. For example, the file session handler only allows - * characters in the range a-z A-Z 0-9 , (comma) and - (minus). - * - * @param string|null $id Id to replace the current session id - * @return string Session id - */ - public static function id($id = null) { - if ($id) { - static::$id = $id; - session_id(static::$id); - } - if (static::started()) { - return session_id(); - } - return static::$id; - } - - /** - * Removes a variable from session. - * - * @param string $name Session variable to remove - * @return bool Success - */ - public static function delete($name) { - if (static::check($name)) { - static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); - return !static::check($name); - } - return false; - } - - /** - * Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself. - * - * @param array &$old Set of old variables => values - * @param array $new New set of variable => value - * @return void - */ - protected static function _overwrite(&$old, $new) { - if (!empty($old)) { - foreach ($old as $key => $var) { - if (!isset($new[$key])) { - unset($old[$key]); - } - } - } - foreach ($new as $key => $var) { - $old[$key] = $var; - } - } - - /** - * Return error description for given error number. - * - * @param int $errorNumber Error to set - * @return string Error as string - */ - protected static function _error($errorNumber) { - if (!is_array(static::$error) || !array_key_exists($errorNumber, static::$error)) { - return false; - } - return static::$error[$errorNumber]; - } - - /** - * Returns last occurred error as a string, if any. - * - * @return mixed Error description as a string, or false. - */ - public static function error() { - if (static::$lastError) { - return static::_error(static::$lastError); - } - return false; - } - - /** - * Returns true if session is valid. - * - * @return bool Success - */ - public static function valid() { - if (static::start() && static::read('Config')) { - if (static::_validAgentAndTime() && static::$error === false) { - static::$valid = true; - } else { - static::$valid = false; - static::_setError(1, 'Session Highjacking Attempted !!!'); - } - } - return static::$valid; - } - - /** - * Tests that the user agent is valid and that the session hasn't 'timed out'. - * Since timeouts are implemented in CakeSession it checks the current static::$time - * against the time the session is set to expire. The User agent is only checked - * if Session.checkAgent == true. - * - * @return bool - */ - protected static function _validAgentAndTime() { - $userAgent = static::read('Config.userAgent'); - $time = static::read('Config.time'); - $validAgent = ( - Configure::read('Session.checkAgent') === false || - isset($userAgent) && static::$_userAgent === $userAgent - ); - return ($validAgent && static::$time <= $time); - } - - /** - * Get / Set the user agent - * - * @param string|null $userAgent Set the user agent - * @return string Current user agent. - */ - public static function userAgent($userAgent = null) { - if ($userAgent) { - static::$_userAgent = $userAgent; - } - if (empty(static::$_userAgent)) { - CakeSession::init(static::$path); - } - return static::$_userAgent; - } - - /** - * Returns given session variable, or all of them, if no parameters given. - * - * @param string|null $name The name of the session variable (or a path as sent to Set.extract) - * @return mixed The value of the session variable, null if session not available, - * session not started, or provided name not found in the session, false on failure. - */ - public static function read($name = null) { - if (!static::_hasSession() || !static::start()) { - return null; - } - if ($name === null) { - return static::_returnSessionVars(); - } - $result = Hash::get($_SESSION, $name); - - if (isset($result)) { - return $result; - } - return null; - } - - /** - * Returns all session variables. - * - * @return mixed Full $_SESSION array, or false on error. - */ - protected static function _returnSessionVars() { - if (!empty($_SESSION)) { - return $_SESSION; - } - static::_setError(2, 'No Session vars set'); - return false; - } - - /** - * Writes value to given session variable name. - * - * @param string|array $name Name of variable - * @param string $value Value to write - * @return bool True if the write was successful, false if the write failed - */ - public static function write($name, $value = null) { - if (!static::start()) { - return false; - } - - $write = $name; - if (!is_array($name)) { - $write = array($name => $value); - } - foreach ($write as $key => $val) { - static::_overwrite($_SESSION, Hash::insert($_SESSION, $key, $val)); - if (Hash::get($_SESSION, $key) !== $val) { - return false; - } - } - return true; - } - - /** - * Reads and deletes a variable from session. - * - * @param string $name The key to read and remove (or a path as sent to Hash.extract). - * @return mixed The value of the session variable, null if session not available, - * session not started, or provided name not found in the session. - */ - public static function consume($name) { - if (empty($name)) { - return null; - } - $value = static::read($name); - if ($value !== null) { - static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); - } - return $value; - } - - /** - * Helper method to destroy invalid sessions. - * - * @return void - */ - public static function destroy() { - if (!static::started()) { - static::_startSession(); - } - - if (static::started()) { - if (session_id() && static::_hasSession()) { - session_write_close(); - session_start(); - } - session_destroy(); - unset($_COOKIE[static::_cookieName()]); - } - - $_SESSION = null; - static::$id = null; - static::$_cookieName = null; - } - - /** - * Clears the session. - * - * Optionally also clears the session id and renews the session. - * - * @param bool $renew If the session should also be renewed. Defaults to true. - * @return void - */ - public static function clear($renew = true) { - if (!$renew) { - $_SESSION = array(); - return; - } - - $_SESSION = null; - static::$id = null; - static::renew(); - } - - /** - * Helper method to initialize a session, based on CakePHP core settings. - * - * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared. - * - * @return void - * @throws CakeSessionException Throws exceptions when ini_set() fails. - */ - protected static function _configureSession() { - $sessionConfig = Configure::read('Session'); - - if (isset($sessionConfig['defaults'])) { - $defaults = static::_defaultConfig($sessionConfig['defaults']); - if ($defaults) { - $sessionConfig = Hash::merge($defaults, $sessionConfig); - } - } - if (!isset($sessionConfig['ini']['session.cookie_secure']) && env('HTTPS')) { - $sessionConfig['ini']['session.cookie_secure'] = 1; - } - if (isset($sessionConfig['timeout']) && !isset($sessionConfig['cookieTimeout'])) { - $sessionConfig['cookieTimeout'] = $sessionConfig['timeout']; - } - if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) { - $sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60; - } - - if (!isset($sessionConfig['ini']['session.name'])) { - $sessionConfig['ini']['session.name'] = $sessionConfig['cookie']; - } - static::$_cookieName = $sessionConfig['ini']['session.name']; - - if (!empty($sessionConfig['handler'])) { - $sessionConfig['ini']['session.save_handler'] = 'user'; - } elseif (!empty($sessionConfig['session.save_path']) && Configure::read('debug')) { - if (!is_dir($sessionConfig['session.save_path'])) { - mkdir($sessionConfig['session.save_path'], 0775, true); - } - } - - if (!isset($sessionConfig['ini']['session.gc_maxlifetime'])) { - $sessionConfig['ini']['session.gc_maxlifetime'] = $sessionConfig['timeout'] * 60; - } - if (!isset($sessionConfig['ini']['session.cookie_httponly'])) { - $sessionConfig['ini']['session.cookie_httponly'] = 1; - } - // For IE<=8 - if (!isset($sessionConfig['cacheLimiter'])) { - $sessionConfig['cacheLimiter'] = 'must-revalidate'; - } - - if (empty($_SESSION)) { - if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) { - foreach ($sessionConfig['ini'] as $setting => $value) { - if (ini_set($setting, $value) === false) { - throw new CakeSessionException(__d('cake_dev', 'Unable to configure the session, setting %s failed.', $setting)); - } - } - } - } - if (!empty($sessionConfig['handler']) && !isset($sessionConfig['handler']['engine'])) { - call_user_func_array('session_set_save_handler', $sessionConfig['handler']); - } - if (!empty($sessionConfig['handler']['engine'])) { - $handler = static::_getHandler($sessionConfig['handler']['engine']); - session_set_save_handler( - array($handler, 'open'), - array($handler, 'close'), - array($handler, 'read'), - array($handler, 'write'), - array($handler, 'destroy'), - array($handler, 'gc') - ); - } - Configure::write('Session', $sessionConfig); - static::$sessionTime = static::$time + ($sessionConfig['timeout'] * 60); - } - - /** - * Get session cookie name. - * - * @return string - */ - protected static function _cookieName() { - if (static::$_cookieName !== null) { - return static::$_cookieName; - } - - static::init(); - static::_configureSession(); - - return static::$_cookieName = session_name(); - } - - /** - * Returns whether a session exists - * - * @return bool - */ - protected static function _hasSession() { - return static::started() +/** + * Pseudo constructor. + * + * @param string|null $base The base path for the Session + * @return void + */ + public static function init($base = null) { + static::$time = time(); + + if (env('HTTP_USER_AGENT') && !static::$_userAgent) { + static::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); + } + + static::_setPath($base); + static::_setHost(env('HTTP_HOST')); + + if (!static::$_initialized) { + register_shutdown_function('session_write_close'); + } + + static::$_initialized = true; + static::$_isCLI = (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg'); + } + +/** + * Setup the Path variable + * + * @param string|null $base base path + * @return void + */ + protected static function _setPath($base = null) { + if (empty($base)) { + static::$path = '/'; + return; + } + if (strpos($base, 'index.php') !== false) { + $base = str_replace('index.php', '', $base); + } + if (strpos($base, '?') !== false) { + $base = str_replace('?', '', $base); + } + static::$path = $base; + } + +/** + * Set the host name + * + * @param string $host Hostname + * @return void + */ + protected static function _setHost($host) { + static::$host = $host; + if (strpos(static::$host, ':') !== false) { + static::$host = substr(static::$host, 0, strpos(static::$host, ':')); + } + } + +/** + * Starts the Session. + * + * @return bool True if session was started + */ + public static function start() { + if (static::started()) { + return true; + } + + $id = static::id(); + static::_startSession(); + if (!$id && static::started()) { + static::_checkValid(); + } + + static::$error = false; + static::$valid = true; + return static::started(); + } + +/** + * Determine if Session has been started. + * + * @return bool True if session has been started. + */ + public static function started() { + if (function_exists('session_status')) { + return isset($_SESSION) && (session_status() === PHP_SESSION_ACTIVE); + } + return isset($_SESSION) && session_id(); + } + +/** + * Returns true if given variable is set in session. + * + * @param string $name Variable name to check for + * @return bool True if variable is there + */ + public static function check($name) { + if (!static::_hasSession() || !static::start()) { + return false; + } + if (isset($_SESSION[$name])) { + return true; + } + + return Hash::get($_SESSION, $name) !== null; + } + +/** + * Returns the session id. + * Calling this method will not auto start the session. You might have to manually + * assert a started session. + * + * Passing an id into it, you can also replace the session id if the session + * has not already been started. + * Note that depending on the session handler, not all characters are allowed + * within the session id. For example, the file session handler only allows + * characters in the range a-z A-Z 0-9 , (comma) and - (minus). + * + * @param string|null $id Id to replace the current session id + * @return string Session id + */ + public static function id($id = null) { + if ($id) { + static::$id = $id; + session_id(static::$id); + } + if (static::started()) { + return session_id(); + } + return static::$id; + } + +/** + * Removes a variable from session. + * + * @param string $name Session variable to remove + * @return bool Success + */ + public static function delete($name) { + if (static::check($name)) { + static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); + return !static::check($name); + } + return false; + } + +/** + * Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself. + * + * @param array &$old Set of old variables => values + * @param array $new New set of variable => value + * @return void + */ + protected static function _overwrite(&$old, $new) { + if (!empty($old)) { + foreach ($old as $key => $var) { + if (!isset($new[$key])) { + unset($old[$key]); + } + } + } + foreach ($new as $key => $var) { + $old[$key] = $var; + } + } + +/** + * Return error description for given error number. + * + * @param int $errorNumber Error to set + * @return string Error as string + */ + protected static function _error($errorNumber) { + if (!is_array(static::$error) || !array_key_exists($errorNumber, static::$error)) { + return false; + } + return static::$error[$errorNumber]; + } + +/** + * Returns last occurred error as a string, if any. + * + * @return mixed Error description as a string, or false. + */ + public static function error() { + if (static::$lastError) { + return static::_error(static::$lastError); + } + return false; + } + +/** + * Returns true if session is valid. + * + * @return bool Success + */ + public static function valid() { + if (static::start() && static::read('Config')) { + if (static::_validAgentAndTime() && static::$error === false) { + static::$valid = true; + } else { + static::$valid = false; + static::_setError(1, 'Session Highjacking Attempted !!!'); + } + } + return static::$valid; + } + +/** + * Tests that the user agent is valid and that the session hasn't 'timed out'. + * Since timeouts are implemented in CakeSession it checks the current static::$time + * against the time the session is set to expire. The User agent is only checked + * if Session.checkAgent == true. + * + * @return bool + */ + protected static function _validAgentAndTime() { + $userAgent = static::read('Config.userAgent'); + $time = static::read('Config.time'); + $validAgent = ( + Configure::read('Session.checkAgent') === false || + isset($userAgent) && static::$_userAgent === $userAgent + ); + return ($validAgent && static::$time <= $time); + } + +/** + * Get / Set the user agent + * + * @param string|null $userAgent Set the user agent + * @return string Current user agent. + */ + public static function userAgent($userAgent = null) { + if ($userAgent) { + static::$_userAgent = $userAgent; + } + if (empty(static::$_userAgent)) { + CakeSession::init(static::$path); + } + return static::$_userAgent; + } + +/** + * Returns given session variable, or all of them, if no parameters given. + * + * @param string|null $name The name of the session variable (or a path as sent to Set.extract) + * @return mixed The value of the session variable, null if session not available, + * session not started, or provided name not found in the session, false on failure. + */ + public static function read($name = null) { + if (!static::_hasSession() || !static::start()) { + return null; + } + if ($name === null) { + return static::_returnSessionVars(); + } + $result = Hash::get($_SESSION, $name); + + if (isset($result)) { + return $result; + } + return null; + } + +/** + * Returns all session variables. + * + * @return mixed Full $_SESSION array, or false on error. + */ + protected static function _returnSessionVars() { + if (!empty($_SESSION)) { + return $_SESSION; + } + static::_setError(2, 'No Session vars set'); + return false; + } + +/** + * Writes value to given session variable name. + * + * @param string|array $name Name of variable + * @param string $value Value to write + * @return bool True if the write was successful, false if the write failed + */ + public static function write($name, $value = null) { + if (!static::start()) { + return false; + } + + $write = $name; + if (!is_array($name)) { + $write = array($name => $value); + } + foreach ($write as $key => $val) { + static::_overwrite($_SESSION, Hash::insert($_SESSION, $key, $val)); + if (Hash::get($_SESSION, $key) !== $val) { + return false; + } + } + return true; + } + +/** + * Reads and deletes a variable from session. + * + * @param string $name The key to read and remove (or a path as sent to Hash.extract). + * @return mixed The value of the session variable, null if session not available, + * session not started, or provided name not found in the session. + */ + public static function consume($name) { + if (empty($name)) { + return null; + } + $value = static::read($name); + if ($value !== null) { + static::_overwrite($_SESSION, Hash::remove($_SESSION, $name)); + } + return $value; + } + +/** + * Helper method to destroy invalid sessions. + * + * @return void + */ + public static function destroy() { + if (!static::started()) { + static::_startSession(); + } + + if (static::started()) { + if (session_id() && static::_hasSession()) { + session_write_close(); + session_start(); + } + session_destroy(); + unset($_COOKIE[static::_cookieName()]); + } + + $_SESSION = null; + static::$id = null; + static::$_cookieName = null; + } + +/** + * Clears the session. + * + * Optionally also clears the session id and renews the session. + * + * @param bool $renew If the session should also be renewed. Defaults to true. + * @return void + */ + public static function clear($renew = true) { + if (!$renew) { + $_SESSION = array(); + return; + } + + $_SESSION = null; + static::$id = null; + static::renew(); + } + +/** + * Helper method to initialize a session, based on CakePHP core settings. + * + * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared. + * + * @return void + * @throws CakeSessionException Throws exceptions when ini_set() fails. + */ + protected static function _configureSession() { + $sessionConfig = Configure::read('Session'); + + if (isset($sessionConfig['defaults'])) { + $defaults = static::_defaultConfig($sessionConfig['defaults']); + if ($defaults) { + $sessionConfig = Hash::merge($defaults, $sessionConfig); + } + } + if (!isset($sessionConfig['ini']['session.cookie_secure']) && env('HTTPS')) { + $sessionConfig['ini']['session.cookie_secure'] = 1; + } + if (isset($sessionConfig['timeout']) && !isset($sessionConfig['cookieTimeout'])) { + $sessionConfig['cookieTimeout'] = $sessionConfig['timeout']; + } + if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) { + $sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60; + } + + if (!isset($sessionConfig['ini']['session.name'])) { + $sessionConfig['ini']['session.name'] = $sessionConfig['cookie']; + } + static::$_cookieName = $sessionConfig['ini']['session.name']; + + if (!empty($sessionConfig['handler'])) { + $sessionConfig['ini']['session.save_handler'] = 'user'; + } elseif (!empty($sessionConfig['session.save_path']) && Configure::read('debug')) { + if (!is_dir($sessionConfig['session.save_path'])) { + mkdir($sessionConfig['session.save_path'], 0775, true); + } + } + + if (!isset($sessionConfig['ini']['session.gc_maxlifetime'])) { + $sessionConfig['ini']['session.gc_maxlifetime'] = $sessionConfig['timeout'] * 60; + } + if (!isset($sessionConfig['ini']['session.cookie_httponly'])) { + $sessionConfig['ini']['session.cookie_httponly'] = 1; + } + // For IE<=8 + if (!isset($sessionConfig['cacheLimiter'])) { + $sessionConfig['cacheLimiter'] = 'must-revalidate'; + } + + if (empty($_SESSION)) { + if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) { + foreach ($sessionConfig['ini'] as $setting => $value) { + if (ini_set($setting, $value) === false) { + throw new CakeSessionException(__d('cake_dev', 'Unable to configure the session, setting %s failed.', $setting)); + } + } + } + } + if (!empty($sessionConfig['handler']) && !isset($sessionConfig['handler']['engine'])) { + call_user_func_array('session_set_save_handler', $sessionConfig['handler']); + } + if (!empty($sessionConfig['handler']['engine'])) { + $handler = static::_getHandler($sessionConfig['handler']['engine']); + session_set_save_handler( + array($handler, 'open'), + array($handler, 'close'), + array($handler, 'read'), + array($handler, 'write'), + array($handler, 'destroy'), + array($handler, 'gc') + ); + } + Configure::write('Session', $sessionConfig); + static::$sessionTime = static::$time + ($sessionConfig['timeout'] * 60); + } + +/** + * Get session cookie name. + * + * @return string + */ + protected static function _cookieName() { + if (static::$_cookieName !== null) { + return static::$_cookieName; + } + + static::init(); + static::_configureSession(); + + return static::$_cookieName = session_name(); + } + +/** + * Returns whether a session exists + * + * @return bool + */ + protected static function _hasSession() { + return static::started() || !ini_get('session.use_cookies') || isset($_COOKIE[static::_cookieName()]) || static::$_isCLI || (ini_get('session.use_trans_sid') && isset($_GET[session_name()])); - } - - /** - * Find the handler class and make sure it implements the correct interface. - * - * @param string $handler Handler name. - * @return CakeSessionHandlerInterface - * @throws CakeSessionException - */ - protected static function _getHandler($handler) { - list($plugin, $class) = pluginSplit($handler, true); - App::uses($class, $plugin . 'Model/Datasource/Session'); - if (!class_exists($class)) { - throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class)); - } - $handler = new $class(); - if ($handler instanceof CakeSessionHandlerInterface) { - return $handler; - } - throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); - } - - /** - * Get one of the prebaked default session configurations. - * - * @param string $name Config name. - * @return bool|array - */ - protected static function _defaultConfig($name) { - $defaults = array( - 'php' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'session.cookie_path' => static::$path - ) - ), - 'cake' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.serialize_handler' => 'php', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_path' => TMP . 'sessions', - 'session.save_handler' => 'files' - ) - ), - 'cache' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_handler' => 'user', - ), - 'handler' => array( - 'engine' => 'CacheSession', - 'config' => 'default' - ) - ), - 'database' => array( - 'cookie' => 'CAKEPHP', - 'timeout' => 240, - 'ini' => array( - 'session.use_trans_sid' => 0, - 'url_rewriter.tags' => '', - 'session.use_cookies' => 1, - 'session.cookie_path' => static::$path, - 'session.save_handler' => 'user', - 'session.serialize_handler' => 'php', - ), - 'handler' => array( - 'engine' => 'DatabaseSession', - 'model' => 'Session' - ) - ) - ); - if (isset($defaults[$name])) { - return $defaults[$name]; - } - return false; - } - - /** - * Helper method to start a session - * - * @return bool Success - */ - protected static function _startSession() { - static::init(); - session_write_close(); - static::_configureSession(); - - if (headers_sent()) { - if (empty($_SESSION)) { - $_SESSION = array(); - } - } else { - $limit = Configure::read('Session.cacheLimiter'); - if (!empty($limit)) { - session_cache_limiter($limit); - } - session_start(); - } - return true; - } - - /** - * Helper method to create a new session. - * - * @return void - */ - protected static function _checkValid() { - $config = static::read('Config'); - if ($config) { - $sessionConfig = Configure::read('Session'); - - if (static::valid()) { - static::write('Config.time', static::$sessionTime); - if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { - $check = $config['countdown']; - $check -= 1; - static::write('Config.countdown', $check); - - if ($check < 1) { - static::renew(); - static::write('Config.countdown', static::$requestCountdown); - } - } - } else { - $_SESSION = array(); - static::destroy(); - static::_setError(1, 'Session Highjacking Attempted !!!'); - static::_startSession(); - static::_writeConfig(); - } - } else { - static::_writeConfig(); - } - } - - /** - * Writes configuration variables to the session - * - * @return void - */ - protected static function _writeConfig() { - static::write('Config.userAgent', static::$_userAgent); - static::write('Config.time', static::$sessionTime); - static::write('Config.countdown', static::$requestCountdown); - } - - /** - * Restarts this session. - * - * @return void - */ - public static function renew() { - if (session_id() === '') { - return; - } - if (isset($_COOKIE[static::_cookieName()])) { - setcookie(Configure::read('Session.cookie'), '', time() - 42000, static::$path); - } - if (!headers_sent()) { - session_write_close(); - session_start(); - session_regenerate_id(true); - } - } - - /** - * Helper method to set an internal error message. - * - * @param int $errorNumber Number of the error - * @param string $errorMessage Description of the error - * @return void - */ - protected static function _setError($errorNumber, $errorMessage) { - if (static::$error === false) { - static::$error = array(); - } - static::$error[$errorNumber] = $errorMessage; - static::$lastError = $errorNumber; - } + } + +/** + * Find the handler class and make sure it implements the correct interface. + * + * @param string $handler Handler name. + * @return CakeSessionHandlerInterface + * @throws CakeSessionException + */ + protected static function _getHandler($handler) { + list($plugin, $class) = pluginSplit($handler, true); + App::uses($class, $plugin . 'Model/Datasource/Session'); + if (!class_exists($class)) { + throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class)); + } + $handler = new $class(); + if ($handler instanceof CakeSessionHandlerInterface) { + return $handler; + } + throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); + } + +/** + * Get one of the prebaked default session configurations. + * + * @param string $name Config name. + * @return bool|array + */ + protected static function _defaultConfig($name) { + $defaults = array( + 'php' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'session.cookie_path' => static::$path + ) + ), + 'cake' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.serialize_handler' => 'php', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_path' => TMP . 'sessions', + 'session.save_handler' => 'files' + ) + ), + 'cache' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_handler' => 'user', + ), + 'handler' => array( + 'engine' => 'CacheSession', + 'config' => 'default' + ) + ), + 'database' => array( + 'cookie' => 'CAKEPHP', + 'timeout' => 240, + 'ini' => array( + 'session.use_trans_sid' => 0, + 'url_rewriter.tags' => '', + 'session.use_cookies' => 1, + 'session.cookie_path' => static::$path, + 'session.save_handler' => 'user', + 'session.serialize_handler' => 'php', + ), + 'handler' => array( + 'engine' => 'DatabaseSession', + 'model' => 'Session' + ) + ) + ); + if (isset($defaults[$name])) { + return $defaults[$name]; + } + return false; + } + +/** + * Helper method to start a session + * + * @return bool Success + */ + protected static function _startSession() { + static::init(); + session_write_close(); + static::_configureSession(); + + if (headers_sent()) { + if (empty($_SESSION)) { + $_SESSION = array(); + } + } else { + $limit = Configure::read('Session.cacheLimiter'); + if (!empty($limit)) { + session_cache_limiter($limit); + } + session_start(); + } + return true; + } + +/** + * Helper method to create a new session. + * + * @return void + */ + protected static function _checkValid() { + $config = static::read('Config'); + if ($config) { + $sessionConfig = Configure::read('Session'); + + if (static::valid()) { + static::write('Config.time', static::$sessionTime); + if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { + $check = $config['countdown']; + $check -= 1; + static::write('Config.countdown', $check); + + if ($check < 1) { + static::renew(); + static::write('Config.countdown', static::$requestCountdown); + } + } + } else { + $_SESSION = array(); + static::destroy(); + static::_setError(1, 'Session Highjacking Attempted !!!'); + static::_startSession(); + static::_writeConfig(); + } + } else { + static::_writeConfig(); + } + } + +/** + * Writes configuration variables to the session + * + * @return void + */ + protected static function _writeConfig() { + static::write('Config.userAgent', static::$_userAgent); + static::write('Config.time', static::$sessionTime); + static::write('Config.countdown', static::$requestCountdown); + } + +/** + * Restarts this session. + * + * @return void + */ + public static function renew() { + if (session_id() === '') { + return; + } + if (isset($_COOKIE[static::_cookieName()])) { + setcookie(Configure::read('Session.cookie'), '', time() - 42000, static::$path); + } + if (!headers_sent()) { + session_write_close(); + session_start(); + session_regenerate_id(true); + } + } + +/** + * Helper method to set an internal error message. + * + * @param int $errorNumber Number of the error + * @param string $errorMessage Description of the error + * @return void + */ + protected static function _setError($errorNumber, $errorMessage) { + if (static::$error === false) { + static::$error = array(); + } + static::$error[$errorNumber] = $errorMessage; + static::$lastError = $errorNumber; + } } From 61eddc6bde677a28b00011926970baf0d65b2e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20Wei=C3=9F?= Date: Sat, 7 Oct 2017 11:11:45 +0200 Subject: [PATCH 31/44] Fixed formatting --- lib/Cake/Model/Datasource/CakeSession.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index 4f4f7e97a74..a692ed74c8c 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -139,7 +139,7 @@ class CakeSession { * * @var bool */ - protected static $_isCLI = false; + protected static $_isCLI = false; /** * Pseudo constructor. @@ -605,10 +605,10 @@ protected static function _cookieName() { */ protected static function _hasSession() { return static::started() - || !ini_get('session.use_cookies') - || isset($_COOKIE[static::_cookieName()]) - || static::$_isCLI - || (ini_get('session.use_trans_sid') && isset($_GET[session_name()])); + || !ini_get('session.use_cookies') + || isset($_COOKIE[static::_cookieName()]) + || static::$_isCLI + || (ini_get('session.use_trans_sid') && isset($_GET[session_name()])); } /** From 7d2d902b573ea519f519c5bd2e4b5cebb56a4ece Mon Sep 17 00:00:00 2001 From: Koji Tanaka Date: Sun, 8 Oct 2017 16:15:10 +0900 Subject: [PATCH 32/44] [2.x]Fix Credit card number pattern(JCB) is wrong --- lib/Cake/Test/Case/Utility/ValidationTest.php | 16 ++++++++-------- lib/Cake/Utility/Validation.php | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/ValidationTest.php b/lib/Cake/Test/Case/Utility/ValidationTest.php index a4377b68540..de3b01e52eb 100644 --- a/lib/Cake/Test/Case/Utility/ValidationTest.php +++ b/lib/Cake/Test/Case/Utility/ValidationTest.php @@ -329,14 +329,14 @@ public function testCc() { $this->assertTrue(Validation::cc('214981579370225', array('enroute'))); $this->assertTrue(Validation::cc('201447595859877', array('enroute'))); //JCB 15 digit - $this->assertTrue(Validation::cc('210034762247893', array('jcb'))); + $this->assertTrue(Validation::cc('213134762247898', array('jcb'))); $this->assertTrue(Validation::cc('180078671678892', array('jcb'))); $this->assertTrue(Validation::cc('180010559353736', array('jcb'))); - $this->assertTrue(Validation::cc('210095474464258', array('jcb'))); - $this->assertTrue(Validation::cc('210006675562188', array('jcb'))); - $this->assertTrue(Validation::cc('210063299662662', array('jcb'))); + $this->assertTrue(Validation::cc('213195474464253', array('jcb'))); + $this->assertTrue(Validation::cc('213106675562183', array('jcb'))); + $this->assertTrue(Validation::cc('213163299662667', array('jcb'))); $this->assertTrue(Validation::cc('180032506857825', array('jcb'))); - $this->assertTrue(Validation::cc('210057919192738', array('jcb'))); + $this->assertTrue(Validation::cc('213157919192733', array('jcb'))); $this->assertTrue(Validation::cc('180031358949367', array('jcb'))); $this->assertTrue(Validation::cc('180033802147846', array('jcb'))); //JCB 16 digit @@ -706,7 +706,7 @@ public function testLuhn() { //enRoute $this->assertTrue(Validation::luhn('201496944158937', true)); //JCB 15 digit - $this->assertTrue(Validation::luhn('210034762247893', true)); + $this->assertTrue(Validation::luhn('213134762247898', true)); //JCB 16 digit $this->assertTrue(Validation::luhn('3096806857839939', true)); //Maestro (debit card) @@ -811,7 +811,7 @@ public function testAllCc() { //enRoute $this->assertTrue(Validation::cc('201496944158937', 'all')); //JCB 15 digit - $this->assertTrue(Validation::cc('210034762247893', 'all')); + $this->assertTrue(Validation::cc('213134762247898', 'all')); //JCB 16 digit $this->assertTrue(Validation::cc('3096806857839939', 'all')); //Maestro (debit card) @@ -861,7 +861,7 @@ public function testAllCcDeep() { //enRoute $this->assertTrue(Validation::cc('201496944158937', 'all', true)); //JCB 15 digit - $this->assertTrue(Validation::cc('210034762247893', 'all', true)); + $this->assertTrue(Validation::cc('213134762247898', 'all', true)); //JCB 16 digit $this->assertTrue(Validation::cc('3096806857839939', 'all', true)); //Maestro (debit card) diff --git a/lib/Cake/Utility/Validation.php b/lib/Cake/Utility/Validation.php index 0f340a012ba..f7d27cc9ffb 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -175,7 +175,7 @@ public static function cc($check, $type = 'fast', $deep = false, $regex = null) 'disc' => '/^(?:6011|650\\d)\\d{12}$/', 'electron' => '/^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$/', 'enroute' => '/^2(?:014|149)\\d{11}$/', - 'jcb' => '/^(3\\d{4}|2100|1800)\\d{11}$/', + 'jcb' => '/^(3\\d{4}|2131|1800)\\d{11}$/', 'maestro' => '/^(?:5020|6\\d{3})\\d{12}$/', 'mc' => '/^(5[1-5]\\d{14})|(2(?:22[1-9]|2[3-9][0-9]|[3-6][0-9]{2}|7[0-1][0-9]|720)\\d{12})$/', 'solo' => '/^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$/', From e85f489c1f0d65d62a11d11b0dcce67af069bb42 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 13 Oct 2017 21:55:56 -0400 Subject: [PATCH 33/44] Add test for #11284 --- .../Test/Case/Model/Datasource/Database/SqlserverTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 18a78b78156..4013d215d6b 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -397,6 +397,13 @@ public function testDistinctWithLimit() { )); $result = $this->db->getLastQuery(); $this->assertRegExp('/^SELECT DISTINCT TOP 5/', $result); + + $this->db->read($this->model, array( + 'fields' => array('DISTINCT SqlserverTestModel.city', 'SqlserverTestModel.country'), + 'limit' => '5' + )); + $result = $this->db->getLastQuery(); + $this->assertRegExp('/^SELECT DISTINCT TOP 5/', $result); } /** From bbea91090ddf31bff6d42706860a0a3d74e8d1db Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Mon, 16 Oct 2017 20:55:00 +0900 Subject: [PATCH 34/44] Fix CookieComponent::delete() not working for deep children --- .../Controller/Component/CookieComponent.php | 29 ++----- .../Component/CookieComponentTest.php | 83 +++++++++++++++++++ 2 files changed, 92 insertions(+), 20 deletions(-) diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index 5aeb5a36542..a8ad8bbbed5 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -316,20 +316,16 @@ public function delete($key) { $this->read(); } if (strpos($key, '.') === false) { - if (isset($this->_values[$this->name][$key]) && is_array($this->_values[$this->name][$key])) { - foreach ($this->_values[$this->name][$key] as $idx => $val) { - $this->_delete("[$key][$idx]"); - } - } - $this->_delete("[$key]"); unset($this->_values[$this->name][$key]); - return; - } - $names = explode('.', $key, 2); - if (isset($this->_values[$this->name][$names[0]]) && is_array($this->_values[$this->name][$names[0]])) { - $this->_values[$this->name][$names[0]] = Hash::remove($this->_values[$this->name][$names[0]], $names[1]); + $this->_delete('[' . $key . ']'); + } else { + $this->_values[$this->name] = Hash::remove((array)$this->_values[$this->name], $key); + list($key) = explode('.', $key, 2); + if (isset($this->_values[$this->name][$key])) { + $value = $this->_values[$this->name][$key]; + $this->_write('[' . $key . ']', $value); + } } - $this->_delete('[' . implode('][', $names) . ']'); } /** @@ -347,14 +343,7 @@ public function destroy() { } foreach ($this->_values[$this->name] as $name => $value) { - if (is_array($value)) { - foreach ($value as $key => $val) { - unset($this->_values[$this->name][$name][$key]); - $this->_delete("[$name][$key]"); - } - } - unset($this->_values[$this->name][$name]); - $this->_delete("[$name]"); + $this->delete($name); } } diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index ea2f4998bd5..5524e3366c4 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -807,6 +807,89 @@ public function testDeleteChildrenNotExist() { $this->assertNull($this->Cookie->delete('Not.Found')); } +/** + * Test deleting deep child elements sends correct cookies. + * + * @return void + */ + public function testDeleteDeepChildren() { + $_COOKIE = array( + 'CakeTestCookie' => array( + 'foo' => $this->_encrypt(array( + 'bar' => array( + 'baz' => 'value', + ), + )), + ), + ); + + $this->Cookie->delete('foo.bar.baz'); + + $cookies = $this->Controller->response->cookie(); + $expected = array( + 'CakeTestCookie[foo]' => array( + 'name' => 'CakeTestCookie[foo]', + 'value' => '{"bar":[]}', + 'path' => '/', + 'domain' => '', + 'secure' => false, + 'httpOnly' => false + ), + ); + + $expires = Hash::combine($cookies, '{*}.name', '{*}.expire'); + $cookies = Hash::remove($cookies, '{*}.expire'); + $this->assertEquals($expected, $cookies); + + $this->assertWithinMargin($expires['CakeTestCookie[foo]'], time() + 10, 2); + } + +/** + * Test destroy works. + * + * @return void + */ + public function testDestroy() { + $_COOKIE = array( + 'CakeTestCookie' => array( + 'foo' => $this->_encrypt(array( + 'bar' => array( + 'baz' => 'value', + ), + )), + 'other' => 'value', + ), + ); + + $this->Cookie->destroy(); + + $cookies = $this->Controller->response->cookie(); + $expected = array( + 'CakeTestCookie[foo]' => array( + 'name' => 'CakeTestCookie[foo]', + 'value' => '', + 'path' => '/', + 'domain' => '', + 'secure' => false, + 'httpOnly' => false + ), + 'CakeTestCookie[other]' => array( + 'name' => 'CakeTestCookie[other]', + 'value' => '', + 'path' => '/', + 'domain' => '', + 'secure' => false, + 'httpOnly' => false + ), + ); + + $expires = Hash::combine($cookies, '{*}.name', '{*}.expire'); + $cookies = Hash::remove($cookies, '{*}.expire'); + $this->assertEquals($expected, $cookies); + $this->assertWithinMargin($expires['CakeTestCookie[foo]'], time() - 42000, 2); + $this->assertWithinMargin($expires['CakeTestCookie[other]'], time() - 42000, 2); + } + /** * Helper method for generating old style encoded cookie values. * From 19bbb7da17dd97ae3daa4d8a4987a333516a9e34 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Mon, 16 Oct 2017 21:01:19 +0900 Subject: [PATCH 35/44] Simplify CookieComponent::read() Also, this commit fixes an issue of when the second level key is empty. Previously, read('foo.0') returned incorrect result. --- .../Controller/Component/CookieComponent.php | 17 +---------------- .../Component/CookieComponentTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index a8ad8bbbed5..1d01e227d68 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -261,22 +261,7 @@ public function read($key = null) { if ($key === null) { return $this->_values[$this->name]; } - - if (strpos($key, '.') !== false) { - $names = explode('.', $key, 2); - $key = $names[0]; - } - if (!isset($this->_values[$this->name][$key])) { - return null; - } - - if (!empty($names[1])) { - if (is_array($this->_values[$this->name][$key])) { - return Hash::get($this->_values[$this->name][$key], $names[1]); - } - return null; - } - return $this->_values[$this->name][$key]; + return Hash::get($this->_values[$this->name], $key); } /** diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index 5524e3366c4..1620842accc 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -714,6 +714,20 @@ public function testReadEmpty() { $this->assertEquals(array(), $this->Cookie->read('Array')); } +/** + * Test reading empty key + * + * @return void + */ + public function testReadEmptyKey() { + $_COOKIE['CakeTestCookie'] = array( + '0' => '{"name":"value"}', + 'foo' => array('bar'), + ); + $this->assertEquals('value', $this->Cookie->read('0.name')); + $this->assertEquals('bar', $this->Cookie->read('foo.0')); + } + /** * test that no error is issued for non array data. * From 549c18192643dd1160fd0d094498f24ec4d68dd9 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 18 Oct 2017 21:54:49 -0400 Subject: [PATCH 36/44] Update version number to 2.10.4 --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index 2e9e56b553d..17a775eda56 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.10.3 +2.10.4 From 46296db37308b6661c8b3d0179014efd3649135c Mon Sep 17 00:00:00 2001 From: Joseph Zidell Date: Fri, 20 Oct 2017 12:43:47 -0400 Subject: [PATCH 37/44] Test against PHP 7.2 Install `mcrypt` from PECL --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index ad66e35ad45..4c0b033601b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 env: matrix: @@ -38,6 +39,9 @@ matrix: - php: 7.1 env: DB=mysql PHPUNIT=5.7.19 + - php: 7.2 + env: DB=mysql PHPUNIT=5.7.19 + before_script: - composer require "phpunit/phpunit=$PHPUNIT" @@ -52,6 +56,7 @@ before_script: - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE SCHEMA test3;' -U postgres -d cakephp_test; fi" - chmod -R 777 ./app/tmp - if [[ ${TRAVIS_PHP_VERSION:0:3} == "5.3" ]] ; then pecl install timezonedb ; fi + - if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.2" ]] ; then pecl install mcrypt ; fi - sh -c "if [ '$PHPCS' = '1' ]; then composer require 'cakephp/cakephp-codesniffer:1.*'; fi" - sh -c "if [ '$PHPCS' = '1' ]; then vendors/bin/phpcs --config-set installed_paths vendors/cakephp/cakephp-codesniffer; fi" - echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From b59b64db290ea05dcf919b76e0788652f2032d92 Mon Sep 17 00:00:00 2001 From: saeideng Date: Sat, 21 Oct 2017 22:44:15 +0330 Subject: [PATCH 38/44] replace tab with space --- lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php index 14968be9f3a..16fbcaa1939 100644 --- a/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php @@ -7,8 +7,8 @@ * For full copyright and license information, please see the LICENSE.txt * Redistributions of the files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) - * @link https://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @license https://opensource.org/licenses/mit-license.php MIT License */ From 7de5ae44385bd39eacb4d096722ead1647798a0a Mon Sep 17 00:00:00 2001 From: Milan van As Date: Wed, 25 Oct 2017 08:45:57 +0200 Subject: [PATCH 39/44] Force email domain lookups to work in fallback case. --- lib/Cake/Utility/Validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Validation.php b/lib/Cake/Utility/Validation.php index f7d27cc9ffb..95a960ce0a8 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -478,7 +478,7 @@ public static function email($check, $deep = false, $regex = null) { if (function_exists('checkdnsrr') && checkdnsrr($regs[1], 'MX')) { return true; } - return is_array(gethostbynamel($regs[1])); + return is_array(gethostbynamel($regs[1] . '.')); } return false; } From c625269a600d3521aca10b28923aa32ca8c876b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 2 Nov 2017 01:11:58 +0100 Subject: [PATCH 40/44] Allow the Travis build on PHP 7.2 to fail --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4c0b033601b..3ea5465d075 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,9 @@ matrix: - php: 7.2 env: DB=mysql PHPUNIT=5.7.19 + allow_failures: + - php: 7.2 + env: DB=mysql PHPUNIT=5.7.19 before_script: From 5524768ea47cce21bcc44cd44e120861374fb9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 2 Nov 2017 01:18:00 +0100 Subject: [PATCH 41/44] Allow the other PHP 7.2 job to fail --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3ea5465d075..c4bec90f755 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,9 @@ matrix: - php: 7.2 env: DB=mysql PHPUNIT=5.7.19 allow_failures: + - php: 7.2 + env: DB=mysql + - php: 7.2 env: DB=mysql PHPUNIT=5.7.19 From 26a683f36f1489524f64f9e18597b8694e092391 Mon Sep 17 00:00:00 2001 From: Yaser Naderi Date: Fri, 3 Nov 2017 14:53:54 -0400 Subject: [PATCH 42/44] - DigestAuthenticate modification for cakephp 2.X --- lib/Cake/Controller/Component/Auth/DigestAuthenticate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index f1ba711cda8..581a3798df1 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -44,7 +44,7 @@ * Due to the Digest authentication specification, digest auth requires a special password value. You * can generate this password using `DigestAuthenticate::password()` * - * `$digestPass = DigestAuthenticate::password($username, env('SERVER_NAME'), $password);` + * `$digestPass = DigestAuthenticate::password($username, $passwordm env('SERVER_NAME'));` * * Its recommended that you store this digest auth only password separate from password hashes used for other * login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would From f788c90b3cf57317da46fbb0fb9e8721ffbec9ed Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 5 Nov 2017 22:34:47 -0500 Subject: [PATCH 43/44] Fix typo --- lib/Cake/Controller/Component/Auth/DigestAuthenticate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index 46b7648b1f9..04637994fd3 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -44,7 +44,7 @@ * Due to the Digest authentication specification, digest auth requires a special password value. You * can generate this password using `DigestAuthenticate::password()` * - * `$digestPass = DigestAuthenticate::password($username, $passwordm env('SERVER_NAME'));` + * `$digestPass = DigestAuthenticate::password($username, $password, env('SERVER_NAME'));` * * Its recommended that you store this digest auth only password separate from password hashes used for other * login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would From 10fcd7633d40b100a57054025dd38cd008fded80 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 20 Nov 2017 21:09:55 -0500 Subject: [PATCH 44/44] Update version number to 2.10.5 --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index 17a775eda56..9b5d74257dd 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.10.4 +2.10.5