From aa21244593c0127248edf2a57fa62ef585f587dc Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Tue, 8 Nov 2016 00:40:46 +0100 Subject: [PATCH 01/43] accept webroot shell parameter --- lib/Cake/Console/Command/CommandListShell.php | 1 + lib/Cake/Console/ShellDispatcher.php | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Console/Command/CommandListShell.php b/lib/Cake/Console/Command/CommandListShell.php index ca6620a5b..2962fa526 100644 --- a/lib/Cake/Console/Command/CommandListShell.php +++ b/lib/Cake/Console/Command/CommandListShell.php @@ -54,6 +54,7 @@ class CommandListShell extends AppShell { $this->out(" -working: " . rtrim(APP, DS)); $this->out(" -root: " . rtrim(ROOT, DS)); $this->out(" -core: " . rtrim(CORE_PATH, DS)); + $this->out(" -webroot: " . WWW_ROOT); $this->out(""); $this->out(__d('cake_console', "Changing Paths:"), 2); $this->out(__d('cake_console', "Your working path should be the same as your application path. To change your path use the '-app' param.")); diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index 37aa30037..b33714684 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -129,7 +129,7 @@ class ShellDispatcher { define('APP', $this->params['working'] . DS); } if (!defined('WWW_ROOT')) { - define('WWW_ROOT', APP . $this->params['webroot'] . DS); + define('WWW_ROOT', $this->params['webroot'] . DS); } if (!defined('TMP') && !is_dir(APP . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); @@ -305,7 +305,7 @@ class ShellDispatcher { } } - if ($params['app'][0] === '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) { + if ($this->_isAbsolutePath($params['app'])) { $params['root'] = dirname($params['app']); } elseif (strpos($params['app'], '/')) { $params['root'] .= '/' . dirname($params['app']); @@ -316,14 +316,27 @@ class ShellDispatcher { if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) { $params['working'] .= '/' . $params['app']; } + if (!$this->_isAbsolutePath($params['webroot'])) { + $params['webroot'] = realpath($params['working'] . DS . $params['webroot']); + } - if (!empty($matches[0]) || !empty($isWin)) { + if (DS == '\\' || !empty($isWin)) { $params = str_replace('/', '\\', $params); } $this->params = $params + $this->params; } +/** + * Checks whether the given path is absolute or relative. + * + * @param string $path absolute or relative path. + * @return boolean + */ + protected function _isAbsolutePath($path) { + return $path[0] === '/' || preg_match('/([a-z])(:)/i', $path); + } + /** * Parses out the paths from from the argv * @@ -332,7 +345,7 @@ class ShellDispatcher { */ protected function _parsePaths($args) { $parsed = array(); - $keys = array('-working', '--working', '-app', '--app', '-root', '--root'); + $keys = array('-working', '--working', '-app', '--app', '-root', '--root', '-webroot', '--webroot'); $args = (array)$args; foreach ($keys as $key) { while (($index = array_search($key, $args)) !== false) { From 86b5401778ec660aaa4f83ee2c28d7212bb639fc Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 7 Nov 2016 21:40:22 -0500 Subject: [PATCH 02/43] Update version number to 2.9.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 301ac6ed0..4e65d0110 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license http://www.opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.9.1 +2.9.2 From 467ee851bf0f73f70514fba31d52f2ec384a461a Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Tue, 8 Nov 2016 10:03:46 +0100 Subject: [PATCH 03/43] some refactoring to fix failed shell dispatcher tests --- lib/Cake/Console/Command/CommandListShell.php | 2 +- lib/Cake/Console/ShellDispatcher.php | 10 +++-- .../Test/Case/Console/ShellDispatcherTest.php | 38 +++++++++++++++++-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Console/Command/CommandListShell.php b/lib/Cake/Console/Command/CommandListShell.php index 2962fa526..9ea44960c 100644 --- a/lib/Cake/Console/Command/CommandListShell.php +++ b/lib/Cake/Console/Command/CommandListShell.php @@ -54,7 +54,7 @@ class CommandListShell extends AppShell { $this->out(" -working: " . rtrim(APP, DS)); $this->out(" -root: " . rtrim(ROOT, DS)); $this->out(" -core: " . rtrim(CORE_PATH, DS)); - $this->out(" -webroot: " . WWW_ROOT); + $this->out(" -webroot: " . rtrim(WWW_ROOT, DS)); $this->out(""); $this->out(__d('cake_console', "Changing Paths:"), 2); $this->out(__d('cake_console', "Your working path should be the same as your application path. To change your path use the '-app' param.")); diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index b33714684..fe0dd4274 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -129,7 +129,12 @@ class ShellDispatcher { define('APP', $this->params['working'] . DS); } if (!defined('WWW_ROOT')) { - define('WWW_ROOT', $this->params['webroot'] . DS); + if (!$this->_isAbsolutePath($this->params['webroot'])) { + $webroot = realpath(APP . $this->params['webroot']); + } else { + $webroot = $this->params['webroot']; + } + define('WWW_ROOT', $webroot . DS); } if (!defined('TMP') && !is_dir(APP . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); @@ -316,9 +321,6 @@ class ShellDispatcher { if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) { $params['working'] .= '/' . $params['app']; } - if (!$this->_isAbsolutePath($params['webroot'])) { - $params['webroot'] = realpath($params['working'] . DS . $params['webroot']); - } if (DS == '\\' || !empty($isWin)) { $params = str_replace('/', '\\', $params); diff --git a/lib/Cake/Test/Case/Console/ShellDispatcherTest.php b/lib/Cake/Test/Case/Console/ShellDispatcherTest.php index cec15d12a..a6f4afb05 100644 --- a/lib/Cake/Test/Case/Console/ShellDispatcherTest.php +++ b/lib/Cake/Test/Case/Console/ShellDispatcherTest.php @@ -137,9 +137,8 @@ class ShellDispatcherTest extends CakeTestCase { * * @return void */ - public function testParseParams() { + public function testParseParamsAppWorkingAbsolute() { $Dispatcher = new TestShellDispatcher(); - $params = array( '/cake/1.2.x.x/cake/console/cake.php', 'bake', @@ -156,7 +155,15 @@ class ShellDispatcherTest extends CakeTestCase { ); $Dispatcher->parseParams($params); $this->assertEquals($expected, $Dispatcher->params); + } +/** + * testParseParams method + * + * @return void + */ + public function testParseParamsNone() { + $Dispatcher = new TestShellDispatcher(); $params = array('cake.php'); $expected = array( 'app' => 'app', @@ -167,7 +174,15 @@ class ShellDispatcherTest extends CakeTestCase { $Dispatcher->params = $Dispatcher->args = array(); $Dispatcher->parseParams($params); $this->assertEquals($expected, $Dispatcher->params); + } +/** + * testParseParams method + * + * @return void + */ + public function testParseParamsApp() { + $Dispatcher = new TestShellDispatcher(); $params = array( 'cake.php', '-app', @@ -182,7 +197,15 @@ class ShellDispatcherTest extends CakeTestCase { $Dispatcher->params = $Dispatcher->args = array(); $Dispatcher->parseParams($params); $this->assertEquals($expected, $Dispatcher->params); + } +/** + * testParseParams method + * + * @return void + */ + public function testParseParamsAppWorkingRelative() { + $Dispatcher = new TestShellDispatcher(); $params = array( './cake.php', 'bake', @@ -191,17 +214,24 @@ class ShellDispatcherTest extends CakeTestCase { '-working', '/cake/1.2.x.x/cake/console' ); - $expected = array( 'app' => 'new', 'webroot' => 'webroot', 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'new'), 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH)) ); - $Dispatcher->params = $Dispatcher->args = array(); $Dispatcher->parseParams($params); $this->assertEquals($expected, $Dispatcher->params); + } + +/** + * testParseParams method + * + * @return void + */ + public function testParseParams() { + $Dispatcher = new TestShellDispatcher(); $params = array( './console/cake.php', From 92e380737df96d654855289953dc13082d6f9b3f Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Tue, 8 Nov 2016 10:44:08 +0100 Subject: [PATCH 04/43] fixed failing shell dispatcher test --- lib/Cake/Console/ShellDispatcher.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index fe0dd4274..34b98c2db 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -322,7 +322,7 @@ class ShellDispatcher { $params['working'] .= '/' . $params['app']; } - if (DS == '\\' || !empty($isWin)) { + if ($this->_isWindowsPath($params['app']) || !empty($isWin)) { $params = str_replace('/', '\\', $params); } @@ -336,7 +336,17 @@ class ShellDispatcher { * @return boolean */ protected function _isAbsolutePath($path) { - return $path[0] === '/' || preg_match('/([a-z])(:)/i', $path); + return $path[0] === '/' || $this->_isWindowsPath($path); + } + +/** + * Checks whether the given path is Window OS path. + * + * @param string $path absolute path. + * @return boolean + */ + protected function _isWindowsPath($path) { + return preg_match('/([a-z])(:)/i', $path) == 1; } /** From 7ffa7acea6e11cc6dd8d95fdeb30642ffc186120 Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Tue, 8 Nov 2016 11:04:27 +0100 Subject: [PATCH 05/43] fixed shell dispatcher failed unit test --- lib/Cake/Console/ShellDispatcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index 34b98c2db..6de4c7543 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -315,14 +315,14 @@ class ShellDispatcher { } elseif (strpos($params['app'], '/')) { $params['root'] .= '/' . dirname($params['app']); } - + $isWindowsAppPath = $this->_isWindowsPath($params['app']); $params['app'] = basename($params['app']); $params['working'] = rtrim($params['root'], '/'); if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) { $params['working'] .= '/' . $params['app']; } - if ($this->_isWindowsPath($params['app']) || !empty($isWin)) { + if ($isWindowsAppPath || !empty($isWin)) { $params = str_replace('/', '\\', $params); } From 38518c201c915ed17c9fee96c85229992bfa5e61 Mon Sep 17 00:00:00 2001 From: Val Bancer Date: Tue, 8 Nov 2016 11:35:01 +0100 Subject: [PATCH 06/43] doc blocks adjusted --- lib/Cake/Console/ShellDispatcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index 6de4c7543..bb2095418 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -333,7 +333,7 @@ class ShellDispatcher { * Checks whether the given path is absolute or relative. * * @param string $path absolute or relative path. - * @return boolean + * @return bool */ protected function _isAbsolutePath($path) { return $path[0] === '/' || $this->_isWindowsPath($path); @@ -343,7 +343,7 @@ class ShellDispatcher { * Checks whether the given path is Window OS path. * * @param string $path absolute path. - * @return boolean + * @return bool */ protected function _isWindowsPath($path) { return preg_match('/([a-z])(:)/i', $path) == 1; From 23009ae3cc22651110a6012c4ddd52dee6da0048 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 10 Nov 2016 19:41:05 -0500 Subject: [PATCH 07/43] Update build config for new pear server. Point to the new dokku based pear server. Put the files in the new location and rebuild the dokku app. --- build.properties | 2 +- build.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.properties b/build.properties index 686a4226d..8ecda7cdd 100644 --- a/build.properties +++ b/build.properties @@ -9,4 +9,4 @@ build.dir = build dist.dir = dist # Server -pirum.dir = /home/cakephp/www-live/pear.cakephp.org +pirum.dir = /var/lib/dokku/data/storage/pear diff --git a/build.xml b/build.xml index 98c48bae9..5a7bca15e 100644 --- a/build.xml +++ b/build.xml @@ -213,10 +213,10 @@ --> - + - - + + From 175503fafa3f4741d7b90e4df11a3ded8ecbd957 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Fri, 11 Nov 2016 13:37:20 +0100 Subject: [PATCH 08/43] Expose engines By implementing the `engine` method just like in version 3 --- lib/Cake/Cache/Cache.php | 15 +++++++ lib/Cake/Test/Case/Cache/CacheTest.php | 60 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/lib/Cake/Cache/Cache.php b/lib/Cake/Cache/Cache.php index a7a01d0a1..d2286960e 100644 --- a/lib/Cake/Cache/Cache.php +++ b/lib/Cake/Cache/Cache.php @@ -616,4 +616,19 @@ class Cache { self::set(null, $config); return $success; } + +/** + * Fetch the engine attached to a specific configuration name. + * + * @param string $config Optional string configuration name to get an engine for. Defaults to 'default'. + * @return bool|CacheEngine False if the engine has not been initialized else the engine + */ + public static function engine($config = 'default') { + if (self::isInitialized($config)) { + return self::$_engines[$config]; + } + + return false; + } + } diff --git a/lib/Cake/Test/Case/Cache/CacheTest.php b/lib/Cake/Test/Case/Cache/CacheTest.php index 985adb4f6..b40c77e18 100644 --- a/lib/Cake/Test/Case/Cache/CacheTest.php +++ b/lib/Cake/Test/Case/Cache/CacheTest.php @@ -538,4 +538,64 @@ class CacheTest extends CakeTestCase { $result = Cache::add('test_add_key', 'test data 2', 'default'); $this->assertFalse($result); } + +/** + * Test engine method. + * + * Success, default engine. + * + * @return void + */ + public function testEngineSuccess() { + $actual = Cache::engine(); + $this->assertIsA($actual, 'CacheEngine'); + + $actual = Cache::engine('default'); + $this->assertIsA($actual, 'CacheEngine'); + } + +/** + * Test engine method. + * + * Success, memcached engine. + * + * @return void + */ + public function testEngineSuccessMemcached() { + $this->skipIf(!class_exists('Memcached'), 'Memcached is not installed or configured properly.'); + + // @codingStandardsIgnoreStart + $socket = @fsockopen('127.0.0.1', 11211, $errno, $errstr, 1); + // @codingStandardsIgnoreEnd + $this->skipIf(!$socket, 'Memcached is not running.'); + fclose($socket); + + Cache::config('memcached', array( + 'engine' => 'Memcached', + 'prefix' => 'cake_', + 'duration' => 3600 + )); + + $actual = Cache::engine('memcached'); + $this->assertTrue($actual->add('test_add_key', 'test data', 10)); + $this->assertFalse($actual->add('test_add_key', 'test data', 10)); + $this->assertTrue($actual->delete('test_add_key')); + } + +/** + * Test engine method. + * + * Failure. + * + * @return void + */ + public function testEngineFailure() { + $actual = Cache::engine('some_config_that_does_not_exist'); + $this->assertFalse($actual); + + Configure::write('Cache.disable', true); + $actual = Cache::engine(); + $this->assertFalse($actual); + } + } From 94572ae384432ce99cd5fe397a929e7574abea9f Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Fri, 11 Nov 2016 21:41:23 +0100 Subject: [PATCH 09/43] Do not use deprecated assertIsA --- lib/Cake/Test/Case/Cache/CacheTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Cache/CacheTest.php b/lib/Cake/Test/Case/Cache/CacheTest.php index b40c77e18..725e576b3 100644 --- a/lib/Cake/Test/Case/Cache/CacheTest.php +++ b/lib/Cake/Test/Case/Cache/CacheTest.php @@ -548,10 +548,10 @@ class CacheTest extends CakeTestCase { */ public function testEngineSuccess() { $actual = Cache::engine(); - $this->assertIsA($actual, 'CacheEngine'); + $this->assertInstanceOf('CacheEngine', $actual); $actual = Cache::engine('default'); - $this->assertIsA($actual, 'CacheEngine'); + $this->assertInstanceOf('CacheEngine', $actual); } /** @@ -577,6 +577,8 @@ class CacheTest extends CakeTestCase { )); $actual = Cache::engine('memcached'); + $this->assertInstanceOf('MemcachedEngine', $actual); + $this->assertTrue($actual->add('test_add_key', 'test data', 10)); $this->assertFalse($actual->add('test_add_key', 'test data', 10)); $this->assertTrue($actual->delete('test_add_key')); From dec7f54ecb41b875f10611d66638f43e04067510 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Fri, 11 Nov 2016 21:43:43 +0100 Subject: [PATCH 10/43] Fixed typos --- lib/Cake/TestSuite/CakeTestCase.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Cake/TestSuite/CakeTestCase.php b/lib/Cake/TestSuite/CakeTestCase.php index ab04db6a7..94cf73e73 100644 --- a/lib/Cake/TestSuite/CakeTestCase.php +++ b/lib/Cake/TestSuite/CakeTestCase.php @@ -544,7 +544,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $result * @param mixed $expected * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertEqual($result, $expected, $message = '') { @@ -557,7 +557,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $result * @param mixed $expected * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertNotEqual($result, $expected, $message = '') { @@ -570,7 +570,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $pattern a regular expression * @param string $string the text to be matched * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertPattern($pattern, $string, $message = '') { @@ -583,7 +583,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $actual * @param mixed $expected * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertIdentical($actual, $expected, $message = '') { @@ -596,7 +596,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $actual * @param mixed $expected * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertNotIdentical($actual, $expected, $message = '') { @@ -609,7 +609,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $pattern a regular expression * @param string $string the text to be matched * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertNoPattern($pattern, $string, $message = '') { @@ -619,7 +619,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { /** * assert no errors * - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected function assertNoErrors() { @@ -630,7 +630,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * * @param mixed $expected the name of the Exception or error * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected function expectError($expected = false, $message = '') { @@ -658,7 +658,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param mixed $first * @param mixed $second * @param string $message the text to display if the assertion is not correct - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertReference(&$first, &$second, $message = '') { @@ -671,7 +671,7 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase { * @param string $object * @param string $type * @param string $message - * @deprecated 3.0.0 This is a compatiblity wrapper for 1.x. It will be removed in 3.0 + * @deprecated 3.0.0 This is a compatibility wrapper for 1.x. It will be removed in 3.0 * @return void */ protected static function assertIsA($object, $type, $message = '') { From 58cc9b4596658226a4750c5b1dc4ea25f2daffc4 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Fri, 11 Nov 2016 23:37:23 +0100 Subject: [PATCH 11/43] Make it possible to filter values per method in DboSource::cacheMethod --- lib/Cake/Model/Datasource/DboSource.php | 46 ++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index a73eea8a7..846f932d3 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -60,13 +60,49 @@ class DboSource extends DataSource { public static $methodCache = array(); /** - * Whether or not to cache the results of DboSource::name() and DboSource::conditions() + * Whether or not to cache the results of DboSource::name(), DboSource::fields() and DboSource::conditions() * into the memory cache. Set to false to disable the use of the memory cache. * * @var bool */ public $cacheMethods = true; +/** + * Filters to apply to the results of DboSource::name(), DboSource::fields() and DboSource::conditions(). + * When the filter function for a given method does not return true then the result is not added to the memory cache. + * + * For instance: + * + * ``` + * array( + * // For method fields, do not cache values that contain floats + * 'fields' => function ($value) { + * $hasFloat = preg_grep('/(\d+)?\.\d+/', $value); + * + * return count($hasFloat) === 0; + * }, + * // For method name, do not cache values that have the name floats + * 'name' => function ($value) { + * return preg_match('/^`rating_diff`$/', $value) !== 1; + * } + * ) + * ``` + * + * or + * + * ``` + * array( + * // For method fields, do not cache any values + * 'fields' => function () { + * return false; + * }, + * ) + * ``` + * + * @var array + */ + public $cacheMethodFilters = array(); + /** * Flag to support nested transactions. If it is set to false, you will be able to use * the transaction methods (begin/commit/rollback), but just the global transaction will @@ -786,6 +822,14 @@ class DboSource extends DataSource { if ($value === null) { return (isset(static::$methodCache[$method][$key])) ? static::$methodCache[$method][$key] : null; } + + $methodFilterExists = ( + isset($this->cacheMethodFilters[$method]) && is_callable($this->cacheMethodFilters[$method]) + ); + if ($methodFilterExists && !call_user_func($this->cacheMethodFilters[$method], $value)) { + return $value; + } + $this->_methodCacheChange = true; return static::$methodCache[$method][$key] = $value; } From 15ccf057f4c0ace4be92bb998a1c07f653245155 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Sat, 12 Nov 2016 00:18:13 +0100 Subject: [PATCH 12/43] Make it possible to configure cacheMethodHashAlgo in DboSource --- lib/Cake/Model/Datasource/DboSource.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index a73eea8a7..32081a332 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -51,22 +51,35 @@ class DboSource extends DataSource { public $alias = 'AS '; /** - * Caches result from query parsing operations. Cached results for both DboSource::name() and - * DboSource::conditions() will be stored here. Method caching uses `md5()`. If you have - * problems with collisions, set DboSource::$cacheMethods to false. + * Caches result from query parsing operations. Cached results for both DboSource::name(), DboSource::fields() and + * DboSource::conditions() will be stored here. + * + * Method caching uses `md5` (by default) to construct cache keys. + * If you have problems with collisions, try a different hashing algorithm in DboSource::$cacheMethodHashAlgo or + * set DboSource::$cacheMethods to false. * * @var array */ public static $methodCache = array(); /** - * Whether or not to cache the results of DboSource::name() and DboSource::conditions() + * Whether or not to cache the results of DboSource::name(), DboSource::fields() and DboSource::conditions() * into the memory cache. Set to false to disable the use of the memory cache. * * @var bool */ public $cacheMethods = true; +/** + * Method caching uses `md5` (by default) to construct cache keys. If you have problems with collisions, + * try a different hashing algorithm or set DboSource::$cacheMethods to false. + * + * @var string + * @see http://php.net/manual/en/function.hash-algos.php + * @see http://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + */ + public $cacheMethodHashAlgo = 'md5'; + /** * Flag to support nested transactions. If it is set to false, you will be able to use * the transaction methods (begin/commit/rollback), but just the global transaction will @@ -815,7 +828,7 @@ class DboSource extends DataSource { } return $data; } - $cacheKey = md5($this->startQuote . $data . $this->endQuote); + $cacheKey = hash($this->cacheMethodHashAlgo, $this->startQuote . $data . $this->endQuote); if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { return $return; } @@ -2533,7 +2546,7 @@ class DboSource extends DataSource { $Model->schemaName, $Model->table ); - $cacheKey = md5(serialize($cacheKey)); + $cacheKey = hash($this->cacheMethodHashAlgo, serialize($cacheKey)); if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { return $return; } From 444cf1f16d1b1c8c7f95343d05003c763c613b2e Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 12 Nov 2016 09:41:28 -0500 Subject: [PATCH 13/43] Fix hostname. --- build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index 5a7bca15e..db4fd444e 100644 --- a/build.xml +++ b/build.xml @@ -213,10 +213,10 @@ --> - + - + From e186ffc6d35c70330250042a064263a87864f17a Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 09:42:19 +0100 Subject: [PATCH 14/43] Change cacheMethodHashAlgo to be a method --- lib/Cake/Model/Datasource/DboSource.php | 42 ++++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 32081a332..173afa06f 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -51,35 +51,24 @@ class DboSource extends DataSource { public $alias = 'AS '; /** - * Caches result from query parsing operations. Cached results for both DboSource::name(), DboSource::fields() and - * DboSource::conditions() will be stored here. + * Caches result from query parsing operations. Cached results for both DboSource::name() and DboSource::fields() + * will be stored here. * - * Method caching uses `md5` (by default) to construct cache keys. - * If you have problems with collisions, try a different hashing algorithm in DboSource::$cacheMethodHashAlgo or - * set DboSource::$cacheMethods to false. + * Method caching uses `md5` (by default) to construct cache keys. If you have problems with collisions, + * try a different hashing algorithm by overriding DboSource::cacheMethodHasher or set DboSource::$cacheMethods to false. * * @var array */ public static $methodCache = array(); /** - * Whether or not to cache the results of DboSource::name(), DboSource::fields() and DboSource::conditions() - * into the memory cache. Set to false to disable the use of the memory cache. + * Whether or not to cache the results of DboSource::name() and DboSource::fields() into the memory cache. + * Set to false to disable the use of the memory cache. * * @var bool */ public $cacheMethods = true; -/** - * Method caching uses `md5` (by default) to construct cache keys. If you have problems with collisions, - * try a different hashing algorithm or set DboSource::$cacheMethods to false. - * - * @var string - * @see http://php.net/manual/en/function.hash-algos.php - * @see http://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed - */ - public $cacheMethodHashAlgo = 'md5'; - /** * Flag to support nested transactions. If it is set to false, you will be able to use * the transaction methods (begin/commit/rollback), but just the global transaction will @@ -803,6 +792,21 @@ class DboSource extends DataSource { return static::$methodCache[$method][$key] = $value; } +/** + * Hashes a given value. + * + * Method caching uses `md5` (by default) to construct cache keys. If you have problems with collisions, + * try a different hashing algorithm or set DboSource::$cacheMethods to false. + * + * @param string $value Value to hash + * @return string Hashed value + * @see http://php.net/manual/en/function.hash-algos.php + * @see http://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + */ + public function cacheMethodHasher($value) { + return md5($value); + } + /** * Returns a quoted name of $data for use in an SQL statement. * Strips fields out of SQL functions before quoting. @@ -828,7 +832,7 @@ class DboSource extends DataSource { } return $data; } - $cacheKey = hash($this->cacheMethodHashAlgo, $this->startQuote . $data . $this->endQuote); + $cacheKey = $this->cacheMethodHasher($this->startQuote . $data . $this->endQuote); if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { return $return; } @@ -2546,7 +2550,7 @@ class DboSource extends DataSource { $Model->schemaName, $Model->table ); - $cacheKey = hash($this->cacheMethodHashAlgo, serialize($cacheKey)); + $cacheKey = $this->cacheMethodHasher(serialize($cacheKey)); if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) { return $return; } From 7ffb5c36008935aa92250c413e017a93386d002a Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 10:00:47 +0100 Subject: [PATCH 15/43] Add tests for cacheMethodHasher --- .../Case/Model/Datasource/DboSourceTest.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 911faec5c..b55fb5088 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -737,6 +737,34 @@ class DboSourceTest extends CakeTestCase { $this->assertNull($result); } +/** + * Test that cacheMethodHasher uses md5 by default. + * + * @return void + */ + public function testCacheMethodHasher() { + $name = 'Model.fieldlbqndkezcoapfgirmjsh'; + $actual = $this->testDb->cacheMethodHasher($name); + $expected = '4a45dc9ed52f98c393d04ac424ee5078'; + + $this->assertEquals($expected, $actual); + } + +/** + * Test that cacheMethodHasher can be overridden to use a different hashing algorithm. + * + * @return void + */ + public function testCacheMethodHasherOverridden() { + $testDb = new DboThirdTestSource(); + + $name = 'Model.fieldlbqndkezcoapfgirmjsh'; + $actual = $testDb->cacheMethodHasher($name); + $expected = 'f4441bb8fcbe0944'; + + $this->assertEquals($expected, $actual); + } + /** * Test that rare collisions do not happen with method caching * From 5947c2346bd7232f0e4dfb105d86a3dce3c5992c Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 10:27:51 +0100 Subject: [PATCH 16/43] Fix failing test --- .../Case/Model/Datasource/DboSourceTest.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index b55fb5088..030a8ef4c 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -109,6 +109,23 @@ class DboSecondTestSource extends DboSource { } +/** + * DboThirdTestSource + * + * @package Cake.Test.Case.Model.Datasource + */ +class DboThirdTestSource extends DboSource { + + public function connect($config = array()) { + $this->connected = true; + } + + public function cacheMethodHasher($value) { + return hash('sha1', $value); + } + +} + /** * DboSourceTest class * @@ -760,7 +777,7 @@ class DboSourceTest extends CakeTestCase { $name = 'Model.fieldlbqndkezcoapfgirmjsh'; $actual = $testDb->cacheMethodHasher($name); - $expected = 'f4441bb8fcbe0944'; + $expected = 'beb8b6469359285b7c2865dce0ef743feb16cb71'; $this->assertEquals($expected, $actual); } From 71535d2d2c94b505b688545dc2ad42d90c674132 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 11:15:08 +0100 Subject: [PATCH 17/43] Change cacheMethodFilters to be a method --- lib/Cake/Model/Datasource/DboSource.php | 58 +++++++------------------ 1 file changed, 15 insertions(+), 43 deletions(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 846f932d3..654853d70 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -60,49 +60,13 @@ class DboSource extends DataSource { public static $methodCache = array(); /** - * Whether or not to cache the results of DboSource::name(), DboSource::fields() and DboSource::conditions() + * Whether or not to cache the results of DboSource::name() and DboSource::conditions() * into the memory cache. Set to false to disable the use of the memory cache. * * @var bool */ public $cacheMethods = true; -/** - * Filters to apply to the results of DboSource::name(), DboSource::fields() and DboSource::conditions(). - * When the filter function for a given method does not return true then the result is not added to the memory cache. - * - * For instance: - * - * ``` - * array( - * // For method fields, do not cache values that contain floats - * 'fields' => function ($value) { - * $hasFloat = preg_grep('/(\d+)?\.\d+/', $value); - * - * return count($hasFloat) === 0; - * }, - * // For method name, do not cache values that have the name floats - * 'name' => function ($value) { - * return preg_match('/^`rating_diff`$/', $value) !== 1; - * } - * ) - * ``` - * - * or - * - * ``` - * array( - * // For method fields, do not cache any values - * 'fields' => function () { - * return false; - * }, - * ) - * ``` - * - * @var array - */ - public $cacheMethodFilters = array(); - /** * Flag to support nested transactions. If it is set to false, you will be able to use * the transaction methods (begin/commit/rollback), but just the global transaction will @@ -822,18 +786,26 @@ class DboSource extends DataSource { if ($value === null) { return (isset(static::$methodCache[$method][$key])) ? static::$methodCache[$method][$key] : null; } - - $methodFilterExists = ( - isset($this->cacheMethodFilters[$method]) && is_callable($this->cacheMethodFilters[$method]) - ); - if ($methodFilterExists && !call_user_func($this->cacheMethodFilters[$method], $value)) { + if (!$this->cacheMethodFilter($method, $key, $value)) { return $value; } - $this->_methodCacheChange = true; return static::$methodCache[$method][$key] = $value; } +/** + * Filters to apply to the results of `name` and `fields`. When the filter for a given method does not return `true` + * then the result is not added to the memory cache. + * + * @param string $method Name of the method being cached. + * @param string $key The key name for the cache operation. + * @param mixed $value The value to cache into memory. + * @return bool Whether or not to cache + */ + public function cacheMethodFilter($method, $key, $value) { + return true; + } + /** * Returns a quoted name of $data for use in an SQL statement. * Strips fields out of SQL functions before quoting. From 1952d2ee1774591a38051e4f2b3440ab8d31656a Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 11:44:35 +0100 Subject: [PATCH 18/43] Add tests for cacheMethodFilter --- lib/Cake/Model/Datasource/DboSource.php | 31 +++++++++++++++++++ .../Case/Model/Datasource/DboSourceTest.php | 28 +++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 654853d70..9402bdc21 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -797,6 +797,37 @@ class DboSource extends DataSource { * Filters to apply to the results of `name` and `fields`. When the filter for a given method does not return `true` * then the result is not added to the memory cache. * + * Some examples: + * + * ``` + * // For method fields, do not cache values that contain floats + * if ($method === 'fields') { + * $hasFloat = preg_grep('/(\d+)?\.\d+/', $value); + * + * return count($hasFloat) === 0; + * } + * + * return true; + * ``` + * + * ``` + * // For method name, do not cache values that have the name created + * if ($method === 'name') { + * return preg_match('/^`created`$/', $value) !== 1; + * } + * + * return true; + * ``` + * + * ``` + * // For method name, do not cache values that have the key 472551d38e1f8bbc78d7dfd28106166f + * if ($key === '472551d38e1f8bbc78d7dfd28106166f') { + * return false; + * } + * + * return true; + * ``` + * * @param string $method Name of the method being cached. * @param string $key The key name for the cache operation. * @param mixed $value The value to cache into memory. diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 911faec5c..9be7e90c8 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -737,6 +737,34 @@ class DboSourceTest extends CakeTestCase { $this->assertNull($result); } +/** + * Test that cacheMethodFilter does not filter by default. + * + * @return void + */ + public function testCacheMethodFilter() { + $method = 'name'; + $key = '49d9207adfce6df1dd3ee8c30c434414'; + $value = '`menus`'; + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'fields'; + $key = '2b57253ab1fffb3e95fa4f95299220b1'; + $value = ["`Menu`.`id`", "`Menu`.`name`"]; + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'non-existing'; + $key = ''; + $value = '``'; + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + } + /** * Test that rare collisions do not happen with method caching * From 936b9924b3c1f00b53c1745c4c5cd1dc16bd4d61 Mon Sep 17 00:00:00 2001 From: Mischa ter Smitten Date: Mon, 14 Nov 2016 12:04:36 +0100 Subject: [PATCH 19/43] Add tests for overridden cacheMethodFilter --- .../Case/Model/Datasource/DboSourceTest.php | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 9be7e90c8..1ae79694e 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -109,6 +109,35 @@ class DboSecondTestSource extends DboSource { } +/** + * DboFourthTestSource + * + * @package Cake.Test.Case.Model.Datasource + */ +class DboFourthTestSource extends DboSource { + + public function connect($config = array()) { + $this->connected = true; + } + + public function cacheMethodFilter($method, $key, $value) { + if ($method === 'name') { + if ($value === '`menus`') { + return false; + } elseif ($key === '1fca740733997f1ebbedacfc7678592a') { + return false; + } + } elseif ($method === 'fields') { + $endsWithName = preg_grep('/`name`$/', $value); + + return count($endsWithName) === 0; + } + + return true; + } + +} + /** * DboSourceTest class * @@ -752,7 +781,7 @@ class DboSourceTest extends CakeTestCase { $method = 'fields'; $key = '2b57253ab1fffb3e95fa4f95299220b1'; - $value = ["`Menu`.`id`", "`Menu`.`name`"]; + $value = array("`Menu`.`id`", "`Menu`.`name`"); $actual = $this->testDb->cacheMethodFilter($method, $key, $value); $this->assertTrue($actual); @@ -765,6 +794,50 @@ class DboSourceTest extends CakeTestCase { $this->assertTrue($actual); } +/** + * Test that cacheMethodFilter can be overridden to do actual filtering. + * + * @return void + */ + public function testCacheMethodFilterOverridden() { + $testDb = new DboFourthTestSource(); + + $method = 'name'; + $key = '49d9207adfce6df1dd3ee8c30c434414'; + $value = '`menus`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'name'; + $key = '1fca740733997f1ebbedacfc7678592a'; + $value = '`Menu`.`id`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'fields'; + $key = '2b57253ab1fffb3e95fa4f95299220b1'; + $value = array("`Menu`.`id`", "`Menu`.`name`"); + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'name'; + $key = 'd2bc458620afb092c61ab4383b7475e0'; + $value = '`Menu`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'non-existing'; + $key = ''; + $value = '``'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + } + /** * Test that rare collisions do not happen with method caching * From 5c184190c5a71637a273d41e3271fef7a53ed177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 17 Nov 2016 14:55:01 +0100 Subject: [PATCH 20/43] Improve doc block --- lib/Cake/Utility/Security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index be128e64a..1068bdfdf 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -171,7 +171,7 @@ class Security { /** * Get random bytes from a secure source. * - * This method will fall back to an insecure source an trigger a warning + * This method will fall back to an insecure source and trigger a warning, * if it cannot find a secure source of random data. * * @param int $length The number of bytes you want. From 66363e6bea97cfa052e5c9653c8402c5c480f0b0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 19 Nov 2016 10:02:09 -0400 Subject: [PATCH 21/43] Add tests for #9766 I'm not able to reproduce incorrect aliases coming out of ClassRegistry. As reported. --- .../Test/Case/Utility/ClassRegistryTest.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php index 09e54959f..d6d70774f 100644 --- a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php +++ b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php @@ -147,7 +147,7 @@ class ClassRegistryTest extends CakeTestCase { $this->assertSame($Tag, $TagCopy); $NewTag = ClassRegistry::init(array('class' => 'RegisterArticleTag', 'alias' => 'NewTag')); - $this->assertInstanceOf('RegisterArticleTag', $Tag); + $this->assertInstanceOf('RegisterArticleTag', $NewTag); $NewTagCopy = ClassRegistry::init(array('class' => 'RegisterArticleTag', 'alias' => 'NewTag')); @@ -182,6 +182,24 @@ class ClassRegistryTest extends CakeTestCase { $this->assertEquals('ParentCategory', $ParentCategory->alias); } +/** + * Test that init() can make models with alias set properly + * + * @return void + */ + public function testAddModelWithAlias() + { + $tag = ClassRegistry::init(array('class' => 'RegisterArticleTag', 'alias' => 'NewTag')); + $this->assertInstanceOf('RegisterArticleTag', $tag); + $this->assertSame('NewTag', $tag->alias); + $this->assertSame('RegisterArticleTag', $tag->name); + + $newTag = ClassRegistry::init(array('class' => 'RegisterArticleTag', 'alias' => 'OtherTag')); + $this->assertInstanceOf('RegisterArticleTag', $tag); + $this->assertSame('OtherTag', $newTag->alias); + $this->assertSame('RegisterArticleTag', $newTag->name); + } + /** * testClassRegistryFlush method * From 71b7d6211bb9660bc34423bace5146f76cf2427d Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 19 Nov 2016 22:30:18 -0400 Subject: [PATCH 22/43] Fix AclNode constructor. It should forward the settings from ClassRegistry::init() so that aliases can be customized as needed. Refs #9766 --- lib/Cake/Model/AclNode.php | 4 ++-- lib/Cake/Test/Case/Utility/ClassRegistryTest.php | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Model/AclNode.php b/lib/Cake/Model/AclNode.php index 1080b9a22..4d62dea87 100644 --- a/lib/Cake/Model/AclNode.php +++ b/lib/Cake/Model/AclNode.php @@ -40,12 +40,12 @@ class AclNode extends Model { /** * Constructor */ - public function __construct() { + public function __construct($id = false, $table = null, $ds = null) { $config = Configure::read('Acl.database'); if (isset($config)) { $this->useDbConfig = $config; } - parent::__construct(); + parent::__construct($id, $table, $ds); } /** diff --git a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php index d6d70774f..fc3fdb18b 100644 --- a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php +++ b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php @@ -200,6 +200,19 @@ class ClassRegistryTest extends CakeTestCase { $this->assertSame('RegisterArticleTag', $newTag->name); } +/** + * Test that init() can make the Aco models with alias set properly + * + * @return void + */ + public function testAddModelWithAliasAco() + { + $aco = ClassRegistry::init(array('class' => 'Aco', 'alias' => 'CustomAco')); + $this->assertInstanceOf('Aco', $aco); + $this->assertSame('Aco', $aco->name); + $this->assertSame('CustomAco', $aco->alias); + } + /** * testClassRegistryFlush method * From e057b5572cfb94773b6a33f728b3369c1d6b4d4f Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 21 Nov 2016 20:51:12 -0500 Subject: [PATCH 23/43] Fix PHPCS. --- lib/Cake/Model/AclNode.php | 5 +++++ lib/Cake/Test/Case/Utility/ClassRegistryTest.php | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Model/AclNode.php b/lib/Cake/Model/AclNode.php index 4d62dea87..a689ffe0e 100644 --- a/lib/Cake/Model/AclNode.php +++ b/lib/Cake/Model/AclNode.php @@ -39,6 +39,11 @@ class AclNode extends Model { /** * Constructor + * + * @param bool|int|string|array $id Set this ID for this model on startup, + * can also be an array of options, see above. + * @param string $table Name of database table to use. + * @param string $ds DataSource connection name. */ public function __construct($id = false, $table = null, $ds = null) { $config = Configure::read('Acl.database'); diff --git a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php index fc3fdb18b..8587b3ef3 100644 --- a/lib/Cake/Test/Case/Utility/ClassRegistryTest.php +++ b/lib/Cake/Test/Case/Utility/ClassRegistryTest.php @@ -187,8 +187,7 @@ class ClassRegistryTest extends CakeTestCase { * * @return void */ - public function testAddModelWithAlias() - { + public function testAddModelWithAlias() { $tag = ClassRegistry::init(array('class' => 'RegisterArticleTag', 'alias' => 'NewTag')); $this->assertInstanceOf('RegisterArticleTag', $tag); $this->assertSame('NewTag', $tag->alias); @@ -205,8 +204,7 @@ class ClassRegistryTest extends CakeTestCase { * * @return void */ - public function testAddModelWithAliasAco() - { + public function testAddModelWithAliasAco() { $aco = ClassRegistry::init(array('class' => 'Aco', 'alias' => 'CustomAco')); $this->assertInstanceOf('Aco', $aco); $this->assertSame('Aco', $aco->name); From bbb87b3e87d751fef6c2d202fc38a975a5c95673 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 26 Nov 2016 10:38:28 -0500 Subject: [PATCH 24/43] Use null instead of false for failure. null is better to indicate that a thing doesn't exist. --- lib/Cake/Cache/Cache.php | 5 ++--- lib/Cake/Test/Case/Cache/CacheTest.php | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/Cake/Cache/Cache.php b/lib/Cake/Cache/Cache.php index d2286960e..e9f27bed3 100644 --- a/lib/Cake/Cache/Cache.php +++ b/lib/Cake/Cache/Cache.php @@ -621,14 +621,13 @@ class Cache { * Fetch the engine attached to a specific configuration name. * * @param string $config Optional string configuration name to get an engine for. Defaults to 'default'. - * @return bool|CacheEngine False if the engine has not been initialized else the engine + * @return null|CacheEngine Null if the engine has not been initialized or the engine. */ public static function engine($config = 'default') { if (self::isInitialized($config)) { return self::$_engines[$config]; } - return false; + return null; } - } diff --git a/lib/Cake/Test/Case/Cache/CacheTest.php b/lib/Cake/Test/Case/Cache/CacheTest.php index 725e576b3..745efab19 100644 --- a/lib/Cake/Test/Case/Cache/CacheTest.php +++ b/lib/Cake/Test/Case/Cache/CacheTest.php @@ -593,11 +593,10 @@ class CacheTest extends CakeTestCase { */ public function testEngineFailure() { $actual = Cache::engine('some_config_that_does_not_exist'); - $this->assertFalse($actual); + $this->assertNull($actual); Configure::write('Cache.disable', true); $actual = Cache::engine(); - $this->assertFalse($actual); + $this->assertNull($actual); } - } From f9d2a52152813fdf9cd3a719b63ccb5d9c3791dd Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Sun, 27 Nov 2016 01:25:01 +0900 Subject: [PATCH 25/43] Revert "Remove dead code" This reverts commit bf908762db80c39eb22a73a2dbde42c018e1b676. --- lib/Cake/Console/ShellDispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index bb2095418..4b8a077e6 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -139,7 +139,7 @@ class ShellDispatcher { if (!defined('TMP') && !is_dir(APP . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); } - + $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php'); require CORE_PATH . 'Cake' . DS . 'bootstrap.php'; if (!file_exists(APP . 'Config' . DS . 'core.php')) { From 02df9ff72ef54962b618a8f967c1b39c84dbf34e Mon Sep 17 00:00:00 2001 From: Mark Sch Date: Sat, 26 Nov 2016 18:10:37 +0100 Subject: [PATCH 26/43] Add a note about $boot --- lib/Cake/Console/ShellDispatcher.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php index 4b8a077e6..9882dd9c9 100644 --- a/lib/Cake/Console/ShellDispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -139,6 +139,8 @@ class ShellDispatcher { if (!defined('TMP') && !is_dir(APP . 'tmp')) { define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS); } + + // $boot is used by Cake/bootstrap.php file $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php'); require CORE_PATH . 'Cake' . DS . 'bootstrap.php'; From 74c2ded8725eaa110f489d8dc51e9ac2221747c1 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Sun, 27 Nov 2016 18:03:32 +0900 Subject: [PATCH 27/43] Fix directory traversal of .ctp files --- app/Controller/PagesController.php | 6 +++++- .../skel/Controller/PagesController.php | 4 ++++ .../Case/Controller/PagesControllerTest.php | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/Controller/PagesController.php b/app/Controller/PagesController.php index 97b782ac7..f4bc815f9 100644 --- a/app/Controller/PagesController.php +++ b/app/Controller/PagesController.php @@ -41,8 +41,9 @@ class PagesController extends AppController { * Displays a view * * @return void + * @throws ForbiddenException When a directory traversal attempt. * @throws NotFoundException When the view file could not be found - * or MissingViewException in debug mode. + * or MissingViewException in debug mode. */ public function display() { $path = func_get_args(); @@ -51,6 +52,9 @@ class PagesController extends AppController { if (!$count) { return $this->redirect('/'); } + if (in_array('..', $path, true) || in_array('.', $path, true)) { + throw new ForbiddenException(); + } $page = $subpage = $title_for_layout = null; if (!empty($path[0])) { diff --git a/lib/Cake/Console/Templates/skel/Controller/PagesController.php b/lib/Cake/Console/Templates/skel/Controller/PagesController.php index eb023a573..c97b9a281 100644 --- a/lib/Cake/Console/Templates/skel/Controller/PagesController.php +++ b/lib/Cake/Console/Templates/skel/Controller/PagesController.php @@ -32,6 +32,7 @@ class PagesController extends AppController { * Displays a view * * @return void + * @throws ForbiddenException When a directory traversal attempt. * @throws NotFoundException When the view file could not be found * or MissingViewException in debug mode. */ @@ -42,6 +43,9 @@ class PagesController extends AppController { if (!$count) { return $this->redirect('/'); } + if (in_array('..', $path, true) || in_array('.', $path, true)) { + throw new ForbiddenException(); + } $page = $subpage = $title_for_layout = null; if (!empty($path[0])) { diff --git a/lib/Cake/Test/Case/Controller/PagesControllerTest.php b/lib/Cake/Test/Case/Controller/PagesControllerTest.php index 402a27a54..887c88960 100644 --- a/lib/Cake/Test/Case/Controller/PagesControllerTest.php +++ b/lib/Cake/Test/Case/Controller/PagesControllerTest.php @@ -75,4 +75,21 @@ class PagesControllerTest extends CakeTestCase { $Pages = new PagesController(new CakeRequest(null, false), new CakeResponse()); $Pages->display('non_existing_page'); } + +/** + * Test directory traversal protection + * + * @expectedException ForbiddenException + * @expectedExceptionCode 403 + * @return void + */ + public function testDirectoryTraversalProtection() { + App::build(array( + 'View' => array( + CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS + ) + )); + $Pages = new PagesController(new CakeRequest(null, false), new CakeResponse()); + $Pages->display('..', 'Posts', 'index'); + } } From 410df003e625a30868e33327dfb966b9bb059946 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 27 Nov 2016 21:25:11 -0500 Subject: [PATCH 28/43] Update version number to 2.9.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 4e65d0110..594316744 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license http://www.opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.9.2 +2.9.3 From 75bb30f6b2205fa37ea249c6a52e788043f44b58 Mon Sep 17 00:00:00 2001 From: Henrik Gemal Date: Thu, 1 Dec 2016 12:39:47 +0100 Subject: [PATCH 29/43] add new locales fixes #9825 --- lib/Cake/I18n/L10n.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Cake/I18n/L10n.php b/lib/Cake/I18n/L10n.php index a87be16c0..fe84bc9fd 100644 --- a/lib/Cake/I18n/L10n.php +++ b/lib/Cake/I18n/L10n.php @@ -269,6 +269,7 @@ class L10n { 'hi' => array('language' => 'Hindi', 'locale' => 'hin', 'localeFallback' => 'hin', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hr' => array('language' => 'Croatian', 'locale' => 'hrv', 'localeFallback' => 'hrv', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hu' => array('language' => 'Hungarian', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'hu-hu' => array('language' => 'Hungarian (Hungary)', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'), 'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'), 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'), @@ -286,6 +287,7 @@ class L10n { 'li' => array('language' => 'Limburgish', 'locale' => 'lim', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'), 'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'), 'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'), + 'lv-lv' => array('language' => 'Latvian (Latvia)', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mkd', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'), 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mkd', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ms' => array('language' => 'Malaysian', 'locale' => 'msa', 'localeFallback' => 'msa', 'charset' => 'utf-8', 'direction' => 'ltr'), From 27f951fb41ce10ac14180c41a40e90a5fa1076bb Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 3 Dec 2016 14:10:47 -0500 Subject: [PATCH 30/43] Don't emit errors when operating on corrupted cookie data. When deleting from corrupted cookie data, there shouldn't be any errors. Refs #9779 --- .../Controller/Component/CookieComponent.php | 9 ++++++--- .../Component/CookieComponentTest.php | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index 2bb75194d..9768d5a99 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -283,8 +283,11 @@ class CookieComponent extends Component { return null; } - if (!empty($names[1]) && is_array($this->_values[$this->name][$key])) { - return Hash::get($this->_values[$this->name][$key], $names[1]); + 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]; } @@ -336,7 +339,7 @@ class CookieComponent extends Component { return; } $names = explode('.', $key, 2); - if (isset($this->_values[$this->name][$names[0]])) { + 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) . ']'); diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index 7d9365c84..e3a8f0970 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -451,6 +451,25 @@ class CookieComponentTest extends CakeTestCase { $this->assertNull($data); } +/** + * test delete() on corrupted/truncated cookie data. + * + * @return void + */ + public function testDeleteCorruptedCookieData() { + $this->Cookie->type('aes'); + $this->Cookie->key = sha1('some bad key'); + + $data = $this->_implode(array('name' => 'jill', 'age' => 24)); + // Corrupt the cookie data by slicing some bytes off. + $_COOKIE['CakeTestCookie'] = array( + 'BadData' => substr(Security::encrypt($data, $this->Cookie->key), 0, -5) + ); + + $this->assertNull($this->Cookie->delete('BadData.name')); + $this->assertNull($this->Cookie->read('BadData.name')); + } + /** * testReadingCookieArray * From 934bb00b366cec6201e5f29138cca675e000a94d Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 3 Dec 2016 14:14:57 -0500 Subject: [PATCH 31/43] Add tests showing recent changes fix #9784 --- .../Component/CookieComponentTest.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index e3a8f0970..467e7a225 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -153,6 +153,24 @@ class CookieComponentTest extends CakeTestCase { $this->assertEquals($expected, $data); } +/** + * test read operations on corrupted cookie data. + * + * @return void + */ + public function testReadCorruptedCookieData() { + $this->Cookie->type('aes'); + $this->Cookie->key = sha1('some bad key'); + + $data = $this->_implode(array('name' => 'jill', 'age' => 24)); + // Corrupt the cookie data by slicing some bytes off. + $_COOKIE['CakeTestCookie'] = array( + 'BadData' => substr(Security::encrypt($data, $this->Cookie->key), 0, -5) + ); + $this->assertFalse($this->Cookie->check('BadData.name'), 'Key does not exist'); + $this->assertNull($this->Cookie->read('BadData.name'), 'Key does not exist'); + } + /** * testReadPlainCookieData * @@ -169,6 +187,19 @@ class CookieComponentTest extends CakeTestCase { $this->assertEquals($expected, $data); } +/** + * test read array keys from string data. + * + * @return void + */ + public function testReadNestedDataFromStrings() { + $_COOKIE['CakeTestCookie'] = array( + 'User' => 'bad data' + ); + $this->assertFalse($this->Cookie->check('User.name'), 'No key'); + $this->assertNull($this->Cookie->read('User.name'), 'No key'); + } + /** * test read() after switching the cookie name. * From b7481096c8921801d3632d16343150a17e349b35 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Sun, 4 Dec 2016 20:06:24 +0900 Subject: [PATCH 32/43] Fix redirectUrl issue when loginRedirect is empty Fixes #9819 --- lib/Cake/Controller/Component/AuthComponent.php | 3 +++ .../Case/Controller/Component/AuthComponentTest.php | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php index 3e62e2cc9..29a0e49b3 100644 --- a/lib/Cake/Controller/Component/AuthComponent.php +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -742,6 +742,9 @@ class AuthComponent extends Component { if (Router::normalize($redir) === Router::normalize($this->loginAction)) { $redir = $this->loginRedirect; + if (!$redir) { + $redir = '/'; + } } } elseif ($this->loginRedirect) { $redir = $this->loginRedirect; diff --git a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php index 4514e5ec8..e8f674e77 100644 --- a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php @@ -1652,6 +1652,19 @@ class AuthComponentTest extends CakeTestCase { Router::reload(); } +/** + * Test that redirectUrl() returns '/' if loginRedirect is empty + * and Auth.redirect is the login page. + * + * @return void + */ + public function testRedirectUrlWithoutLoginRedirect() { + $this->Auth->Session->write('Auth.redirect', '/users/login'); + $this->Auth->request->addParams(Router::parse('/users/login')); + $result = $this->Auth->redirectUrl(); + $this->assertEquals('/', $result); + } + /** * test password hashing * From 26731b93bf972c041f1c4bc9a1816fcbafd48eaa Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Sun, 4 Dec 2016 21:55:29 +0900 Subject: [PATCH 33/43] Use ternary operator --- lib/Cake/Controller/Component/AuthComponent.php | 5 +---- .../Test/Case/Controller/Component/AuthComponentTest.php | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php index 29a0e49b3..54e7034ab 100644 --- a/lib/Cake/Controller/Component/AuthComponent.php +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -741,10 +741,7 @@ class AuthComponent extends Component { $this->Session->delete('Auth.redirect'); if (Router::normalize($redir) === Router::normalize($this->loginAction)) { - $redir = $this->loginRedirect; - if (!$redir) { - $redir = '/'; - } + $redir = $this->loginRedirect ?: '/'; } } elseif ($this->loginRedirect) { $redir = $this->loginRedirect; diff --git a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php index e8f674e77..5da15d1e9 100644 --- a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php @@ -1659,6 +1659,7 @@ class AuthComponentTest extends CakeTestCase { * @return void */ public function testRedirectUrlWithoutLoginRedirect() { + $this->Auth->loginRedirect = null; $this->Auth->Session->write('Auth.redirect', '/users/login'); $this->Auth->request->addParams(Router::parse('/users/login')); $result = $this->Auth->redirectUrl(); From caaf7488839307d3e5e0a22d65e5350db355951d Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 5 Dec 2016 09:22:48 -0500 Subject: [PATCH 34/43] Add PHP7.1 to test matrix. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b43db1d25..2070d62da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 env: - DB=mysql @@ -22,7 +23,7 @@ matrix: - php: 5.4 env: DB=sqlite - - php: 5.4 + - php: 7.0 env: PHPCS=1 From e3221b1c383fb7f99f8aad0945aa303f2321d3b0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 5 Dec 2016 16:14:33 -0500 Subject: [PATCH 35/43] Fix errors in php7.1 * The constructor of errors has changed in PHP 7.1 * mcrypt is no longer available in PHP 7.1 by default. --- .../Controller/Component/Auth/ControllerAuthorizeTest.php | 5 ++--- .../Test/Case/Controller/Component/CookieComponentTest.php | 1 + lib/Cake/Test/Case/Core/ConfigureTest.php | 5 ++--- lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php | 5 ++--- lib/Cake/Test/Case/Model/ModelValidationTest.php | 5 ++--- lib/Cake/Test/Case/Utility/SecurityTest.php | 5 +++++ lib/Cake/View/View.php | 2 +- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php index b0f554bf4..ce92d6b14 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php @@ -47,15 +47,14 @@ class ControllerAuthorizeTest extends CakeTestCase { /** * testControllerTypeError * - * @expectedException PHPUnit_Framework_Error - * @throws PHPUnit_Framework_Error * @return void */ public function testControllerTypeError() { try { $this->auth->controller(new StdClass()); + $this->fail('No exception thrown'); } catch (Throwable $t) { - throw new PHPUnit_Framework_Error($t); + $this->assertTrue(true, 'Exception was raised'); } } diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index 7d9365c84..18b70bafc 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -207,6 +207,7 @@ class CookieComponentTest extends CakeTestCase { * @return void */ public function testWriteWithFalseyValue() { + $this->skipIf(!extension_loaded('mcrypt'), 'No Mcrypt, skipping.'); $this->Cookie->type('aes'); $this->Cookie->key = 'qSI232qs*&sXOw!adre@34SAv!@*(XSL#$%)asGb$@11~_+!@#HKis~#^'; diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php index 6a1b4bbbd..d8d3e33b2 100644 --- a/lib/Cake/Test/Case/Core/ConfigureTest.php +++ b/lib/Cake/Test/Case/Core/ConfigureTest.php @@ -449,8 +449,6 @@ class ConfigureTest extends CakeTestCase { /** * test reader() throwing exceptions on missing interface. * - * @expectedException PHPUnit_Framework_Error - * @throws PHPUnit_Framework_Error * @return void */ public function testReaderExceptionOnIncorrectClass() { @@ -458,8 +456,9 @@ class ConfigureTest extends CakeTestCase { try { Configure::config('test', $reader); + $this->fail('No error raised'); } catch (Throwable $t) { - throw new PHPUnit_Framework_Error($t); + $this->assertTrue(true, 'TypeError raised'); } } diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index ee9c0f57e..6dc888223 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -2908,15 +2908,14 @@ SQL; /** * testDropSchemaNoSchema method * - * @expectedException PHPUnit_Framework_Error - * @throws PHPUnit_Framework_Error * @return void */ public function testDropSchemaNoSchema() { try { $this->Dbo->dropSchema(null); + $this->fail('No exception'); } catch (Throwable $t) { - throw new PHPUnit_Framework_Error($t); + $this->assertTrue(true, 'Exception raised'); } } diff --git a/lib/Cake/Test/Case/Model/ModelValidationTest.php b/lib/Cake/Test/Case/Model/ModelValidationTest.php index 1636f7a21..7f2a73e43 100644 --- a/lib/Cake/Test/Case/Model/ModelValidationTest.php +++ b/lib/Cake/Test/Case/Model/ModelValidationTest.php @@ -2223,15 +2223,14 @@ class ModelValidationTest extends BaseModelTest { /** * Test that type hint exception is thrown * - * @expectedException PHPUnit_Framework_Error - * @throws PHPUnit_Framework_Error * @return void */ public function testValidatorTypehintException() { try { new ModelValidator('asdasds'); + $this->fail('No exeption raised'); } catch (Throwable $t) { - throw new PHPUnit_Framework_Error($t); + $this->assertTrue(true, 'An error/exception was raised'); } } diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php index 10aa1d4c3..fed0dce1f 100644 --- a/lib/Cake/Test/Case/Utility/SecurityTest.php +++ b/lib/Cake/Test/Case/Utility/SecurityTest.php @@ -328,6 +328,7 @@ class SecurityTest extends CakeTestCase { * @return void */ public function testEncryptDecrypt() { + $this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed'); $txt = 'The quick brown fox'; $key = 'This key is longer than 32 bytes long.'; $result = Security::encrypt($txt, $key); @@ -342,6 +343,7 @@ class SecurityTest extends CakeTestCase { * @return void */ public function testDecryptKeyFailure() { + $this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed'); $txt = 'The quick brown fox'; $key = 'This key is longer than 32 bytes long.'; Security::encrypt($txt, $key); @@ -356,6 +358,7 @@ class SecurityTest extends CakeTestCase { * @return void */ public function testDecryptHmacFailure() { + $this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed'); $txt = 'The quick brown fox'; $key = 'This key is quite long and works well.'; $salt = 'this is a delicious salt!'; @@ -372,6 +375,7 @@ class SecurityTest extends CakeTestCase { * @return void */ public function testDecryptHmacSaltFailure() { + $this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed'); $txt = 'The quick brown fox'; $key = 'This key is quite long and works well.'; $salt = 'this is a delicious salt!'; @@ -400,6 +404,7 @@ class SecurityTest extends CakeTestCase { * @return void */ public function testEncryptDecryptFalseyData() { + $this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed'); $key = 'This is a key that is long enough to be ok.'; $result = Security::encrypt('', $key); diff --git a/lib/Cake/View/View.php b/lib/Cake/View/View.php index 4d28993e0..9c643fdc1 100644 --- a/lib/Cake/View/View.php +++ b/lib/Cake/View/View.php @@ -564,7 +564,7 @@ class View extends CakeObject { $type = $response->mapType($response->type()); if (Configure::read('debug') > 0 && $type === 'html') { - echo ""; + echo ""; } $out = ob_get_clean(); From 0a2a400ea42d73d4f9d111e5485646dfc91630b4 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 6 Dec 2016 21:20:32 -0500 Subject: [PATCH 36/43] Fix type error tests to work in PHP5 & PHP7.1 Catch the TypeErrors that are raised and make the match the PHP5 behavior of a converted error. --- .../Controller/Component/Auth/ControllerAuthorizeTest.php | 5 +++-- lib/Cake/Test/Case/Core/ConfigureTest.php | 6 +++--- lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php | 5 +++-- lib/Cake/Test/Case/Model/ModelValidationTest.php | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php index ce92d6b14..3ed011262 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php @@ -47,14 +47,15 @@ class ControllerAuthorizeTest extends CakeTestCase { /** * testControllerTypeError * + * @expectedException PHPUnit_Framework_Error * @return void */ public function testControllerTypeError() { try { $this->auth->controller(new StdClass()); $this->fail('No exception thrown'); - } catch (Throwable $t) { - $this->assertTrue(true, 'Exception was raised'); + } catch (TypeError $e) { + throw new PHPUnit_Framework_Error('Raised an error', 100, __FILE__, __LINE__); } } diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php index d8d3e33b2..8a738fd30 100644 --- a/lib/Cake/Test/Case/Core/ConfigureTest.php +++ b/lib/Cake/Test/Case/Core/ConfigureTest.php @@ -449,6 +449,7 @@ class ConfigureTest extends CakeTestCase { /** * test reader() throwing exceptions on missing interface. * + * @expectedException PHPUnit_Framework_Error * @return void */ public function testReaderExceptionOnIncorrectClass() { @@ -456,9 +457,8 @@ class ConfigureTest extends CakeTestCase { try { Configure::config('test', $reader); - $this->fail('No error raised'); - } catch (Throwable $t) { - $this->assertTrue(true, 'TypeError raised'); + } catch (TypeError $e) { + throw new PHPUnit_Framework_Error('Raised an error', 100, __FILE__, __LINE__); } } diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index 6dc888223..e4c28cae0 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -2908,14 +2908,15 @@ SQL; /** * testDropSchemaNoSchema method * + * @expectedException PHPUnit_Framework_Error * @return void */ public function testDropSchemaNoSchema() { try { $this->Dbo->dropSchema(null); $this->fail('No exception'); - } catch (Throwable $t) { - $this->assertTrue(true, 'Exception raised'); + } catch (TypeError $e) { + throw new PHPUnit_Framework_Error('Raised an error', 100, __FILE__, __LINE__); } } diff --git a/lib/Cake/Test/Case/Model/ModelValidationTest.php b/lib/Cake/Test/Case/Model/ModelValidationTest.php index 7f2a73e43..f00c1a250 100644 --- a/lib/Cake/Test/Case/Model/ModelValidationTest.php +++ b/lib/Cake/Test/Case/Model/ModelValidationTest.php @@ -2223,14 +2223,15 @@ class ModelValidationTest extends BaseModelTest { /** * Test that type hint exception is thrown * + * @expectedException PHPUnit_Framework_Error * @return void */ public function testValidatorTypehintException() { try { new ModelValidator('asdasds'); $this->fail('No exeption raised'); - } catch (Throwable $t) { - $this->assertTrue(true, 'An error/exception was raised'); + } catch (TypeError $e) { + throw new PHPUnit_Framework_Error('Raised an error', 100, __FILE__, __LINE__); } } From 12cdc247ace5e2921d297d6ffd026b1bc306d0c3 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 7 Dec 2016 00:38:55 -0500 Subject: [PATCH 37/43] Fix PHPCS errors. --- .../Case/Controller/Component/Auth/ControllerAuthorizeTest.php | 1 + lib/Cake/Test/Case/Core/ConfigureTest.php | 1 + lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php | 1 + lib/Cake/Test/Case/Model/ModelValidationTest.php | 1 + 4 files changed, 4 insertions(+) diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php index 3ed011262..6bf7b1026 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php @@ -49,6 +49,7 @@ class ControllerAuthorizeTest extends CakeTestCase { * * @expectedException PHPUnit_Framework_Error * @return void + * @throws PHPUnit_Framework_Error */ public function testControllerTypeError() { try { diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php index 8a738fd30..d4457e21b 100644 --- a/lib/Cake/Test/Case/Core/ConfigureTest.php +++ b/lib/Cake/Test/Case/Core/ConfigureTest.php @@ -451,6 +451,7 @@ class ConfigureTest extends CakeTestCase { * * @expectedException PHPUnit_Framework_Error * @return void + * @throws PHPUnit_Framework_Error */ public function testReaderExceptionOnIncorrectClass() { $reader = new StdClass(); diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index e4c28cae0..9577bad34 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -2910,6 +2910,7 @@ SQL; * * @expectedException PHPUnit_Framework_Error * @return void + * @throws PHPUnit_Framework_Error */ public function testDropSchemaNoSchema() { try { diff --git a/lib/Cake/Test/Case/Model/ModelValidationTest.php b/lib/Cake/Test/Case/Model/ModelValidationTest.php index f00c1a250..3eee85c28 100644 --- a/lib/Cake/Test/Case/Model/ModelValidationTest.php +++ b/lib/Cake/Test/Case/Model/ModelValidationTest.php @@ -2225,6 +2225,7 @@ class ModelValidationTest extends BaseModelTest { * * @expectedException PHPUnit_Framework_Error * @return void + * @throws PHPUnit_Framework_Error */ public function testValidatorTypehintException() { try { From edfda47cf4692a60fcfed910c6f10f2ac5e1cf05 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 10 Dec 2016 08:47:13 -0500 Subject: [PATCH 38/43] Fix missing HTML encoding in Debugger Fix missing HTML encoding when error messages contain HTML. This can happen when user data is used as an offset in an array in an unchecked way. Thanks to Teppei Fukuda for reporting this issue via the responsible security disclosure process. --- lib/Cake/Test/Case/Utility/DebuggerTest.php | 18 ++++++++++++++++++ lib/Cake/Utility/Debugger.php | 1 + 2 files changed, 19 insertions(+) diff --git a/lib/Cake/Test/Case/Utility/DebuggerTest.php b/lib/Cake/Test/Case/Utility/DebuggerTest.php index 4179a7636..3528ce5f7 100644 --- a/lib/Cake/Test/Case/Utility/DebuggerTest.php +++ b/lib/Cake/Test/Case/Utility/DebuggerTest.php @@ -155,6 +155,24 @@ class DebuggerTest extends CakeTestCase { $this->assertContains('$wrong = ''', $result[3], 'Context should be HTML escaped.'); } +/** + * test encodes error messages + * + * @return void + */ + public function testOutputEncodeDescription() { + set_error_handler('Debugger::showError'); + $this->_restoreError = true; + + ob_start(); + $a = 'things'; + $b = $a['']; + $result = ob_get_clean(); + + $this->assertNotContains('']; $result = ob_get_clean(); From 4d77cb059dfd4db72179dde9d9da8c17dfad2d54 Mon Sep 17 00:00:00 2001 From: domingues Date: Tue, 13 Dec 2016 16:16:12 +0000 Subject: [PATCH 42/43] Fix a bug in Xml::fromArray() When creating from an array with elements like this: `[ "a" => [ 0 ] ]` or `[ "a" => [ '0' ] ]` it fails and produces XML like this `` instant of `0`. The problem is that in PHP `empty('0')` is true, so an exception to this case is needed. --- lib/Cake/Utility/Xml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Xml.php b/lib/Cake/Utility/Xml.php index 95bb4659e..f27fc1497 100644 --- a/lib/Cake/Utility/Xml.php +++ b/lib/Cake/Utility/Xml.php @@ -312,7 +312,7 @@ class Xml { $childNS = $value['xmlns:']; unset($value['xmlns:']); } - } elseif (!empty($value) || $value === 0) { + } elseif (!empty($value) || $value === 0 || $value === '0') { $childValue = (string)$value; } From 3c44ddd10b057ea1095583987495a7724223c178 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 13 Dec 2016 22:47:57 -0500 Subject: [PATCH 43/43] Add tests for #9870 --- lib/Cake/Test/Case/Utility/XmlTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/Cake/Test/Case/Utility/XmlTest.php b/lib/Cake/Test/Case/Utility/XmlTest.php index 5cb62d0f8..d0fa9d1d5 100644 --- a/lib/Cake/Test/Case/Utility/XmlTest.php +++ b/lib/Cake/Test/Case/Utility/XmlTest.php @@ -395,7 +395,15 @@ XML; $obj = Xml::fromArray($xml, 'attributes'); $xmlText = '<' . '?xml version="1.0" encoding="UTF-8"?>defect'; $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML()); + } +/** + * Test fromArray() with zero values. + * + * @return void + */ + public function testFromArrayZeroValue() + { $xml = array( 'tag' => array( '@' => 0, @@ -406,6 +414,16 @@ XML; $xmlText = << 0 +XML; + $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML()); + + $xml = array( + 'tag' => array('0') + ); + $obj = Xml::fromArray($xml); + $xmlText = << +0 XML; $this->assertXmlStringEqualsXmlString($xmlText, $obj->asXML()); }