From d9b5ec1a3ae9382864176f7cd6ba3c159f4f40ce Mon Sep 17 00:00:00 2001 From: David Thalmann Date: Sat, 21 Jul 2012 22:07:51 +0300 Subject: [PATCH 01/11] Changed all string concatenations like $Model->alias . '.' . $field to the more consistent $Model->escapeField($field). --- lib/Cake/Model/Behavior/TreeBehavior.php | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php index 365d26002..cb28d733f 100644 --- a/lib/Cake/Model/Behavior/TreeBehavior.php +++ b/lib/Cake/Model/Behavior/TreeBehavior.php @@ -70,8 +70,8 @@ class TreeBehavior extends ModelBehavior { if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) { $data = $Model->getAssociated($settings['scope']); - $parent = $Model->{$settings['scope']}; - $settings['scope'] = $Model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey; + $Parent = $Model->{$settings['scope']}; + $settings['scope'] = $Model->escapeField($data['foreignKey']) . ' = ' . $Parent->escapeField(); $settings['recursive'] = 0; } $this->settings[$Model->alias] = $settings; @@ -125,8 +125,8 @@ class TreeBehavior extends ModelBehavior { public function beforeDelete(Model $Model, $cascade = true) { extract($this->settings[$Model->alias]); $data = $Model->find('first', array( - 'conditions' => array($Model->alias . '.' . $Model->primaryKey => $Model->id), - 'fields' => array($Model->alias . '.' . $left, $Model->alias . '.' . $right), + 'conditions' => array($Model->escapeField($Model->primaryKey) => $Model->id), + 'fields' => array($Model->escapeField($left), $Model->escapeField($right)), 'recursive' => -1)); if ($data) { $this->_deletedRow = current($data); @@ -156,7 +156,7 @@ class TreeBehavior extends ModelBehavior { if (is_string($scope)) { $scope = array($scope); } - $scope[]["{$Model->alias}.{$left} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1); + $scope[]["{$Model->escapeField($left)} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1); $Model->deleteAll($scope); } $this->_sync($Model, $diff, '-', '> ' . $data[$right]); @@ -308,7 +308,7 @@ class TreeBehavior extends ModelBehavior { $recursive = $overrideRecursive; } if (!$order) { - $order = $Model->alias . '.' . $left . ' asc'; + $order = "{$Model->escapeField($left)} asc"; } if ($direct) { $conditions = array($scope, $Model->escapeField($parent) => $id); @@ -373,7 +373,7 @@ class TreeBehavior extends ModelBehavior { } else { array_unshift($valuePath, '%s' . $valuePath[0], '{n}.tree_prefix'); } - $order = $Model->alias . '.' . $left . ' asc'; + $order = "{$Model->escapeField($left)} asc"; $results = $Model->find('all', compact('conditions', 'fields', 'order', 'recursive')); $stack = array(); @@ -933,13 +933,13 @@ class TreeBehavior extends ModelBehavior { $db = ConnectionManager::getDataSource($Model->useDbConfig); if ($created) { if (is_string($scope)) { - $scope .= " AND {$Model->alias}.{$Model->primaryKey} <> "; + $scope .= " AND {$Model->escapeField()} <> "; $scope .= $db->value($Model->id, $Model->getColumnType($Model->primaryKey)); } else { $scope['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id; } } - $name = $Model->alias . '.' . $right; + $name = $Model->escapeField($right); list($edge) = array_values($Model->find('first', array( 'conditions' => $scope, 'fields' => $db->calculate($Model, 'max', array($name, $right)), @@ -959,7 +959,7 @@ class TreeBehavior extends ModelBehavior { */ protected function _getMin(Model $Model, $scope, $left, $recursive = -1) { $db = ConnectionManager::getDataSource($Model->useDbConfig); - $name = $Model->alias . '.' . $left; + $name = $Model->escapeField($left); list($edge) = array_values($Model->find('first', array( 'conditions' => $scope, 'fields' => $db->calculate($Model, 'min', array($name, $left)), @@ -991,15 +991,15 @@ class TreeBehavior extends ModelBehavior { $field = $right; } if (is_string($conditions)) { - $conditions = array("{$Model->alias}.{$field} {$conditions}"); + $conditions = array("{$Model->escapeField($field)} {$conditions}"); } if (($scope != '1 = 1' && $scope !== true) && $scope) { $conditions[] = $scope; } if ($created) { - $conditions['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id; + $conditions['NOT'][$Model->escapeField()] = $Model->id; } - $Model->updateAll(array($Model->alias . '.' . $field => $Model->escapeField($field) . ' ' . $dir . ' ' . $shift), $conditions); + $Model->updateAll(array($Model->escapeField($field) => $Model->escapeField($field) . ' ' . $dir . ' ' . $shift), $conditions); $Model->recursive = $ModelRecursive; } From 78de6e276a28f01cb7ac1f906457a5a55b106472 Mon Sep 17 00:00:00 2001 From: David Thalmann Date: Sun, 22 Jul 2012 03:40:49 +0300 Subject: [PATCH 02/11] Removed inline method calls in curly braced string concat's. --- lib/Cake/Model/Behavior/TreeBehavior.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php index cb28d733f..eb316a4d7 100644 --- a/lib/Cake/Model/Behavior/TreeBehavior.php +++ b/lib/Cake/Model/Behavior/TreeBehavior.php @@ -156,7 +156,7 @@ class TreeBehavior extends ModelBehavior { if (is_string($scope)) { $scope = array($scope); } - $scope[]["{$Model->escapeField($left)} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1); + $scope[][$Model->escapeField($left) . " BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1); $Model->deleteAll($scope); } $this->_sync($Model, $diff, '-', '> ' . $data[$right]); @@ -308,7 +308,7 @@ class TreeBehavior extends ModelBehavior { $recursive = $overrideRecursive; } if (!$order) { - $order = "{$Model->escapeField($left)} asc"; + $order = $Model->escapeField($left) . " asc"; } if ($direct) { $conditions = array($scope, $Model->escapeField($parent) => $id); @@ -373,7 +373,7 @@ class TreeBehavior extends ModelBehavior { } else { array_unshift($valuePath, '%s' . $valuePath[0], '{n}.tree_prefix'); } - $order = "{$Model->escapeField($left)} asc"; + $order = $Model->escapeField($left) . " asc"; $results = $Model->find('all', compact('conditions', 'fields', 'order', 'recursive')); $stack = array(); @@ -933,7 +933,7 @@ class TreeBehavior extends ModelBehavior { $db = ConnectionManager::getDataSource($Model->useDbConfig); if ($created) { if (is_string($scope)) { - $scope .= " AND {$Model->escapeField()} <> "; + $scope .= " AND " . $Model->escapeField() . " <> "; $scope .= $db->value($Model->id, $Model->getColumnType($Model->primaryKey)); } else { $scope['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id; @@ -991,7 +991,7 @@ class TreeBehavior extends ModelBehavior { $field = $right; } if (is_string($conditions)) { - $conditions = array("{$Model->escapeField($field)} {$conditions}"); + $conditions = array($Model->escapeField($field) . " {$conditions}"); } if (($scope != '1 = 1' && $scope !== true) && $scope) { $conditions[] = $scope; From 5413b672ebbbd396249879d20e7ec52c704678a3 Mon Sep 17 00:00:00 2001 From: Rachman Chavik Date: Fri, 27 Jul 2012 11:31:59 +0700 Subject: [PATCH 03/11] use is_subclass_of instead of comparing Acl.classname --- lib/Cake/Console/Command/AclShell.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/Command/AclShell.php b/lib/Cake/Console/Command/AclShell.php index 8fa17c2e1..4a935287f 100644 --- a/lib/Cake/Console/Command/AclShell.php +++ b/lib/Cake/Console/Command/AclShell.php @@ -70,12 +70,15 @@ class AclShell extends AppShell { $this->connection = $this->params['connection']; } - if (!in_array(Configure::read('Acl.classname'), array('DbAcl', 'DB_ACL'))) { + $class = Configure::read('Acl.classname'); + list($plugin, $class) = pluginSplit($class, true); + App::uses($class, $plugin . 'Controller/Component/Acl'); + if (!in_array($class, array('DbAcl', 'DB_ACL')) && !is_subclass_of($class, 'DbAcl')) { $out = "--------------------------------------------------\n"; $out .= __d('cake_console', 'Error: Your current Cake configuration is set to an ACL implementation other than DB.') . "\n"; $out .= __d('cake_console', 'Please change your core config to reflect your decision to use DbAcl before attempting to use this script') . "\n"; $out .= "--------------------------------------------------\n"; - $out .= __d('cake_console', 'Current ACL Classname: %s', Configure::read('Acl.classname')) . "\n"; + $out .= __d('cake_console', 'Current ACL Classname: %s', $class) . "\n"; $out .= "--------------------------------------------------\n"; $this->err($out); $this->_stop(); From 19f0e72d582fba29ade83b11000ba03e0e697f7f Mon Sep 17 00:00:00 2001 From: Schlaefer Date: Sun, 29 Jul 2012 14:24:46 +0200 Subject: [PATCH 04/11] fix #2858 RSS helper bug with namedspaced keys http://cakephp.lighthouseapp.com/projects/42648/tickets/2858-rss-helper-bug-with-namedspaced-keys --- .../Test/Case/View/Helper/RssHelperTest.php | 52 +++++++++++++++++++ lib/Cake/View/Helper/RssHelper.php | 15 ++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php index bfffdf4fc..1e69da066 100644 --- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php @@ -717,4 +717,56 @@ class RssHelperTest extends CakeTestCase { $this->assertTags($result, $expected); } + public function testElementNamespaceWithoutPrefix() { + $item = array( + 'creator' => 'Alex', + ); + $attributes = array( + 'namespace' => 'http://link.com' + ); + $result = $this->Rss->item($attributes, $item); + $expected = array( + 'item' => array( + 'xmlns' => 'http://link.com' + ), + 'creator' => array( + 'xmlns' => 'http://link.com' + ), + 'Alex', + '/creator', + '/item' + ); + $this->assertTags($result, $expected, true); + } + + public function testElementNamespaceWithPrefix() { + $item = array( + 'title' => 'Title', + 'creator' => 'Alex' + ); + $attributes = array( + 'namespace' => array( + 'prefix' => 'dc', + 'url' => 'http://link.com' + ) + ); + $result = $this->Rss->item($attributes, $item); + $expected = array( + 'item' => array( + 'xmlns:dc' => 'http://link.com' + ), + 'title' => array( + 'xmlns:dc' => 'http://link.com' + ), + 'Title', + '/title', + 'creator' => array( + 'xmlns:dc' => 'http://link.com' + ), + 'Alex', + '/creator', + '/item' + ); + $this->assertTags($result, $expected, true); + } } diff --git a/lib/Cake/View/Helper/RssHelper.php b/lib/Cake/View/Helper/RssHelper.php index bd412848f..26160f055 100644 --- a/lib/Cake/View/Helper/RssHelper.php +++ b/lib/Cake/View/Helper/RssHelper.php @@ -256,6 +256,8 @@ class RssHelper extends AppHelper { $attrib = $val; $val = null; break; + default: + $attrib = $att; } if (!is_null($val) && $escape) { $val = h($val); @@ -312,7 +314,12 @@ class RssHelper extends AppHelper { $xml = '<' . $name; if (!empty($namespace)) { - $xml .= ' xmlns:"' . $namespace . '"'; + $xml .= ' xmlns'; + if (is_array($namespace)) { + $xml .= ':' . $namespace['prefix']; + $namespace = $namespace['url']; + } + $xml .= '="' . $namespace . '"'; } $bareName = $name; if (strpos($name, ':') !== false) { @@ -329,8 +336,10 @@ class RssHelper extends AppHelper { $xml .= '>' . $content . ''; $elem = Xml::build($xml, array('return' => 'domdocument')); $nodes = $elem->getElementsByTagName($bareName); - foreach ($attrib as $key => $value) { - $nodes->item(0)->setAttribute($key, $value); + if ($attrib) { + foreach ($attrib as $key => $value) { + $nodes->item(0)->setAttribute($key, $value); + } } foreach ($children as $k => $child) { $child = $elem->createElement($name, $child); From 7b939186a1da7a1afa027c2cbbe66e5228b076f0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 29 Jul 2012 21:18:33 -0400 Subject: [PATCH 05/11] Fix ( and ) not being correctly handled by autoLinkUrls Fixes #3077 --- lib/Cake/Test/Case/View/Helper/TextHelperTest.php | 10 ++++++++++ lib/Cake/View/Helper/TextHelper.php | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php index 7538f2094..2c04eb154 100644 --- a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php @@ -181,6 +181,16 @@ class TextHelperTest extends CakeTestCase { $result = $this->Text->autoLinkUrls($text); $this->assertEquals($expected, $result); + $text = 'This is a test that includes http://de.wikipedia.org/wiki/Kanton_(Schweiz)#fragment'; + $expected = 'This is a test that includes http://de.wikipedia.org/wiki/Kanton_(Schweiz)#fragment'; + $result = $this->Text->autoLinkUrls($text); + $this->assertEquals($expected, $result); + + $text = 'This is a test that includes www.wikipedia.org/wiki/Kanton_(Schweiz)#fragment'; + $expected = 'This is a test that includes www.wikipedia.org/wiki/Kanton_(Schweiz)#fragment'; + $result = $this->Text->autoLinkUrls($text); + $this->assertEquals($expected, $result); + $text = 'Text with a partial www.cakephp.org URL'; $expected = 'Text with a partial www.cakephp.org URL'; $result = $this->Text->autoLinkUrls($text); diff --git a/lib/Cake/View/Helper/TextHelper.php b/lib/Cake/View/Helper/TextHelper.php index 096029ed1..c7523b425 100644 --- a/lib/Cake/View/Helper/TextHelper.php +++ b/lib/Cake/View/Helper/TextHelper.php @@ -101,8 +101,9 @@ class TextHelper extends AppHelper { $this->_placeholders = array(); $options += array('escape' => true); + $pattern = '#(?)((?:https?|ftp|nntp)://[^\s<>()]+\.[a-z]+(?:\/[^\s]+)?)#i'; $text = preg_replace_callback( - '#(?)((?:https?|ftp|nntp)://[^\s<>()]+)#i', + $pattern, array(&$this, '_insertPlaceHolder'), $text ); From 4541510e26b2b75abac698c74974bbe6c6de997e Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 29 Jul 2012 22:37:41 -0400 Subject: [PATCH 06/11] Fix notice error when a missing action error is hit. --- lib/Cake/TestSuite/ControllerTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/TestSuite/ControllerTestCase.php b/lib/Cake/TestSuite/ControllerTestCase.php index d6002f07a..c92b2af20 100644 --- a/lib/Cake/TestSuite/ControllerTestCase.php +++ b/lib/Cake/TestSuite/ControllerTestCase.php @@ -246,7 +246,7 @@ abstract class ControllerTestCase extends CakeTestCase { } $Dispatch->loadRoutes = $this->loadRoutes; $Dispatch->parseParams(new CakeEvent('ControllerTestCase', $Dispatch, array('request' => $request))); - if (!isset($request->params['controller'])) { + if (!isset($request->params['controller']) && Router::currentRoute()) { $this->headers = Router::currentRoute()->response->header(); return; } From af8c5716fc9172accbcbfe48f14eb57527680648 Mon Sep 17 00:00:00 2001 From: Schlaefer Date: Mon, 30 Jul 2012 10:09:47 +0200 Subject: [PATCH 07/11] Added test for RSS to allow namespace tags if namespace is specified If a namespace prefix is defined it's prefix should not be stripped from the tag: `` stays ``. Other prefixes are still stripped from the tag name. This test is missing in 19f0e72d582fba29ade83b11000ba03e0e697f7f --- lib/Cake/Test/Case/View/Helper/RssHelperTest.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php index 1e69da066..34e99576d 100644 --- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php @@ -742,7 +742,8 @@ class RssHelperTest extends CakeTestCase { public function testElementNamespaceWithPrefix() { $item = array( 'title' => 'Title', - 'creator' => 'Alex' + 'dc:creator' => 'Alex', + 'xy:description' => 'descriptive words' ); $attributes = array( 'namespace' => array( @@ -760,11 +761,16 @@ class RssHelperTest extends CakeTestCase { ), 'Title', '/title', - 'creator' => array( + 'dc:creator' => array( 'xmlns:dc' => 'http://link.com' ), 'Alex', - '/creator', + '/dc:creator', + 'description' => array( + 'xmlns:dc' => 'http://link.com' + ), + 'descriptive words', + '/description', '/item' ); $this->assertTags($result, $expected, true); From 9b94133f0d1cba534e78aba96f5546adc33e5889 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 30 Jul 2012 21:27:21 -0400 Subject: [PATCH 08/11] Fix uncaught exceptions when generating view cache files Fixes #3016 --- lib/Cake/View/Helper/CacheHelper.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/CacheHelper.php b/lib/Cake/View/Helper/CacheHelper.php index a48088650..2f85cd50b 100644 --- a/lib/Cake/View/Helper/CacheHelper.php +++ b/lib/Cake/View/Helper/CacheHelper.php @@ -150,7 +150,17 @@ class CacheHelper extends AppHelper { if ($cacheTime != '' && $cacheTime > 0) { $cached = $this->_parseOutput($out); - $this->_writeFile($cached, $cacheTime, $useCallbacks); + try { + $this->_writeFile($cached, $cacheTime, $useCallbacks); + } catch (Exception $e) { + $message = __d( + 'cake_dev', + 'Unable to write view cache file: "%s" for "%s"', + $e->getMessage(), + $this->request->here + ); + $this->log($message, 'error'); + } $out = $this->_stripTags($out); } return $out; From 2a0a5f2afa398331b855665bff425c6386b3a7cd Mon Sep 17 00:00:00 2001 From: Ceeram Date: Tue, 31 Jul 2012 18:39:05 +0200 Subject: [PATCH 09/11] Use the returned response instance from the event --- lib/Cake/Routing/Dispatcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Routing/Dispatcher.php b/lib/Cake/Routing/Dispatcher.php index bf3e3954e..b10fe4ebb 100644 --- a/lib/Cake/Routing/Dispatcher.php +++ b/lib/Cake/Routing/Dispatcher.php @@ -143,9 +143,9 @@ class Dispatcher implements CakeEventListener { $request = $beforeEvent->data['request']; if ($beforeEvent->result instanceof CakeResponse) { if (isset($request->params['return'])) { - return $response->body(); + return $beforeEvent->result->body(); } - $response->send(); + $beforeEvent->result->send(); return; } From cffc36e4e05ccf2c1cd79f3706db14828d33971a Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 1 Aug 2012 23:05:48 -0400 Subject: [PATCH 10/11] Fix notice error when impossible conditions are created. Fixes #3084 --- lib/Cake/Model/Model.php | 2 +- lib/Cake/Test/Case/Model/ModelReadTest.php | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php index 8909483b8..c95ff26a8 100644 --- a/lib/Cake/Model/Model.php +++ b/lib/Cake/Model/Model.php @@ -2863,7 +2863,7 @@ class Model extends Object implements CakeEventListener { $query['order'] = $field . ' ASC'; $neighbors = $this->find('all', $query); if (!array_key_exists('prev', $return)) { - $return['prev'] = $neighbors[0]; + $return['prev'] = isset($neighbors[0]) ? $neighbors[0] : null; } if (count($neighbors) === 2) { $return['next'] = $neighbors[1]; diff --git a/lib/Cake/Test/Case/Model/ModelReadTest.php b/lib/Cake/Test/Case/Model/ModelReadTest.php index 58a2ff472..7209e0216 100644 --- a/lib/Cake/Test/Case/Model/ModelReadTest.php +++ b/lib/Cake/Test/Case/Model/ModelReadTest.php @@ -3736,6 +3736,30 @@ class ModelReadTest extends BaseModelTest { $this->assertEquals($expected, $result); } +/** + * Test find(neighbors) with missing fields so no neighbors are found. + * + * @return + */ + public function testFindNeighborsNoPrev() { + $this->loadFixtures('User', 'Article', 'Comment', 'Tag', 'ArticlesTag', 'Attachment'); + $Article = new Article(); + + $result = $Article->find('neighbors', array( + 'field' => 'Article.title', + 'value' => 'Second Article', + 'fields' => array('id'), + 'conditions' => array( + 'Article.title LIKE' => '%Article%' + ), + 'recursive' => 0, + )); + $expected = array( + 'prev' => null, + 'next' => null + ); + $this->assertEquals($expected, $result); + } /** * testFindCombinedRelations method * From c96e364cbb6ec8dd72dd220836a07ed104d2d50a Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 2 Aug 2012 21:03:53 -0400 Subject: [PATCH 11/11] Fix incorrect expiry of sessions. Fixes #3088 --- lib/Cake/Model/Datasource/Session/DatabaseSession.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Cake/Model/Datasource/Session/DatabaseSession.php b/lib/Cake/Model/Datasource/Session/DatabaseSession.php index 17207f9ca..33cd2284d 100644 --- a/lib/Cake/Model/Datasource/Session/DatabaseSession.php +++ b/lib/Cake/Model/Datasource/Session/DatabaseSession.php @@ -137,6 +137,8 @@ class DatabaseSession implements CakeSessionHandlerInterface { public function gc($expires = null) { if (!$expires) { $expires = time(); + } else { + $expires = time() - $expires; } return $this->_model->deleteAll(array($this->_model->alias . ".expires <" => $expires), false, false); }