ENHANCEMENT Session::start() now only called when there is changed

session data to be saved, and started on Director::direct() when there
is a cookie (or request var) containing the current PHP session name.
This commit is contained in:
Sean Harvey 2012-04-26 16:43:58 +12:00
parent bd6ca59558
commit f63d137d49
6 changed files with 89 additions and 31 deletions

View File

@ -94,6 +94,8 @@ class Director implements TemplateGlobalProvider {
}
// Load the session into the controller
if(!isset($_SESSION) && (isset($_COOKIE[session_name()]) || isset($_REQUEST[session_name()]))) Session::start();
$session = new Session(isset($_SESSION) ? $_SESSION : null);
$result = Director::handleRequest($req, $session, $model);

View File

@ -102,6 +102,17 @@ class Session {
protected $changedData = array();
/**
* Start PHP session, then create a new Session object with the given start data.
*
* @param $data Can be an array of data (such as $_SESSION) or another Session object to clone.
*/
function __construct($data) {
if($data instanceof Session) $data = $data->inst_getAll();
$this->data = $data;
}
/**
* Cookie domain, for example 'www.php.net'.
*
@ -176,17 +187,6 @@ class Session {
return self::$session_store_path;
}
/**
* Create a new session object, with the given starting data
*
* @param $data Can be an array of data (such as $_SESSION) or another Session object to clone.
*/
function __construct($data) {
if($data instanceof Session) $data = $data->inst_getAll();
$this->data = $data;
}
/**
* Provide an <code>array</code> of rules specifing timeouts for IPv4 address ranges or
* individual IPv4 addresses. The key is an IP address or range and the value is the time
@ -301,10 +301,12 @@ class Session {
$diffVar = &$diffVar[$n];
}
if($var !== $val) {
$var = $val;
$diffVar = $val;
}
}
}
public function inst_addToArray($name, $val) {
$names = explode('.', $name);
@ -355,13 +357,21 @@ class Session {
$diffVar = &$this->changedData;
foreach($names as $n) {
// don't clear a record that doesn't exist
if(!isset($var[$n])) return;
$var = &$var[$n];
}
// only loop to find data within diffVar if var is proven to exist in the above loop
foreach($names as $n) {
$diffVar = &$diffVar[$n];
}
if($var !== null) {
$var = null;
$diffVar = null;
}
}
public function inst_clearAll() {
if($this->data && is_array($this->data)) {
@ -380,8 +390,11 @@ class Session {
* Only save the changes, so that anyone manipulating $_SESSION directly doesn't get burned.
*/
public function inst_save() {
if($this->changedData) {
if(!isset($_SESSION)) Session::start();
$this->recursivelyApply($this->changedData, $_SESSION);
}
}
/**
* Recursively apply the changes represented in $data to $dest.
@ -398,6 +411,14 @@ class Session {
}
}
/**
* Return the changed data, for debugging purposes.
* @return array
*/
public function inst_changedData() {
return $this->changedData;
}
/**
* Sets the appropriate form message in session, with type. This will be shown once,
* for the form specified.

View File

@ -59,9 +59,7 @@ if (version_compare(phpversion(), '5.3.2', '<')) {
/**
* Include SilverStripe's core code
*/
require_once("core/Core.php");
Session::start();
require_once('core/Core.php');
// IIS will sometimes generate this.
if(!empty($_SERVER['HTTP_X_ORIGINAL_URL'])) {

View File

@ -791,9 +791,17 @@ class Versioned extends DataExtension {
if(!headers_sent() && !Director::is_cli()) {
if(Versioned::current_stage() == 'Live') {
// clear the cookie if it's set
if(!empty($_COOKIE['bypassStaticCache'])) {
Cookie::set('bypassStaticCache', null, 0, null, null, false, true /* httponly */);
unset($_COOKIE['bypassStaticCache']);
}
} else {
// set the cookie if it's cleared
if(empty($_COOKIE['bypassStaticCache'])) {
Cookie::set('bypassStaticCache', '1', 0, null, null, false, true /* httponly */);
$_COOKIE['bypassStaticCache'] = 1;
}
}
}
}

View File

@ -55,9 +55,6 @@ class SecurityToken extends Object implements TemplateGlobalProvider {
*/
function __construct($name = null) {
$this->name = ($name) ? $name : self::get_default_name();
// only regenerate if the token isn't already set in the session
if(!$this->getValue()) $this->setValue($this->generate());
parent::__construct();
}
@ -132,7 +129,15 @@ class SecurityToken extends Object implements TemplateGlobalProvider {
* @return String
*/
function getValue() {
return Session::get($this->getName());
$value = Session::get($this->getName());
// only regenerate if the token isn't already set in the session
if(!$value) {
$value = $this->generate();
$this->setValue($value);
}
return $value;
}
/**

View File

@ -45,6 +45,30 @@ class SessionTest extends SapphireTest {
$this->assertEquals($session, array('Test' => 'Test', 'Test-2' => 'Test-2'));
}
/**
* Check that changedData isn't populated with junk when clearing non-existent entries.
*/
function testClearElementThatDoesntExist() {
$s = new Session(array('something' => array('does' => 'exist')));
$s->inst_clear('something.doesnt.exist');
$this->assertEquals(array(), $s->inst_changedData());
$s->inst_set('something-else', 'val');
$s->inst_clear('something-new');
$this->assertEquals(array('something-else' => 'val'), $s->inst_changedData());
}
/**
* Check that changedData is populated with clearing data.
*/
function testClearElementThatDoesExist() {
$s = new Session(array('something' => array('does' => 'exist')));
$s->inst_clear('something.does');
$this->assertEquals(array('something' => array('does' => null)), $s->inst_changedData());
}
function testNonStandardPath(){
Session::set_session_store_path(realpath(dirname($_SERVER['DOCUMENT_ROOT']) . '/../session'));
Session::start();