Merge pull request #7 from cakephp/2.x

Sync 2.x with upstream
This commit is contained in:
Val Bancer 2018-08-13 12:22:57 +02:00 committed by GitHub
commit 87677d7004
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 248 additions and 64 deletions

View file

@ -40,7 +40,7 @@ CREATE TABLE aros (
PRIMARY KEY (id) PRIMARY KEY (id)
); );
/* this indexes will improve acl perfomance */ /* this indexes will improve acl performance */
CREATE INDEX idx_acos_lft_rght ON `acos` (`lft`, `rght`); CREATE INDEX idx_acos_lft_rght ON `acos` (`lft`, `rght`);
CREATE INDEX idx_acos_alias ON `acos` (`alias`); CREATE INDEX idx_acos_alias ON `acos` (`alias`);

View file

@ -18,8 +18,11 @@
"source": "https://github.com/cakephp/cakephp" "source": "https://github.com/cakephp/cakephp"
}, },
"require": { "require": {
"php": ">=5.3.0", "php": ">=5.3.0"
"ext-mcrypt": "*" },
"suggest": {
"ext-openssl": "You need to install ext-openssl or ext-mcrypt to use AES-256 encryption",
"ext-mcrypt": "You need to install ext-openssl or ext-mcrypt to use AES-256 encryption"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^3.7", "phpunit/phpunit": "^3.7",

View file

@ -45,9 +45,9 @@ class SessionComponent extends Component {
* *
* In your controller: $this->Session->write('Controller.sessKey', 'session value'); * In your controller: $this->Session->write('Controller.sessKey', 'session value');
* *
* @param string $name The name of the key your are setting in the session. * @param string|array $name The name of the key your are setting in the session.
* This should be in a Controller.key format for better organizing * This should be in a Controller.key format for better organizing
* @param string $value The value you want to store in a session. * @param string|array $value The value you want to store in a session.
* @return bool Success * @return bool Success
* @link https://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write * @link https://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write
*/ */

View file

@ -591,7 +591,7 @@ class App {
* *
* @param string|array $type The type of Class if passed as a string, or all params can be passed as * @param string|array $type The type of Class if passed as a string, or all params can be passed as
* a single array to $type. * a single array to $type.
* @param string $name Name of the Class or a unique name for the file * @param string|array $name Name of the Class or a unique name for the file
* @param bool|array $parent boolean true if Class Parent should be searched, accepts key => value * @param bool|array $parent boolean true if Class Parent should be searched, accepts key => value
* array('parent' => $parent, 'file' => $file, 'search' => $search, 'ext' => '$ext'); * array('parent' => $parent, 'file' => $file, 'search' => $search, 'ext' => '$ext');
* $ext allows setting the extension of the file name * $ext allows setting the extension of the file name

View file

@ -137,6 +137,7 @@ class L10n {
/* Latvian */ 'lav' => 'lv', /* Latvian */ 'lav' => 'lv',
/* Limburgish */ 'lim' => 'li', /* Limburgish */ 'lim' => 'li',
/* Lithuanian */ 'lit' => 'lt', /* Lithuanian */ 'lit' => 'lt',
/* Luxembourgish */ 'ltz' => 'lb',
/* Macedonian */ 'mkd' => 'mk', /* Macedonian */ 'mkd' => 'mk',
/* Macedonian - bibliographic */ 'mac' => 'mk', /* Macedonian - bibliographic */ 'mac' => 'mk',
/* Malaysian */ 'msa' => 'ms', /* Malaysian */ 'msa' => 'ms',
@ -284,6 +285,7 @@ class L10n {
'ko-kp' => array('language' => 'Korea (North)', 'locale' => 'ko_kp', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'), 'ko-kp' => array('language' => 'Korea (North)', 'locale' => 'ko_kp', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
'ko-kr' => array('language' => 'Korea (South)', 'locale' => 'ko_kr', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'), 'ko-kr' => array('language' => 'Korea (South)', 'locale' => 'ko_kr', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'), 'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'),
'lb' => array('language' => 'Luxembourgish', 'locale' => 'ltz', 'localeFallback' => 'ltz', 'charset' => 'utf-8', 'direction' => 'ltr'),
'li' => array('language' => 'Limburgish', 'locale' => 'lim', 'localeFallback' => 'nld', 'charset' => 'utf-8', 'direction' => 'ltr'), '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'), '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' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'),

View file

@ -344,7 +344,7 @@ class TranslateBehavior extends ModelBehavior {
public function afterFind(Model $Model, $results, $primary = false) { public function afterFind(Model $Model, $results, $primary = false) {
$Model->virtualFields = $this->runtime[$Model->alias]['virtualFields']; $Model->virtualFields = $this->runtime[$Model->alias]['virtualFields'];
$this->runtime[$Model->alias]['virtualFields'] = $this->runtime[$Model->alias]['fields'] = array(); $this->runtime[$Model->alias]['virtualFields'] = array();
if (!empty($this->runtime[$Model->alias]['restoreFields'])) { if (!empty($this->runtime[$Model->alias]['restoreFields'])) {
$this->runtime[$Model->alias]['fields'] = $this->runtime[$Model->alias]['restoreFields']; $this->runtime[$Model->alias]['fields'] = $this->runtime[$Model->alias]['restoreFields'];
unset($this->runtime[$Model->alias]['restoreFields']); unset($this->runtime[$Model->alias]['restoreFields']);

View file

@ -432,7 +432,7 @@ class CakeSession {
* Writes value to given session variable name. * Writes value to given session variable name.
* *
* @param string|array $name Name of variable * @param string|array $name Name of variable
* @param string $value Value to write * @param string|array $value Value to write
* @return bool True if the write was successful, false if the write failed * @return bool True if the write was successful, false if the write failed
*/ */
public static function write($name, $value = null) { public static function write($name, $value = null) {

View file

@ -109,7 +109,7 @@ class DboSource extends DataSource {
/** /**
* Result * Result
* *
* @var array * @var array|PDOStatement
*/ */
protected $_result = null; protected $_result = null;
@ -1076,7 +1076,7 @@ class DboSource extends DataSource {
for ($i = 0; $i < $count; $i++) { for ($i = 0; $i < $count; $i++) {
$schema = $Model->schema(); $schema = $Model->schema();
$valueInsert[] = $this->value($values[$i], $Model->getColumnType($fields[$i]), isset($schema[$fields[$i]]) ? $schema[$fields[$i]]['null'] : true); $valueInsert[] = $this->value($values[$i], $Model->getColumnType($fields[$i]), isset($schema[$fields[$i]]['null']) ? $schema[$fields[$i]]['null'] : true);
$fieldInsert[] = $this->name($fields[$i]); $fieldInsert[] = $this->name($fields[$i]);
if ($fields[$i] === $Model->primaryKey) { if ($fields[$i] === $Model->primaryKey) {
$id = $values[$i]; $id = $values[$i];
@ -1566,23 +1566,25 @@ class DboSource extends DataSource {
// Make one pass through children and collect by parent key // Make one pass through children and collect by parent key
// Make second pass through parents and associate children // Make second pass through parents and associate children
$mergedByFK = array(); $mergedByFK = array();
foreach ($assocResultSet as $data) { if (is_array($assocResultSet)) {
$fk = $data[$association][$foreignKey]; foreach ($assocResultSet as $data) {
if (! array_key_exists($fk, $mergedByFK)) { $fk = $data[$association][$foreignKey];
$mergedByFK[$fk] = array(); if (! array_key_exists($fk, $mergedByFK)) {
} $mergedByFK[$fk] = array();
if (count($data) > 1) { }
$data = array_merge($data[$association], $data); if (count($data) > 1) {
unset($data[$association]); $data = array_merge($data[$association], $data);
foreach ($data as $key => $name) { unset($data[$association]);
if (is_numeric($key)) { foreach ($data as $key => $name) {
$data[$association][] = $name; if (is_numeric($key)) {
unset($data[$key]); $data[$association][] = $name;
} unset($data[$key]);
}
}
$mergedByFK[$fk][] = $data;
} else {
$mergedByFK[$fk][] = $data[$association];
} }
$mergedByFK[$fk][] = $data;
} else {
$mergedByFK[$fk][] = $data[$association];
} }
} }
@ -2175,7 +2177,7 @@ class DboSource extends DataSource {
$update = $quoted . ' = '; $update = $quoted . ' = ';
if ($quoteValues) { if ($quoteValues) {
$update .= $this->value($value, $Model->getColumnType($field), isset($schema[$field]) ? $schema[$field]['null'] : true); $update .= $this->value($value, $Model->getColumnType($field), isset($schema[$field]['null']) ? $schema[$field]['null'] : true);
} elseif ($Model->getColumnType($field) === 'boolean' && (is_int($value) || is_bool($value))) { } elseif ($Model->getColumnType($field) === 'boolean' && (is_int($value) || is_bool($value))) {
$update .= $this->boolean($value, true); $update .= $this->boolean($value, true);
} elseif (!$alias) { } elseif (!$alias) {
@ -2576,7 +2578,12 @@ class DboSource extends DataSource {
$virtual = array(); $virtual = array();
foreach ($fields as $field) { foreach ($fields as $field) {
$virtualField = $this->name($alias . $this->virtualFieldSeparator . $field); $virtualField = $this->name($alias . $this->virtualFieldSeparator . $field);
$expression = $this->_quoteFields($Model->getVirtualField($field)); $virtualFieldExpression = $Model->getVirtualField($field);
if (is_object($virtualFieldExpression) && $virtualFieldExpression->type == 'expression') {
$expression = $virtualFieldExpression->value;
} else {
$expression = $this->_quoteFields($virtualFieldExpression);
}
$virtual[] = '(' . $expression . ") {$this->alias} {$virtualField}"; $virtual[] = '(' . $expression . ") {$this->alias} {$virtualField}";
} }
return $virtual; return $virtual;
@ -2885,7 +2892,12 @@ class DboSource extends DataSource {
if ($Model !== null) { if ($Model !== null) {
if ($Model->isVirtualField($key)) { if ($Model->isVirtualField($key)) {
$key = $this->_quoteFields($Model->getVirtualField($key)); $virtualField = $Model->getVirtualField($key);
if (is_object($virtualField) && $virtualField->type == 'expression') {
$key = $virtualField->value;
} else {
$key = $this->_quoteFields($virtualField);
}
$virtual = true; $virtual = true;
} }
@ -3034,12 +3046,12 @@ class DboSource extends DataSource {
if (!is_array($keys)) { if (!is_array($keys)) {
$keys = array($keys); $keys = array($keys);
} }
$keys = array_filter($keys); $keys = array_filter($keys);
$result = array(); $result = array();
while (!empty($keys)) { while (!empty($keys)) {
list($key, $dir) = each($keys); $key = key($keys);
$dir = current($keys);
array_shift($keys); array_shift($keys);
if (is_numeric($key)) { if (is_numeric($key)) {

View file

@ -1648,7 +1648,7 @@ class Model extends CakeObject implements CakeEventListener {
* *
* @param string $name The name of the field to get. * @param string $name The name of the field to get.
* @param array $conditions SQL conditions (defaults to NULL). * @param array $conditions SQL conditions (defaults to NULL).
* @param string $order SQL ORDER BY fragment. * @param string|array $order SQL ORDER BY fragment.
* @return string|false Field content, or false if not found. * @return string|false Field content, or false if not found.
* @link https://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-field * @link https://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-field
*/ */

View file

@ -594,7 +594,7 @@ class ModelValidator implements ArrayAccess, IteratorAggregate, Countable {
$this->_parseRules(); $this->_parseRules();
if ($rule === null) { if ($rule === null) {
unset($this->_fields[$field]); unset($this->_fields[$field]);
} else { } elseif (array_key_exists($field, $this->_fields)) {
$this->_fields[$field]->removeRule($rule); $this->_fields[$field]->removeRule($rule);
} }
return $this; return $this;

View file

@ -589,7 +589,7 @@ class CakeEmail {
*/ */
protected function _setEmail($varName, $email, $name) { protected function _setEmail($varName, $email, $name) {
if (!is_array($email)) { if (!is_array($email)) {
$this->_validateEmail($email); $this->_validateEmail($email, $varName);
if ($name === null) { if ($name === null) {
$name = $email; $name = $email;
} }
@ -601,7 +601,7 @@ class CakeEmail {
if (is_int($key)) { if (is_int($key)) {
$key = $value; $key = $value;
} }
$this->_validateEmail($key); $this->_validateEmail($key, $varName);
$list[$key] = $value; $list[$key] = $value;
} }
$this->{$varName} = $list; $this->{$varName} = $list;
@ -611,11 +611,12 @@ class CakeEmail {
/** /**
* Validate email address * Validate email address
* *
* @param string $email Email * @param string $email Email address to validate
* @param string $context Which property was set
* @return void * @return void
* @throws SocketException If email address does not validate * @throws SocketException If email address does not validate
*/ */
protected function _validateEmail($email) { protected function _validateEmail($email, $context) {
if ($this->_emailPattern === null) { if ($this->_emailPattern === null) {
if (filter_var($email, FILTER_VALIDATE_EMAIL)) { if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
return; return;
@ -623,7 +624,10 @@ class CakeEmail {
} elseif (preg_match($this->_emailPattern, $email)) { } elseif (preg_match($this->_emailPattern, $email)) {
return; return;
} }
throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email)); if ($email == '') {
throw new SocketException(__d('cake_dev', 'The email set for "%s" is empty.', $context));
}
throw new SocketException(__d('cake_dev', 'Invalid email set for "%s". You passed "%s".', $context, $email));
} }
/** /**
@ -659,7 +663,7 @@ class CakeEmail {
*/ */
protected function _addEmail($varName, $email, $name) { protected function _addEmail($varName, $email, $name) {
if (!is_array($email)) { if (!is_array($email)) {
$this->_validateEmail($email); $this->_validateEmail($email, $varName);
if ($name === null) { if ($name === null) {
$name = $email; $name = $email;
} }
@ -671,7 +675,7 @@ class CakeEmail {
if (is_int($key)) { if (is_int($key)) {
$key = $value; $key = $value;
} }
$this->_validateEmail($key); $this->_validateEmail($key, $varName);
$list[$key] = $value; $list[$key] = $value;
} }
$this->{$varName} = array_merge($this->{$varName}, $list); $this->{$varName} = array_merge($this->{$varName}, $list);
@ -788,7 +792,7 @@ class CakeEmail {
} }
if ($this->_messageId !== false) { if ($this->_messageId !== false) {
if ($this->_messageId === true) { if ($this->_messageId === true) {
$headers['Message-ID'] = '<' . str_replace('-', '', CakeText::UUID()) . '@' . $this->_domain . '>'; $headers['Message-ID'] = '<' . str_replace('-', '', CakeText::uuid()) . '@' . $this->_domain . '>';
} else { } else {
$headers['Message-ID'] = $this->_messageId; $headers['Message-ID'] = $this->_messageId;
} }

View file

@ -1144,6 +1144,16 @@ class TranslateBehaviorTest extends CakeTestCase {
$TestModel->bindTranslation($translations); $TestModel->bindTranslation($translations);
$result = $TestModel->find('first'); $result = $TestModel->find('first');
$TestModel->find('first', array(
'fields' => array(
'TranslatedItem.title',
),
));
$TestModel->find('first', array(
'fields' => array(
'TranslatedItem.title',
),
));
$this->assertArrayHasKey('Title', $result); $this->assertArrayHasKey('Title', $result);
$this->assertArrayHasKey('content', $result['Title'][0]); $this->assertArrayHasKey('content', $result['Title'][0]);
$this->assertArrayNotHasKey('title', $result); $this->assertArrayNotHasKey('title', $result);

View file

@ -1650,6 +1650,42 @@ class DboSourceTest extends CakeTestCase {
$this->assertEquals($expected, $result[0]); $this->assertEquals($expected, $result[0]);
} }
/**
* Test conditionKeysToString() with virtual field
*
* @return void
*/
public function testConditionKeysToStringVirtualFieldExpression() {
$Article = ClassRegistry::init('Article');
$Article->virtualFields = array(
'extra' => $Article->getDataSource()->expression('something virtual')
);
$conn = $this->getMock('MockPDO', array('quote'));
$db = new DboTestSource();
$db->setConnection($conn);
$conn->expects($this->at(0))
->method('quote')
->will($this->returnValue('just text'));
$conditions = array('Article.extra' => 'just text');
$result = $db->conditionKeysToString($conditions, true, $Article);
$expected = "(" . $Article->virtualFields['extra']->value . ") = just text";
$this->assertEquals($expected, $result[0]);
$conn->expects($this->at(0))
->method('quote')
->will($this->returnValue('just text'));
$conn->expects($this->at(1))
->method('quote')
->will($this->returnValue('other text'));
$conditions = array('Article.extra' => array('just text', 'other text'));
$result = $db->conditionKeysToString($conditions, true, $Article);
$expected = "(" . $Article->virtualFields['extra']->value . ") IN (just text, other text)";
$this->assertEquals($expected, $result[0]);
}
/** /**
* Test conditionKeysToString() with virtual field * Test conditionKeysToString() with virtual field
* *

View file

@ -2007,6 +2007,9 @@ class ModelValidationTest extends BaseModelTest {
$this->assertTrue(isset($Validator['other'])); $this->assertTrue(isset($Validator['other']));
$this->assertFalse(isset($Validator['other']['numeric'])); $this->assertFalse(isset($Validator['other']['numeric']));
$this->assertTrue(isset($Validator['other']['between'])); $this->assertTrue(isset($Validator['other']['between']));
$Validator->remove('other');
$Validator->remove('other', 'between');
} }
/** /**

View file

@ -334,23 +334,34 @@ class CakeEmailTest extends CakeTestCase {
/** /**
* testBuildInvalidData * testBuildInvalidData
* *
* @dataProvider invalidEmails
* @expectedException SocketException * @expectedException SocketException
* @expectedExceptionMessage The email set for "_to" is empty.
* @return void * @return void
*/ */
public function testInvalidEmail($value) { public function testInvalidEmail() {
$this->CakeEmail->to($value); $this->CakeEmail->to('');
} }
/** /**
* testBuildInvalidData * testBuildInvalidData
* *
* @dataProvider invalidEmails
* @expectedException SocketException * @expectedException SocketException
* @expectedExceptionMessage Invalid email set for "_from". You passed "cake.@"
* @return void * @return void
*/ */
public function testInvalidEmailAdd($value) { public function testInvalidFrom() {
$this->CakeEmail->addTo($value); $this->CakeEmail->from('cake.@');
}
/**
* testBuildInvalidData
*
* @expectedException SocketException
* @expectedExceptionMessage Invalid email set for "_to". You passed "1"
* @return void
*/
public function testInvalidEmailAdd() {
$this->CakeEmail->addTo('1');
} }
/** /**
@ -423,7 +434,7 @@ class CakeEmailTest extends CakeTestCase {
* @return void * @return void
* *
* @expectedException SocketException * @expectedException SocketException
* @expectedExceptionMessage Invalid email: "fail.@example.com" * @expectedExceptionMessage Invalid email set for "_to". You passed "fail.@example.com"
*/ */
public function testUnsetEmailPattern() { public function testUnsetEmailPattern() {
$email = new CakeEmail(); $email = new CakeEmail();

View file

@ -445,7 +445,8 @@ class CakeTestCaseTest extends CakeTestCase {
), App::RESET); ), App::RESET);
CakePlugin::load('TestPlugin'); CakePlugin::load('TestPlugin');
ConnectionManager::create('test_secondary', array( ConnectionManager::create('test_secondary', array(
'datasource' => 'Database/TestLocalDriver' 'datasource' => 'Database/TestLocalDriver',
'prefix' => ''
)); ));
$post = $this->getMockForModel('SecondaryPost', array('save')); $post = $this->getMockForModel('SecondaryPost', array('save'));
$this->assertEquals('test_secondary', $post->useDbConfig); $this->assertEquals('test_secondary', $post->useDbConfig);

View file

@ -29,6 +29,26 @@ class SecurityTest extends CakeTestCase {
*/ */
public $sut = null; public $sut = null;
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
Configure::delete('Security.useOpenSsl');
}
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
Configure::delete('Security.useOpenSsl');
}
/** /**
* testInactiveMins method * testInactiveMins method
* *
@ -337,6 +357,54 @@ class SecurityTest extends CakeTestCase {
$this->assertEquals($txt, Security::decrypt($result, $key)); $this->assertEquals($txt, Security::decrypt($result, $key));
} }
/**
* Tests that encrypted strings are compatible between the mcrypt and openssl engine.
*
* @dataProvider plainTextProvider
* @param string $txt Plain text to be encrypted.
* @return void
*/
public function testEncryptDecryptCompatibility($txt) {
$this->skipIf(!extension_loaded('mcrypt'), 'This test requires mcrypt to be installed');
$this->skipIf(!extension_loaded('openssl'), 'This test requires openssl to be installed');
$this->skipIf(version_compare(PHP_VERSION, '5.3.3', '<'), 'This test requires PHP 5.3.3 or greater');
$key = '12345678901234567890123456789012';
Configure::write('Security.useOpenSsl', false);
$mcrypt = Security::encrypt($txt, $key);
Configure::write('Security.useOpenSsl', true);
$openssl = Security::encrypt($txt, $key);
$this->assertEquals(strlen($mcrypt), strlen($openssl));
Configure::write('Security.useOpenSsl', false);
$this->assertEquals($txt, Security::decrypt($mcrypt, $key));
$this->assertEquals($txt, Security::decrypt($openssl, $key));
Configure::write('Security.useOpenSsl', true);
$this->assertEquals($txt, Security::decrypt($mcrypt, $key));
$this->assertEquals($txt, Security::decrypt($openssl, $key));
}
/**
* Data provider for testEncryptDecryptCompatibility
*
* @return array
*/
public function plainTextProvider() {
return array(
array(''),
array('abcdefg'),
array('1234567890123456'),
array('The quick brown fox'),
array('12345678901234567890123456789012'),
array('The quick brown fox jumped over the lazy dog.'),
array('何らかのマルチバイト文字列'),
);
}
/** /**
* Test that changing the key causes decryption to fail. * Test that changing the key causes decryption to fail.
* *

View file

@ -866,7 +866,8 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
$availableDs = array_keys(ConnectionManager::enumConnectionObjects()); $availableDs = array_keys(ConnectionManager::enumConnectionObjects());
if ($mock->useDbConfig !== 'test' && in_array('test_' . $mock->useDbConfig, $availableDs)) { if ($mock->useDbConfig !== 'test' && in_array('test_' . $mock->useDbConfig, $availableDs)) {
$mock->setDataSource('test_' . $mock->useDbConfig); $mock->useDbConfig = 'test_' . $mock->useDbConfig;
$mock->setDataSource($mock->useDbConfig);
} else { } else {
$mock->useDbConfig = 'test'; $mock->useDbConfig = 'test';
$mock->setDataSource('test'); $mock->setDataSource('test');

View file

@ -18,6 +18,14 @@
if (!class_exists('PHPUnit_TextUI_TestRunner')) { if (!class_exists('PHPUnit_TextUI_TestRunner')) {
require_once 'PHPUnit/TextUI/TestRunner.php'; require_once 'PHPUnit/TextUI/TestRunner.php';
} }
if (class_exists('SebastianBergmann\CodeCoverage\CodeCoverage')) {
class_alias('SebastianBergmann\CodeCoverage\CodeCoverage', 'PHP_CodeCoverage');
class_alias('SebastianBergmann\CodeCoverage\Report\Text', 'PHP_CodeCoverage_Report_Text');
class_alias('SebastianBergmann\CodeCoverage\Report\PHP', 'PHP_CodeCoverage_Report_PHP');
class_alias('SebastianBergmann\CodeCoverage\Report\Clover', 'PHP_CodeCoverage_Report_Clover');
class_alias('SebastianBergmann\CodeCoverage\Report\Html\Facade', 'PHP_CodeCoverage_Report_HTML');
class_alias('SebastianBergmann\CodeCoverage\Exception', 'PHP_CodeCoverage_Exception');
}
App::uses('CakeFixtureManager', 'TestSuite/Fixture'); App::uses('CakeFixtureManager', 'TestSuite/Fixture');

View file

@ -184,9 +184,12 @@ class Security {
if (function_exists('openssl_random_pseudo_bytes')) { if (function_exists('openssl_random_pseudo_bytes')) {
return openssl_random_pseudo_bytes($length); return openssl_random_pseudo_bytes($length);
} }
if (function_exists('mcrypt_create_iv')) {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
trigger_error( trigger_error(
'You do not have a safe source of random data available. ' . 'You do not have a safe source of random data available. ' .
'Install either the openssl extension, or paragonie/random_compat. ' . 'Install either the openssl extension, the mcrypt extension, or paragonie/random_compat. ' .
'Falling back to an insecure random source.', 'Falling back to an insecure random source.',
E_USER_WARNING E_USER_WARNING
); );
@ -206,7 +209,7 @@ class Security {
* for sensitive data. Additionally this method does *not* work in environments * for sensitive data. Additionally this method does *not* work in environments
* where suhosin is enabled. * where suhosin is enabled.
* *
* Instead you should use Security::rijndael() when you need strong * Instead you should use Security::encrypt() when you need strong
* encryption. * encryption.
* *
* @param string $text Encrypted string to decrypt, normal string to encrypt * @param string $text Encrypted string to decrypt, normal string to encrypt
@ -349,12 +352,24 @@ class Security {
// Generate the encryption and hmac key. // Generate the encryption and hmac key.
$key = substr(hash('sha256', $key . $hmacSalt), 0, 32); $key = substr(hash('sha256', $key . $hmacSalt), 0, 32);
$algorithm = MCRYPT_RIJNDAEL_128; if (Configure::read('Security.useOpenSsl')) {
$mode = MCRYPT_MODE_CBC; $method = 'AES-256-CBC';
$ivSize = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivSize);
$padLength = (int)ceil((strlen($plain) ?: 1) / $ivSize) * $ivSize;
$ciphertext = openssl_encrypt(str_pad($plain, $padLength, "\0"), $method, $key, true, $iv);
// Remove the PKCS#7 padding block for compatibility with mcrypt.
// Since we have padded the provided data with \0, the final block contains only padded bytes.
// So it can be removed safely.
$ciphertext = $iv . substr($ciphertext, 0, -$ivSize);
} else {
$algorithm = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_CBC;
$ivSize = mcrypt_get_iv_size($algorithm, $mode);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$ciphertext = $iv . mcrypt_encrypt($algorithm, $key, $plain, $mode, $iv);
}
$ivSize = mcrypt_get_iv_size($algorithm, $mode);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$ciphertext = $iv . mcrypt_encrypt($algorithm, $key, $plain, $mode, $iv);
$hmac = hash_hmac('sha256', $ciphertext, $key); $hmac = hash_hmac('sha256', $ciphertext, $key);
return $hmac . $ciphertext; return $hmac . $ciphertext;
} }
@ -404,13 +419,23 @@ class Security {
return false; return false;
} }
$algorithm = MCRYPT_RIJNDAEL_128; if (Configure::read('Security.useOpenSsl')) {
$mode = MCRYPT_MODE_CBC; $method = 'AES-256-CBC';
$ivSize = mcrypt_get_iv_size($algorithm, $mode); $ivSize = openssl_cipher_iv_length($method);
$iv = substr($cipher, 0, $ivSize);
$cipher = substr($cipher, $ivSize);
// Regenerate PKCS#7 padding block
$padding = openssl_encrypt('', $method, $key, true, substr($cipher, -$ivSize));
$plain = openssl_decrypt($cipher . $padding, $method, $key, true, $iv);
} else {
$algorithm = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_CBC;
$ivSize = mcrypt_get_iv_size($algorithm, $mode);
$iv = substr($cipher, 0, $ivSize);
$cipher = substr($cipher, $ivSize);
$plain = mcrypt_decrypt($algorithm, $key, $cipher, $mode, $iv);
}
$iv = substr($cipher, 0, $ivSize);
$cipher = substr($cipher, $ivSize);
$plain = mcrypt_decrypt($algorithm, $key, $cipher, $mode, $iv);
return rtrim($plain, "\0"); return rtrim($plain, "\0");
} }

View file

@ -17,4 +17,4 @@
// @license https://opensource.org/licenses/mit-license.php MIT License // @license https://opensource.org/licenses/mit-license.php MIT License
// +--------------------------------------------------------------------------------------------+ // // +--------------------------------------------------------------------------------------------+ //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
2.10.7 2.10.11