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 57d1df3c6..31808c647 100644 --- a/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php +++ b/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php @@ -175,7 +175,7 @@ class CakeFixtureManager { } /** - * 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 @@ class CakeFixtureManager { } } if (!empty($fixture->created) && in_array($db->configKeyName, $fixture->created)) { + $fixture->truncate($db); return; } @@ -205,6 +206,7 @@ class CakeFixtureManager { $fixture->create($db); } else { $fixture->created[] = $db->configKeyName; + $fixture->truncate($db); } } @@ -229,7 +231,6 @@ class CakeFixtureManager { $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 @@ class CakeFixtureManager { $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 e3ff573ec..69c5fdc03 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 c868580f7..75def3eb4 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -265,7 +265,19 @@ class CakeHtmlReporter extends CakeBaseReporter { 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 75def3eb4..2c04d5215 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -267,13 +267,9 @@ class CakeHtmlReporter extends CakeBaseReporter { 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 2c04d5215..9106d17bd 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -270,7 +270,8 @@ class CakeHtmlReporter extends CakeBaseReporter { 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 9106d17bd..8c07e9b45 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -265,7 +265,7 @@ class CakeHtmlReporter extends CakeBaseReporter { 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 @@ class CakeHtmlReporter extends CakeBaseReporter {
 				$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 78c5c4526..40a147782 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -4944,6 +4944,30 @@ class FormHelperTest extends CakeTestCase { $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 61ec241c3..8a15e1d7a 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1674,7 +1674,7 @@ class FormHelper extends AppHelper { $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 806ec9144..03e9f9091 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 ab3e0a773..f373218a7 100644 --- a/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/SessionHelperTest.php @@ -47,24 +47,32 @@ class SessionHelperTest extends CakeTestCase { '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 @@ class SessionHelperTest extends CakeTestCase { 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 6a97dbddd..fd340843d 100644 --- a/lib/Cake/View/Helper/SessionHelper.php +++ b/lib/Cake/View/Helper/SessionHelper.php @@ -134,30 +134,14 @@ class SessionHelper extends AppHelper { 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 @@ class SessionHelper extends AppHelper { 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 69c5fdc03..c3b4d2639 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 4c7b467da..f66f5be62 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -136,7 +136,13 @@ class SessionComponent extends Component { * @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 dd0df58c7..8814a491f 100644 --- a/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php @@ -247,16 +247,13 @@ class SessionComponentTest extends CakeTestCase { $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 f66f5be62..4057885ca 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -137,11 +137,11 @@ class SessionComponent extends Component { */ 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 75010f023..61ca6f047 100644 --- a/lib/Cake/basics.php +++ b/lib/Cake/basics.php @@ -196,7 +196,7 @@ if (!function_exists('h')) { * 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 c3b4d2639..2e9e56b55 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 5946e31af..bb4b47f65 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 5946e31af..bb4b47f65 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 b84b35950..9c7fcf66a 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -275,6 +275,10 @@ class CakeEmailTest extends CakeTestCase { $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 9c7fcf66a..a0d15bec8 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -276,7 +276,7 @@ class CakeEmailTest extends CakeTestCase { $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 4057885ca..b298e420d 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -153,7 +153,7 @@ class SessionComponent extends Component { * @return void */ public function renew() { - return CakeSession::renew(); + CakeSession::renew(); } /** @@ -176,7 +176,7 @@ class SessionComponent extends Component { * @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 3df0bf734..b12560e30 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -60,7 +60,7 @@ class ConsoleErrorHandler { )); $code = $exception->getCode(); $code = ($code && is_int($code)) ? $code : 1; - return $this->_stop($code); + $this->_stop($code); } /** @@ -88,7 +88,7 @@ class ConsoleErrorHandler { } 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 e4ce01f3c..90ee0eb38 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -415,7 +415,7 @@ class Shell extends CakeObject { * @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 @@ class Shell extends CakeObject { * 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 @@ class Shell extends CakeObject { * @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 @@ class Shell extends CakeObject { * * @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 eb420709c..dbbb30fef 100644 --- a/lib/Cake/Controller/Component/Acl/DbAcl.php +++ b/lib/Cake/Controller/Component/Acl/DbAcl.php @@ -52,7 +52,7 @@ class DbAcl extends CakeObject implements AclInterface { /** * 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 f1ba711cd..86fdac616 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -136,7 +136,7 @@ class DigestAuthenticate extends BasicAuthenticate { /** * 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 9fe60e683..e21f6e085 100644 --- a/lib/Cake/Controller/Component/AuthComponent.php +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -761,7 +761,7 @@ class AuthComponent extends Component { * * @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 af46d5e9e..4332dac81 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -494,7 +494,7 @@ class CookieComponent extends Component { * 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 @@ class CookieComponent extends Component { * 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 @@ class CookieComponent extends Component { * 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 47e91d2b0..4fd96dfb7 100644 --- a/lib/Cake/Controller/Component/EmailComponent.php +++ b/lib/Cake/Controller/Component/EmailComponent.php @@ -282,7 +282,7 @@ class EmailComponent extends Component { * 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 322fac19d..4a23756ef 100644 --- a/lib/Cake/Event/CakeEvent.php +++ b/lib/Cake/Event/CakeEvent.php @@ -111,7 +111,7 @@ class CakeEvent { /** * 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 e2d9276e6..e4b74a096 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -166,7 +166,8 @@ class CakeEventManager { */ 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 740fcccad..1b9b51116 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -432,7 +432,7 @@ class TranslateBehavior extends ModelBehavior { * 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 @@ class TranslateBehavior extends ModelBehavior { * 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 @@ class TranslateBehavior extends ModelBehavior { * @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 d137cb222..db10a8762 100644 --- a/lib/Cake/Model/BehaviorCollection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -73,7 +73,7 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener { * * @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 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener { * * @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 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener { * @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 9a9e4c1c3..2cf39c356 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlite.php +++ b/lib/Cake/Model/Datasource/Database/Sqlite.php @@ -212,7 +212,7 @@ class Sqlite extends DboSource { * @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 bcf6b9e44..f968e2cff 100644 --- a/lib/Cake/Model/ModelValidator.php +++ b/lib/Cake/Model/ModelValidator.php @@ -234,7 +234,7 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable { * 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 8aacde4ef..1643bcbfd 100644 --- a/lib/Cake/Network/Http/HttpSocket.php +++ b/lib/Cake/Network/Http/HttpSocket.php @@ -760,7 +760,7 @@ class HttpSocket extends CakeSocket { * * @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 3be02126a..69c6da725 100644 --- a/lib/Cake/Network/Http/HttpSocketResponse.php +++ b/lib/Cake/Network/Http/HttpSocketResponse.php @@ -259,7 +259,7 @@ class HttpSocketResponse implements ArrayAccess { * 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 6c4bed107..06ecf6c65 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -581,10 +581,10 @@ class File { */ 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 2ee5ad30b..62fef677a 100644 --- a/lib/Cake/Utility/Folder.php +++ b/lib/Cake/Utility/Folder.php @@ -323,7 +323,7 @@ class Folder { * 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 450d061f6..0f8b5e073 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 06ecf6c65..344e00df9 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -582,6 +582,7 @@ class File { 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 b12560e30..6a07d0128 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -60,7 +60,7 @@ class ConsoleErrorHandler { )); $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 344e00df9..a2e704143 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -582,7 +582,7 @@ class File { 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 6a07d0128..3df0bf734 100644 --- a/lib/Cake/Console/ConsoleErrorHandler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -88,7 +88,7 @@ class ConsoleErrorHandler { } 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 e4b74a096..ef53ea4c1 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -167,7 +167,7 @@ class CakeEventManager { 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 db10a8762..faae57064 100644 --- a/lib/Cake/Model/BehaviorCollection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -204,7 +204,7 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener { * @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 ef53ea4c1..e2d9276e6 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -166,8 +166,7 @@ class CakeEventManager { */ 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 a2e704143..6c4bed107 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -581,11 +581,10 @@ class File { */ 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 03e9f9091..2e9c78fd7 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -411,7 +411,7 @@ class Sqlserver extends DboSource { $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 4332dac81..5aeb5a365 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -229,27 +229,14 @@ class CookieComponent extends Component { } 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 c3fddddb3..ea2f4998b 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -429,6 +429,24 @@ class CookieComponentTest extends CakeTestCase { $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 344d7bca1..6208aa4a4 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -91,8 +91,8 @@ class Hash { * * - `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 @@ class Hash { } return $context[$_key]; } + /** * Split token conditions * @@ -454,7 +455,7 @@ class Hash { * 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 @@ class Hash { * 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 @@ class Hash { * 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 @@ class Hash { * - `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 c4a43df9d..fb5db2693 100644 --- a/lib/Cake/Test/Case/Utility/HashTest.php +++ b/lib/Cake/Test/Case/Utility/HashTest.php @@ -1356,7 +1356,7 @@ class HashTest extends CakeTestCase { ); $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 @@ class HashTest extends CakeTestCase { $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 @@ class HashTest extends CakeTestCase { 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 @@ class HashTest extends CakeTestCase { $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 @@ class HashTest extends CakeTestCase { 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 6208aa4a4..08dd2700a 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -275,12 +275,10 @@ class Hash { 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 @@ class Hash { $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 @@ class Hash { } } 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 @@ class Hash { 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 @@ class Hash { $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 @@ class Hash { $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 38ab50e92..3fb00a46e 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -34,759 +34,771 @@ App::uses('Security', 'Utility'); */ 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 | 1390 ++++++++++----------- 1 file changed, 695 insertions(+), 695 deletions(-) diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index 3fb00a46e..4f4f7e97a 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -34,771 +34,771 @@ App::uses('Security', 'Utility'); */ class CakeSession { - /** - * True if the Session is still valid - * - * @var bool - */ - public static $valid = false; +/** + * True if the Session is still valid + * + * @var bool + */ + public static $valid = false; - /** - * Error messages for this session - * - * @var array - */ - public static $error = false; +/** + * Error messages for this session + * + * @var array + */ + public static $error = false; - /** - * User agent string - * - * @var string - */ - protected static $_userAgent = ''; +/** + * User agent string + * + * @var string + */ + protected static $_userAgent = ''; - /** - * Path to where the session is active. - * - * @var string - */ - public static $path = '/'; +/** + * Path to where the session is active. + * + * @var string + */ + public static $path = '/'; - /** - * Error number of last occurred error - * - * @var int - */ - public static $lastError = null; +/** + * Error number of last occurred error + * + * @var int + */ + public static $lastError = null; - /** - * Start time for this session. - * - * @var int - */ - public static $time = false; +/** + * Start time for this session. + * + * @var int + */ + public static $time = false; - /** - * Cookie lifetime - * - * @var int - */ - public static $cookieLifeTime; +/** + * Cookie lifetime + * + * @var int + */ + public static $cookieLifeTime; - /** - * Time when this session becomes invalid. - * - * @var int - */ - public static $sessionTime = false; +/** + * Time when this session becomes invalid. + * + * @var int + */ + public static $sessionTime = false; - /** - * Current Session id - * - * @var string - */ - public static $id = null; +/** + * Current Session id + * + * @var string + */ + public static $id = null; - /** - * Hostname - * - * @var string - */ - public static $host = null; +/** + * Hostname + * + * @var string + */ + public static $host = null; - /** - * Session timeout multiplier factor - * - * @var int - */ - public static $timeout = 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; +/** + * 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; +/** + * 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; +/** + * Session cookie name + * + * @var string + */ + protected static $_cookieName = null; - /** - * Whether this session is running under a CLI environment - * - * @var bool - */ +/** + * 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(); +/** + * 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')); - } + 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')); + static::_setPath($base); + static::_setHost(env('HTTP_HOST')); - if (!static::$_initialized) { - register_shutdown_function('session_write_close'); - } + if (!static::$_initialized) { + register_shutdown_function('session_write_close'); + } - static::$_initialized = true; - static::$_isCLI = (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg'); - } + 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; - } +/** + * 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, ':')); - } - } +/** + * 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; - } +/** + * 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(); - } + $id = static::id(); + static::_startSession(); + if (!$id && static::started()) { + static::_checkValid(); + } - static::$error = false; - static::$valid = true; - return static::started(); - } + 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(); - } +/** + * 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; - } +/** + * 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; - } + 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; - } +/** + * 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; - } +/** + * 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; - } - } +/** + * 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]; - } +/** + * 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 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; - } +/** + * 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); - } +/** + * 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; - } +/** + * 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); +/** + * 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; - } + 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; - } +/** + * 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; - } +/** + * 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; - } + $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; - } +/** + * 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(); - } +/** + * 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()]); - } + 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; - } + $_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; - } +/** + * 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(); - } + $_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'); +/** + * 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['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 (!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 (!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 (!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); - } + 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; - } +/** + * Get session cookie name. + * + * @return string + */ + protected static function _cookieName() { + if (static::$_cookieName !== null) { + return static::$_cookieName; + } - static::init(); - static::_configureSession(); + static::init(); + static::_configureSession(); - return static::$_cookieName = session_name(); - } + return static::$_cookieName = session_name(); + } - /** - * Returns whether a session exists - * - * @return bool - */ - protected static function _hasSession() { - return static::started() +/** + * 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.')); - } +/** + * 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; - } +/** + * 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(); +/** + * 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; - } + 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'); +/** + * 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 (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(); - } - } + 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); - } +/** + * 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); - } - } +/** + * 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; - } +/** + * 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 4f4f7e97a..a692ed74c 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 @@ class CakeSession { */ 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 a4377b685..de3b01e52 100644 --- a/lib/Cake/Test/Case/Utility/ValidationTest.php +++ b/lib/Cake/Test/Case/Utility/ValidationTest.php @@ -329,14 +329,14 @@ class ValidationTest extends CakeTestCase { $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 @@ class ValidationTest extends CakeTestCase { //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 @@ class ValidationTest extends CakeTestCase { //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 @@ class ValidationTest extends CakeTestCase { //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 0f340a012..f7d27cc9f 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -175,7 +175,7 @@ class Validation { '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 18a78b781..4013d215d 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 @@ class SqlserverTest extends CakeTestCase { )); $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 5aeb5a365..a8ad8bbbe 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -316,20 +316,16 @@ class CookieComponent extends Component { $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; + $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); + } } - $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('[' . implode('][', $names) . ']'); } /** @@ -347,14 +343,7 @@ class CookieComponent extends Component { } 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 ea2f4998b..5524e3366 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -807,6 +807,89 @@ class CookieComponentTest extends CakeTestCase { $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 a8ad8bbbe..1d01e227d 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -261,22 +261,7 @@ class CookieComponent extends Component { 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 5524e3366..1620842ac 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -714,6 +714,20 @@ class CookieComponentTest extends CakeTestCase { $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 2e9e56b55..17a775eda 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 ad66e35ad..4c0b03360 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 14968be9f..16fbcaa19 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 f7d27cc9f..95a960ce0 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -478,7 +478,7 @@ class Validation { 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 4c0b03360..3ea5465d0 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 3ea5465d0..c4bec90f7 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 f1ba711cd..581a3798d 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -44,7 +44,7 @@ App::uses('BasicAuthenticate', 'Controller/Component/Auth'); * 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 46b7648b1..04637994f 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -44,7 +44,7 @@ App::uses('BasicAuthenticate', 'Controller/Component/Auth'); * 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 17a775eda..9b5d74257 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