Merge branch 'master' into 2.5

This commit is contained in:
mark_story 2013-12-14 17:45:49 -05:00
commit c2b8778ce8
29 changed files with 150 additions and 29 deletions

View file

@ -18,6 +18,7 @@
* @since CakePHP(tm) v 0.2.9 * @since CakePHP(tm) v 0.2.9
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('Controller', 'Controller'); App::uses('Controller', 'Controller');
/** /**

View file

@ -17,6 +17,7 @@
* @since CakePHP(tm) v 0.2.9 * @since CakePHP(tm) v 0.2.9
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('AppController', 'Controller'); App::uses('AppController', 'Controller');
/** /**

View file

@ -18,6 +18,7 @@
* @since CakePHP(tm) v 0.2.9 * @since CakePHP(tm) v 0.2.9
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('Helper', 'View'); App::uses('Helper', 'View');
/** /**

View file

@ -14,6 +14,7 @@
* @since CakePHP(tm) v 2.4.0 * @since CakePHP(tm) v 2.4.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth'); App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
App::uses('Security', 'Utility'); App::uses('Security', 'Utility');

View file

@ -14,6 +14,7 @@
* @since CakePHP(tm) v 2.4.0 * @since CakePHP(tm) v 2.4.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth'); App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
App::uses('Security', 'Utility'); App::uses('Security', 'Utility');

View file

@ -120,6 +120,13 @@ class CakeSession {
*/ */
public static $requestCountdown = 10; public static $requestCountdown = 10;
/**
* Whether or not the init function in this class was already called
*
* @var boolean
*/
protected static $_initialized = false;
/** /**
* Pseudo constructor. * Pseudo constructor.
* *
@ -128,15 +135,20 @@ class CakeSession {
*/ */
public static function init($base = null) { public static function init($base = null) {
self::$time = time(); self::$time = time();
$checkAgent = Configure::read('Session.checkAgent'); $checkAgent = Configure::read('Session.checkAgent');
if (env('HTTP_USER_AGENT')) { if (env('HTTP_USER_AGENT')) {
self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt')); self::$_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
} }
self::_setPath($base); self::_setPath($base);
self::_setHost(env('HTTP_HOST')); self::_setHost(env('HTTP_HOST'));
register_shutdown_function('session_write_close'); if (!self::$_initialized) {
register_shutdown_function('session_write_close');
}
self::$_initialized = true;
} }
/** /**
@ -181,10 +193,8 @@ class CakeSession {
if (self::started()) { if (self::started()) {
return true; return true;
} }
self::init();
$id = self::id(); $id = self::id();
session_write_close();
self::_configureSession();
self::_startSession(); self::_startSession();
if (!$id && self::started()) { if (!$id && self::started()) {
@ -192,6 +202,7 @@ class CakeSession {
} }
self::$error = false; self::$error = false;
self::$valid = true;
return self::started(); return self::started();
} }
@ -424,9 +435,14 @@ class CakeSession {
* @return void * @return void
*/ */
public static function destroy() { public static function destroy() {
self::start(); if (!self::started()) {
self::_startSession();
}
session_destroy(); session_destroy();
self::clear();
$_SESSION = null;
self::$id = null;
} }
/** /**
@ -437,7 +453,6 @@ class CakeSession {
public static function clear() { public static function clear() {
$_SESSION = null; $_SESSION = null;
self::$id = null; self::$id = null;
self::start();
self::renew(); self::renew();
} }
@ -600,6 +615,10 @@ class CakeSession {
* @return boolean Success * @return boolean Success
*/ */
protected static function _startSession() { protected static function _startSession() {
self::init();
session_write_close();
self::_configureSession();
if (headers_sent()) { if (headers_sent()) {
if (empty($_SESSION)) { if (empty($_SESSION)) {
$_SESSION = array(); $_SESSION = array();
@ -618,14 +637,11 @@ class CakeSession {
* @return void * @return void
*/ */
protected static function _checkValid() { protected static function _checkValid() {
if (!self::start()) { $config = self::read('Config');
self::$valid = false; if ($config) {
return false;
}
if ($config = self::read('Config')) {
$sessionConfig = Configure::read('Session'); $sessionConfig = Configure::read('Session');
if (self::_validAgentAndTime()) { if (self::valid()) {
self::write('Config.time', self::$sessionTime); self::write('Config.time', self::$sessionTime);
if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) {
$check = $config['countdown']; $check = $config['countdown'];
@ -637,20 +653,29 @@ class CakeSession {
self::write('Config.countdown', self::$requestCountdown); self::write('Config.countdown', self::$requestCountdown);
} }
} }
self::$valid = true;
} else { } else {
$_SESSION = array();
self::destroy(); self::destroy();
self::$valid = false;
self::_setError(1, 'Session Highjacking Attempted !!!'); self::_setError(1, 'Session Highjacking Attempted !!!');
self::_startSession();
self::_writeConfig();
} }
} else { } else {
self::write('Config.userAgent', self::$_userAgent); self::_writeConfig();
self::write('Config.time', self::$sessionTime);
self::write('Config.countdown', self::$requestCountdown);
self::$valid = true;
} }
} }
/**
* Writes configuration variables to the session
*
* @return void
*/
protected static function _writeConfig() {
self::write('Config.userAgent', self::$_userAgent);
self::write('Config.time', self::$sessionTime);
self::write('Config.countdown', self::$requestCountdown);
}
/** /**
* Restarts this session. * Restarts this session.
* *

View file

@ -429,9 +429,9 @@ class CakeResponse {
} }
/** /**
* Sets the cookies that have been added via static method CakeResponse::addCookie() * Sets the cookies that have been added via CakeResponse::cookie() before any
* before any other output is sent to the client. * other output is sent to the client. Will set the cookies in the order they
* Will set the cookies in the order they have been set. * have been set.
* *
* @return void * @return void
*/ */

View file

@ -17,6 +17,7 @@
*/ */
require_once CAKE . 'basics.php'; require_once CAKE . 'basics.php';
App::uses('Folder', 'Utility'); App::uses('Folder', 'Utility');
App::uses('CakeResponse', 'Network'); App::uses('CakeResponse', 'Network');

View file

@ -18,6 +18,7 @@
App::uses('TaskCollection', 'Console'); App::uses('TaskCollection', 'Console');
App::uses('Shell', 'Console'); App::uses('Shell', 'Console');
/** /**
* Extended Task * Extended Task
*/ */

View file

@ -175,6 +175,7 @@ class SessionComponentTest extends CakeTestCase {
* @return void * @return void
*/ */
public function testSessionError() { public function testSessionError() {
CakeSession::$lastError = null;
$Session = new SessionComponent($this->ComponentCollection); $Session = new SessionComponent($this->ComponentCollection);
$this->assertFalse($Session->error()); $this->assertFalse($Session->error());
} }

View file

@ -15,6 +15,7 @@
* @since CakePHP(tm) v 2.4 * @since CakePHP(tm) v 2.4
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('SyslogLog', 'Log/Engine'); App::uses('SyslogLog', 'Log/Engine');
/** /**

View file

@ -15,6 +15,7 @@
* @since CakePHP(tm) v 2.4 * @since CakePHP(tm) v 2.4
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
App::uses('LogEngineCollection', 'Log'); App::uses('LogEngineCollection', 'Log');
App::uses('FileLog', 'Log/Engine'); App::uses('FileLog', 'Log/Engine');

View file

@ -18,6 +18,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -15,6 +15,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -18,6 +18,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -20,6 +20,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -20,6 +20,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -21,6 +21,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
App::uses('String', 'Utility'); App::uses('String', 'Utility');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -19,6 +19,7 @@
*/ */
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(__FILE__) . DS . 'models.php'; require_once dirname(__FILE__) . DS . 'models.php';
/** /**

View file

@ -546,9 +546,13 @@ class CakeSessionTest extends CakeTestCase {
'engine' => 'TestAppLibSession' 'engine' => 'TestAppLibSession'
) )
)); ));
TestCakeSession::destroy();
TestCakeSession::start();
$this->assertTrue(TestCakeSession::started()); $this->assertTrue(TestCakeSession::started());
TestCakeSession::destroy();
$this->assertFalse(TestCakeSession::started());
App::build(); App::build();
} }
@ -570,9 +574,12 @@ class CakeSessionTest extends CakeTestCase {
) )
)); ));
TestCakeSession::destroy(); TestCakeSession::start();
$this->assertTrue(TestCakeSession::started()); $this->assertTrue(TestCakeSession::started());
TestCakeSession::destroy();
$this->assertFalse(TestCakeSession::started());
App::build(); App::build();
} }
@ -750,4 +757,31 @@ class CakeSessionTest extends CakeTestCase {
$this->assertEquals(400, Configure::read('Session.timeout')); $this->assertEquals(400, Configure::read('Session.timeout'));
} }
/**
* Proves that invalid sessions will be destroyed and re-created
* if invalid
*
* @return void
*/
public function testInvalidSessionRenew() {
TestCakeSession::start();
$this->assertNotEmpty($_SESSION['Config']);
$data = $_SESSION;
session_write_close();
$_SESSION = null;
TestCakeSession::start();
$this->assertEquals($data, $_SESSION);
TestCakeSession::write('Foo', 'Bar');
session_write_close();
$_SESSION = null;
TestCakeSession::userAgent('bogus!');
TestCakeSession::start();
$this->assertNotEquals($data, $_SESSION);
$this->assertEquals('bogus!', $_SESSION['Config']['userAgent']);
}
} }

View file

@ -23,6 +23,7 @@ App::uses('DboSource', 'Model/Datasource');
App::uses('DboTestSource', 'Model/Datasource'); App::uses('DboTestSource', 'Model/Datasource');
App::uses('DboSecondTestSource', 'Model/Datasource'); App::uses('DboSecondTestSource', 'Model/Datasource');
App::uses('MockDataSource', 'Model/Datasource'); App::uses('MockDataSource', 'Model/Datasource');
require_once dirname(dirname(__FILE__)) . DS . 'models.php'; require_once dirname(dirname(__FILE__)) . DS . 'models.php';
/** /**

View file

@ -17,6 +17,7 @@
*/ */
require_once dirname(__FILE__) . DS . 'ModelTestBase.php'; require_once dirname(__FILE__) . DS . 'ModelTestBase.php';
App::uses('DboSource', 'Model/Datasource'); App::uses('DboSource', 'Model/Datasource');
App::uses('DboMock', 'Model/Datasource'); App::uses('DboMock', 'Model/Datasource');

View file

@ -18,6 +18,7 @@
App::uses('Model', 'Model'); App::uses('Model', 'Model');
App::uses('AppModel', 'Model'); App::uses('AppModel', 'Model');
require_once dirname(__FILE__) . DS . 'models.php'; require_once dirname(__FILE__) . DS . 'models.php';
/** /**

View file

@ -5027,6 +5027,23 @@ class ModelWriteTest extends BaseModelTest {
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);
} }
/**
* Test SaveMany with validate=false.
*
* @return void
*/
public function testSaveManyValidateFalse() {
$this->loadFixtures('Post');
$TestModel = new Post();
$TestModel->deleteAll(true);
$data = array(
array('id' => 1, 'author_id' => 1, 'title' => 'hi'),
array('id' => 2, 'author_id' => 1, 'title' => 'bye')
);
$result = $TestModel->saveAll($data, array('validate' => false));
$this->assertTrue($result);
}
/** /**
* Test SaveAssociated with Habtm relations * Test SaveAssociated with Habtm relations
* *

View file

@ -669,6 +669,9 @@ class HashTest extends CakeTestCase {
$data = array('one', 2 => 'two', 3 => 'three', 4 => 'four', 'a' => 'five'); $data = array('one', 2 => 'two', 3 => 'three', 4 => 'four', 'a' => 'five');
$this->assertFalse(Hash::numeric(array_keys($data))); $this->assertFalse(Hash::numeric(array_keys($data)));
$data = array(2.4, 1, 0, -1, -2);
$this->assertTrue(Hash::numeric($data));
} }
/** /**
@ -832,6 +835,26 @@ class HashTest extends CakeTestCase {
$this->assertEquals(5, $result[3]['id']); $this->assertEquals(5, $result[3]['id']);
} }
/**
* Test that attribute matchers don't cause errors on scalar data.
*
* @return void
*/
public function testExtractAttributeEqualityOnScalarValue() {
$data = array(
'Entity' => array(
'id' => 1,
'data1' => 'value',
)
);
$result = Hash::extract($data, 'Entity[id=1].data1');
$this->assertEquals(array('value'), $result);
$data = array('Entity' => false );
$result = Hash::extract($data, 'Entity[id=1].data1');
$this->assertEquals(array(), $result);
}
/** /**
* Test comparison operators. * Test comparison operators.
* *

View file

@ -1,4 +1,6 @@
<?php <?php
App::uses('TestSource', 'TestPlugin.Model/Datasource'); App::uses('TestSource', 'TestPlugin.Model/Datasource');
class TestLocalDriver extends TestSource { class TestLocalDriver extends TestSource {
} }

View file

@ -1,4 +1,5 @@
<?php <?php
App::uses('DboSource', 'Model/Datasource'); App::uses('DboSource', 'Model/Datasource');
class DboDummy extends DboSource { class DboDummy extends DboSource {

View file

@ -1,4 +1,5 @@
<?php <?php
App::uses('DataSource', 'Model/Datasource'); App::uses('DataSource', 'Model/Datasource');
class TestSource extends DataSource { class TestSource extends DataSource {

View file

@ -126,7 +126,7 @@ class Hash {
if ($conditions) { if ($conditions) {
$filter = array(); $filter = array();
foreach ($next as $item) { foreach ($next as $item) {
if (self::_matches($item, $conditions)) { if (is_array($item) && self::_matches($item, $conditions)) {
$filter[] = $item; $filter[] = $item;
} }
} }
@ -667,9 +667,7 @@ class Hash {
if (empty($data)) { if (empty($data)) {
return false; return false;
} }
$values = array_values($data); return $data === array_filter($data, 'is_numeric');
$str = implode('', $values);
return (bool)ctype_digit($str);
} }
/** /**