diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php
index b284fcbe9..14b48a5ff 100644
--- a/lib/Cake/Console/ShellDispatcher.php
+++ b/lib/Cake/Console/ShellDispatcher.php
@@ -323,6 +323,7 @@ class ShellDispatcher {
protected function _parsePaths($args) {
$parsed = array();
$keys = array('-working', '--working', '-app', '--app', '-root', '--root');
+ $args = (array)$args;
foreach ($keys as $key) {
while (($index = array_search($key, $args)) !== false) {
$keyname = str_replace('-', '', $key);
diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php
index 2f79c6a6c..6aeb77ef2 100644
--- a/lib/Cake/Controller/Component/SecurityComponent.php
+++ b/lib/Cake/Controller/Component/SecurityComponent.php
@@ -510,7 +510,13 @@ class SecurityComponent extends Component {
$fieldList += $lockedFields;
$unlocked = implode('|', $unlocked);
- $check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'), 'sha1');
+ $hashParts = array(
+ $this->request->here(),
+ serialize($fieldList),
+ $unlocked,
+ Configure::read('Security.salt')
+ );
+ $check = Security::hash(implode('', $hashParts), 'sha1');
return ($token === $check);
}
diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php
index 299060f57..bb4f6d1e5 100644
--- a/lib/Cake/Model/Model.php
+++ b/lib/Cake/Model/Model.php
@@ -1867,9 +1867,9 @@ class Model extends Object implements CakeEventListener {
$success = $this->data;
}
- $this->data = false;
$this->_clearCache();
$this->validationErrors = array();
+ $this->data = false;
}
$this->whitelist = $_whitelist;
diff --git a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
index 455758a60..0243fa90b 100644
--- a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
+++ b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
@@ -142,8 +142,12 @@ class SecurityComponentTest extends CakeTestCase {
public function setUp() {
parent::setUp();
- $request = new CakeRequest('posts/index', false);
+ $request = $this->getMock('CakeRequest', ['here'], ['posts/index', false]);
$request->addParams(array('controller' => 'posts', 'action' => 'index'));
+ $request->expects($this->any())
+ ->method('here')
+ ->will($this->returnValue('/posts/index'));
+
$this->Controller = new SecurityTestController($request);
$this->Controller->Components->init($this->Controller);
$this->Controller->Security = $this->Controller->TestSecurity;
@@ -485,7 +489,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
+ $fields = '01c1f6dbba02ac6f21b229eab1cc666839b14303%3AModel.valid';
$unlocked = '';
$this->Controller->request->data = array(
@@ -565,7 +569,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A';
+ $fields = '38504e4a341d4e6eadb437217efd91270e558d55%3A';
$unlocked = '';
$this->Controller->request->data = array(
@@ -584,7 +588,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A';
+ $fields = 'c5bc49a6c938c820e7e538df3d8ab7bffbc97ef9%3A';
$unlocked = '';
$this->Controller->request->data = array(
@@ -605,7 +609,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A';
+ $fields = '5415d31b4483c1e09ddb58d2a91ba9650b12aa83%3A';
$unlocked = '';
$this->Controller->request->data = array(
@@ -626,7 +630,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';
+ $fields = 'b72a99e923687687bb5e64025d3cc65e1cecced4%3AAddresses.0.id%7CAddresses.1.id';
$unlocked = '';
$this->Controller->request->data = array(
@@ -655,7 +659,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '422cde416475abc171568be690a98cad20e66079%3A';
+ $fields = '8a764bdb989132c1d46f9a45f64ce2da5f9eebb9%3A';
$unlocked = '';
$this->Controller->request->data = array(
@@ -679,7 +683,7 @@ class SecurityComponentTest extends CakeTestCase {
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertTrue($result);
- $fields = '19464422eafe977ee729c59222af07f983010c5f%3A';
+ $fields = '722de3615e63fdff899e86e85e6498b11c50bb66%3A';
$this->Controller->request->data = array(
'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1',
'Tag' => array('Tag' => array(1)),
@@ -700,7 +704,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testValidatePostCheckbox() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
+ $fields = '01c1f6dbba02ac6f21b229eab1cc666839b14303%3AModel.valid';
$unlocked = '';
$this->Controller->request->data = array(
@@ -711,7 +715,7 @@ class SecurityComponentTest extends CakeTestCase {
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertTrue($result);
- $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A';
+ $fields = 'efbcf463a2c31e97c85d95eedc41dff9e9c6a026%3A';
$this->Controller->request->data = array(
'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
@@ -742,7 +746,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testValidatePostHidden() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden';
+ $fields = 'baaf832a714b39a0618238ac89c7065fc8ec853e%3AModel.hidden%7CModel.other_hidden';
$unlocked = '';
$this->Controller->request->data = array(
@@ -765,7 +769,7 @@ class SecurityComponentTest extends CakeTestCase {
$this->Controller->Security->disabledFields = array('Model.username', 'Model.password');
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden';
+ $fields = 'aa7f254ebd8bf2ef118bc5ca1e191d1ae96857f5%3AModel.hidden';
$unlocked = '';
$this->Controller->request->data = array(
@@ -789,7 +793,12 @@ class SecurityComponentTest extends CakeTestCase {
$key = $this->Controller->request->params['_Token']['key'];
$unlocked = 'Model.username';
$fields = array('Model.hidden', 'Model.password');
- $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
+ $fields = urlencode(Security::hash(
+ '/posts/index' .
+ serialize($fields) .
+ $unlocked .
+ Configure::read('Security.salt'))
+ );
$this->Controller->request->data = array(
'Model' => array(
@@ -864,7 +873,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testValidateHiddenMultipleModel() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid';
+ $fields = '38dd8a37bbb52e67ee4eb812bf1725a6a18b989b%3AModel.valid%7CModel2.valid%7CModel3.valid';
$unlocked = '';
$this->Controller->request->data = array(
@@ -885,7 +894,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testValidateHasManyModel() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid';
+ $fields = 'dcef68de6634c60d2e60484ad0e2faec003456e6%3AModel.0.hidden%7CModel.0.valid';
$fields .= '%7CModel.1.hidden%7CModel.1.valid';
$unlocked = '';
@@ -915,7 +924,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testValidateHasManyRecordsPass() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
+ $fields = '8b6880fbbd4b69279155f899652ecffdd9b4c5a1%3AAddress.0.id%7CAddress.0.primary%7C';
$fields .= 'Address.1.id%7CAddress.1.primary';
$unlocked = '';
@@ -959,7 +968,13 @@ class SecurityComponentTest extends CakeTestCase {
$key = $this->Controller->request->params['_Token']['key'];
$unlocked = '';
$hashFields = array('TaxonomyData');
- $fields = urlencode(Security::hash(serialize($hashFields) . $unlocked . Configure::read('Security.salt')));
+ $fields = urlencode(
+ Security::hash(
+ '/posts/index' .
+ serialize($hashFields) .
+ $unlocked .
+ Configure::read('Security.salt'), 'sha1')
+ );
$this->Controller->request->data = array(
'TaxonomyData' => array(
@@ -1024,7 +1039,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testFormDisabledFields() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D';
+ $fields = '216ee717efd1a251a6d6e9efbb96005a9d09f1eb%3An%3A0%3A%7B%7D';
$unlocked = '';
$this->Controller->request->data = array(
@@ -1055,7 +1070,7 @@ class SecurityComponentTest extends CakeTestCase {
public function testRadio() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->request->params['_Token']['key'];
- $fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D';
+ $fields = '3be63770e7953c6d2119f5377a9303372040f66f%3An%3A0%3A%7B%7D';
$unlocked = '';
$this->Controller->request->data = array(
diff --git a/lib/Cake/Test/Case/Utility/InflectorTest.php b/lib/Cake/Test/Case/Utility/InflectorTest.php
index 1d269348b..b403d6a56 100644
--- a/lib/Cake/Test/Case/Utility/InflectorTest.php
+++ b/lib/Cake/Test/Case/Utility/InflectorTest.php
@@ -30,6 +30,57 @@ App::uses('Inflector', 'Utility');
*/
class InflectorTest extends CakeTestCase {
+/**
+ * A list of chars to test transliteration.
+ *
+ * @var array
+ */
+ public static $maps = array (
+ 'de' => array ( /* German */
+ 'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', 'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss',
+ 'ẞ' => 'SS'
+ ),
+ 'latin' => array (
+ 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Å' => 'A', 'Ă' => 'A', 'Æ' => 'AE', 'Ç' =>
+ 'C', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I',
+ 'Ï' => 'I', 'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ő' => 'O', 'Ø' => 'O',
+ 'Ș' => 'S', 'Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ű' => 'U',
+ 'Ý' => 'Y', 'Þ' => 'TH', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a',
+ 'å' => 'a', 'ă' => 'a', 'æ' => 'ae', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
+ 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' =>
+ 'o', 'ô' => 'o', 'õ' => 'o', 'ő' => 'o', 'ø' => 'o', 'ș' => 's', 'ț' => 't', 'ù' => 'u', 'ú' => 'u',
+ 'û' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th', 'ÿ' => 'y'
+ ),
+ 'tr' => array ( /* Turkish */
+ 'ş' => 's', 'Ş' => 'S', 'ı' => 'i', 'İ' => 'I', 'ç' => 'c', 'Ç' => 'C', 'ğ' => 'g', 'Ğ' => 'G'
+ ),
+ 'uk' => array ( /* Ukrainian */
+ 'Є' => 'Ye', 'І' => 'I', 'Ї' => 'Yi', 'Ґ' => 'G', 'є' => 'ye', 'і' => 'i', 'ї' => 'yi', 'ґ' => 'g'
+ ),
+ 'cs' => array ( /* Czech */
+ 'č' => 'c', 'ď' => 'd', 'ě' => 'e', 'ň' => 'n', 'ř' => 'r', 'š' => 's', 'ť' => 't', 'ů' => 'u',
+ 'ž' => 'z', 'Č' => 'C', 'Ď' => 'D', 'Ě' => 'E', 'Ň' => 'N', 'Ř' => 'R', 'Š' => 'S', 'Ť' => 'T',
+ 'Ů' => 'U', 'Ž' => 'Z'
+ ),
+ 'pl' => array ( /* Polish */
+ 'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z',
+ 'ż' => 'z', 'Ą' => 'A', 'Ć' => 'C', 'Ł' => 'L', 'Ń' => 'N', 'Ó' => 'O', 'Ś' => 'S',
+ 'Ź' => 'Z', 'Ż' => 'Z'
+ ),
+ 'ro' => array ( /* Romanian */
+ 'ă' => 'a', 'â' => 'a', 'î' => 'i', 'ș' => 's', 'ț' => 't', 'Ţ' => 'T', 'ţ' => 't'
+ ),
+ 'lv' => array ( /* Latvian */
+ 'ā' => 'a', 'č' => 'c', 'ē' => 'e', 'ģ' => 'g', 'ī' => 'i', 'ķ' => 'k', 'ļ' => 'l', 'ņ' => 'n',
+ 'š' => 's', 'ū' => 'u', 'ž' => 'z', 'Ā' => 'A', 'Č' => 'C', 'Ē' => 'E', 'Ģ' => 'G', 'Ī' => 'I',
+ 'Ķ' => 'K', 'Ļ' => 'L', 'Ņ' => 'N', 'Š' => 'S', 'Ū' => 'U', 'Ž' => 'Z'
+ ),
+ 'lt' => array ( /* Lithuanian */
+ 'ą' => 'a', 'č' => 'c', 'ę' => 'e', 'ė' => 'e', 'į' => 'i', 'š' => 's', 'ų' => 'u', 'ū' => 'u', 'ž' => 'z',
+ 'Ą' => 'A', 'Č' => 'C', 'Ę' => 'E', 'Ė' => 'E', 'Į' => 'I', 'Š' => 'S', 'Ų' => 'U', 'Ū' => 'U', 'Ž' => 'Z'
+ )
+ );
+
/**
* tearDown
*
@@ -259,6 +310,20 @@ class InflectorTest extends CakeTestCase {
$this->assertEquals('non_breaking_space', $result);
}
+/**
+ * Test slug() with a complete list of special chars.
+ *
+ * @return void
+ */
+ public function testInflectorSlugCharList() {
+ foreach (self::$maps as $language => $list) {
+ foreach ($list as $from => $to) {
+ $result = Inflector::slug($from);
+ $this->assertEquals($to, $result, $from . ' (' . $language . ') should be ' . $to . ' - but is ' . $result);
+ }
+ }
+ }
+
/**
* testInflectorSlugWithMap method
*
diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php
index d0f6a11af..bfe0a7eb8 100644
--- a/lib/Cake/Test/Case/Utility/SecurityTest.php
+++ b/lib/Cake/Test/Case/Utility/SecurityTest.php
@@ -114,10 +114,10 @@ class SecurityTest extends CakeTestCase {
$key = 'someKey';
$hash = 'someHash';
- $this->assertSame(strlen(Security::hash($key, null, false)), 40);
- $this->assertSame(strlen(Security::hash($key, 'sha1', false)), 40);
- $this->assertSame(strlen(Security::hash($key, null, true)), 40);
- $this->assertSame(strlen(Security::hash($key, 'sha1', true)), 40);
+ $this->assertSame(40, strlen(Security::hash($key, null, false)));
+ $this->assertSame(40, strlen(Security::hash($key, 'sha1', false)));
+ $this->assertSame(40, strlen(Security::hash($key, null, true)));
+ $this->assertSame(40, strlen(Security::hash($key, 'sha1', true)));
$result = Security::hash($key, null, $hash);
$this->assertSame($result, 'e38fcb877dccb6a94729a81523851c931a46efb1');
@@ -127,25 +127,25 @@ class SecurityTest extends CakeTestCase {
$hashType = 'sha1';
Security::setHash($hashType);
- $this->assertSame(Security::$hashType, $hashType);
- $this->assertSame(strlen(Security::hash($key, null, true)), 40);
- $this->assertSame(strlen(Security::hash($key, null, false)), 40);
+ $this->assertSame($hashType, Security::$hashType);
+ $this->assertSame(40, strlen(Security::hash($key, null, true)));
+ $this->assertSame(40, strlen(Security::hash($key, null, false)));
- $this->assertSame(strlen(Security::hash($key, 'md5', false)), 32);
- $this->assertSame(strlen(Security::hash($key, 'md5', true)), 32);
+ $this->assertSame(32, strlen(Security::hash($key, 'md5', false)));
+ $this->assertSame(32, strlen(Security::hash($key, 'md5', true)));
$hashType = 'md5';
Security::setHash($hashType);
- $this->assertSame(Security::$hashType, $hashType);
- $this->assertSame(strlen(Security::hash($key, null, false)), 32);
- $this->assertSame(strlen(Security::hash($key, null, true)), 32);
+ $this->assertSame($hashType, Security::$hashType);
+ $this->assertSame(32, strlen(Security::hash($key, null, false)));
+ $this->assertSame(32, strlen(Security::hash($key, null, true)));
if (!function_exists('hash') && !function_exists('mhash')) {
- $this->assertSame(strlen(Security::hash($key, 'sha256', false)), 32);
- $this->assertSame(strlen(Security::hash($key, 'sha256', true)), 32);
+ $this->assertSame(32, strlen(Security::hash($key, 'sha256', false)));
+ $this->assertSame(32, strlen(Security::hash($key, 'sha256', true)));
} else {
- $this->assertSame(strlen(Security::hash($key, 'sha256', false)), 64);
- $this->assertSame(strlen(Security::hash($key, 'sha256', true)), 64);
+ $this->assertSame(64, strlen(Security::hash($key, 'sha256', false)));
+ $this->assertSame(64, strlen(Security::hash($key, 'sha256', true)));
}
Security::setHash($_hashType);
@@ -167,8 +167,8 @@ class SecurityTest extends CakeTestCase {
$hashType = 'blowfish';
Security::setHash($hashType);
- $this->assertSame(Security::$hashType, $hashType);
- $this->assertSame(strlen(Security::hash($key, null, false)), 60);
+ $this->assertSame($hashType, Security::$hashType);
+ $this->assertSame(60, strlen(Security::hash($key, null, false)));
$password = $submittedPassword = $key;
$storedPassword = Security::hash($password);
diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
index a5ff2df54..6b8d8b30f 100755
--- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php
@@ -1009,7 +1009,7 @@ class FormHelperTest extends CakeTestCase {
$result = $this->Form->secure($this->Form->fields);
- $hash = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';
+ $hash = 'a3b9b2ba1cb688838f92818a5970e17dd7943a78%3AAddresses.0.id%7CAddresses.1.id';
$expected = array(
'div' => array('style' => 'display:none;'),
@@ -1074,7 +1074,7 @@ class FormHelperTest extends CakeTestCase {
$this->Form->input('Addresses.1.phone');
$result = $this->Form->secure($this->Form->fields);
- $hash = '629b6536dcece48aa41a117045628ce602ccbbb2%3AAddresses.0.id%7CAddresses.1.id';
+ $hash = '5c9cadf9da008cc444d3960b481391a425a5d979%3AAddresses.0.id%7CAddresses.1.id';
$expected = array(
'div' => array('style' => 'display:none;'),
@@ -1124,7 +1124,7 @@ class FormHelperTest extends CakeTestCase {
$result = $this->Form->secure($expected);
- $hash = '2981c38990f3f6ba935e6561dc77277966fabd6d%3AAddresses.id';
+ $hash = '40289bd07811587887ff56585a8526ff9da59d7a%3AAddresses.id';
$expected = array(
'div' => array('style' => 'display:none;'),
array('input' => array(
@@ -1247,7 +1247,7 @@ class FormHelperTest extends CakeTestCase {
);
$this->assertEquals($expected, $result);
- $hash = 'bd7c4a654e5361f9a433a43f488ff9a1065d0aaf%3AUserForm.hidden%7CUserForm.stuff';
+ $hash = '6014b4e1c4f39eb62389712111dbe6435bec66cb%3AUserForm.hidden%7CUserForm.stuff';
$result = $this->Form->secure($this->Form->fields);
$expected = array(
diff --git a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php
index d38d60529..9a3eba7cb 100644
--- a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php
+++ b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php
@@ -265,6 +265,10 @@ class TextHelperTest extends CakeTestCase {
'Text with a url http://www.not--work.com and more',
'Text with a url http://www.not--work.com and more',
),
+ array(
+ 'Text with a url http://www.sub_domain.domain.pl and more',
+ 'Text with a url http://www.sub_domain.domain.pl and more',
+ ),
array(
'Text with a partial www.küchenschöhn-not-working.de URL',
'Text with a partial www.küchenschöhn-not-working.de URL'
diff --git a/lib/Cake/Utility/Inflector.php b/lib/Cake/Utility/Inflector.php
index ef4685edf..951d77091 100644
--- a/lib/Cake/Utility/Inflector.php
+++ b/lib/Cake/Utility/Inflector.php
@@ -176,56 +176,63 @@ class Inflector {
* @var array
*/
protected static $_transliteration = array(
- '/ä|æ|ǽ/' => 'ae',
- '/ö|œ/' => 'oe',
- '/ü/' => 'ue',
- '/Ä/' => 'Ae',
- '/Ü/' => 'Ue',
- '/Ö/' => 'Oe',
'/À|Á|Â|Ã|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A',
- '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a',
- '/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
- '/ç|ć|ĉ|ċ|č/' => 'c',
- '/Ð|Ď|Đ/' => 'D',
- '/ð|ď|đ/' => 'd',
- '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E',
- '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e',
- '/Ĝ|Ğ|Ġ|Ģ/' => 'G',
- '/ĝ|ğ|ġ|ģ/' => 'g',
- '/Ĥ|Ħ/' => 'H',
- '/ĥ|ħ/' => 'h',
- '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I',
- '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i',
- '/Ĵ/' => 'J',
- '/ĵ/' => 'j',
- '/Ķ/' => 'K',
- '/ķ/' => 'k',
- '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L',
- '/ĺ|ļ|ľ|ŀ|ł/' => 'l',
- '/Ñ|Ń|Ņ|Ň/' => 'N',
- '/ñ|ń|ņ|ň|ʼn/' => 'n',
- '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O',
- '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o',
- '/Ŕ|Ŗ|Ř/' => 'R',
- '/ŕ|ŗ|ř/' => 'r',
- '/Ś|Ŝ|Ş|Ș|Š/' => 'S',
- '/ś|ŝ|ş|ș|š|ſ/' => 's',
- '/Ţ|Ț|Ť|Ŧ/' => 'T',
- '/ţ|ț|ť|ŧ/' => 't',
- '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
- '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u',
- '/Ý|Ÿ|Ŷ/' => 'Y',
- '/ý|ÿ|ŷ/' => 'y',
- '/Ŵ/' => 'W',
- '/ŵ/' => 'w',
- '/Ź|Ż|Ž/' => 'Z',
- '/ź|ż|ž/' => 'z',
'/Æ|Ǽ/' => 'AE',
- '/ß/' => 'ss',
+ '/Ä/' => 'Ae',
+ '/Ç|Ć|Ĉ|Ċ|Č/' => 'C',
+ '/Ð|Ď|Đ/' => 'D',
+ '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E',
+ '/Ĝ|Ğ|Ġ|Ģ|Ґ/' => 'G',
+ '/Ĥ|Ħ/' => 'H',
+ '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|І/' => 'I',
'/IJ/' => 'IJ',
- '/ij/' => 'ij',
+ '/Ĵ/' => 'J',
+ '/Ķ/' => 'K',
+ '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L',
+ '/Ñ|Ń|Ņ|Ň/' => 'N',
+ '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O',
'/Œ/' => 'OE',
- '/ƒ/' => 'f'
+ '/Ö/' => 'Oe',
+ '/Ŕ|Ŗ|Ř/' => 'R',
+ '/Ś|Ŝ|Ş|Ș|Š/' => 'S',
+ '/ẞ/' => 'SS',
+ '/Ţ|Ț|Ť|Ŧ/' => 'T',
+ '/Þ/' => 'TH',
+ '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U',
+ '/Ü/' => 'Ue',
+ '/Ŵ/' => 'W',
+ '/Ý|Ÿ|Ŷ/' => 'Y',
+ '/Є/' => 'Ye',
+ '/Ї/' => 'Yi',
+ '/Ź|Ż|Ž/' => 'Z',
+ '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a',
+ '/ä|æ|ǽ/' => 'ae',
+ '/ç|ć|ĉ|ċ|č/' => 'c',
+ '/ð|ď|đ/' => 'd',
+ '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e',
+ '/ƒ/' => 'f',
+ '/ĝ|ğ|ġ|ģ|ґ/' => 'g',
+ '/ĥ|ħ/' => 'h',
+ '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|і/' => 'i',
+ '/ij/' => 'ij',
+ '/ĵ/' => 'j',
+ '/ķ/' => 'k',
+ '/ĺ|ļ|ľ|ŀ|ł/' => 'l',
+ '/ñ|ń|ņ|ň|ʼn/' => 'n',
+ '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o',
+ '/ö|œ/' => 'oe',
+ '/ŕ|ŗ|ř/' => 'r',
+ '/ś|ŝ|ş|ș|š|ſ/' => 's',
+ '/ß/' => 'ss',
+ '/ţ|ț|ť|ŧ/' => 't',
+ '/þ/' => 'th',
+ '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u',
+ '/ü/' => 'ue',
+ '/ŵ/' => 'w',
+ '/ý|ÿ|ŷ/' => 'y',
+ '/є/' => 'ye',
+ '/ї/' => 'yi',
+ '/ź|ż|ž/' => 'z',
);
/**
diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php
index 3f39091ff..11b4b377e 100755
--- a/lib/Cake/View/Helper/FormHelper.php
+++ b/lib/Cake/View/Helper/FormHelper.php
@@ -117,6 +117,14 @@ class FormHelper extends AppHelper {
*/
protected $_domIdSuffixes = array();
+/**
+ * The action attribute value of the last created form.
+ * Used to make form/request specific hashes for SecurityComponent.
+ *
+ * @var string
+ */
+ protected $_lastAction = '';
+
/**
* Copies the validationErrors variable from the View object into this instance
*
@@ -458,6 +466,7 @@ class FormHelper extends AppHelper {
$this->setEntity($model, true);
$this->_introspectModel($model, 'fields');
}
+ $this->_lastAction = $action;
return $this->Html->useTag('form', $action, $htmlAttributes) . $append;
}
@@ -576,7 +585,13 @@ class FormHelper extends AppHelper {
$locked = implode(array_keys($locked), '|');
$unlocked = implode($unlockedFields, '|');
- $fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
+ $hashParts = array(
+ $this->_lastAction,
+ serialize($fields),
+ $unlocked,
+ Configure::read('Security.salt')
+ );
+ $fields = Security::hash(implode('', $hashParts), 'sha1');
$tokenFields = array_merge($secureAttributes, array(
'value' => urlencode($fields . ':' . $locked),
diff --git a/lib/Cake/View/Helper/TextHelper.php b/lib/Cake/View/Helper/TextHelper.php
index 451aa17b6..17ed5a4eb 100644
--- a/lib/Cake/View/Helper/TextHelper.php
+++ b/lib/Cake/View/Helper/TextHelper.php
@@ -104,7 +104,7 @@ class TextHelper extends AppHelper {
$this->_placeholders = array();
$options += array('escape' => true);
- $pattern = '#(?)((?:https?|ftp|nntp)://[\p{L}0-9.\-:]+(?:[/?][^\s<]*)?)#ui';
+ $pattern = '#(?)((?:https?|ftp|nntp)://[\p{L}0-9.\-_:]+(?:[/?][^\s<]*)?)#ui';
$text = preg_replace_callback(
$pattern,
array(&$this, '_insertPlaceHolder'),