add symfony http-foundation.

This commit is contained in:
Taylor Otwell
2012-03-28 15:37:05 -05:00
parent 023dacf5e0
commit de1abef9f0
57 changed files with 9415 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Attribute;
/**
* This class relates to session attribute storage
*/
class AttributeBag implements AttributeBagInterface
{
private $name = 'attributes';
/**
* @var string
*/
private $storageKey;
/**
* @var array
*/
protected $attributes = array();
/**
* Constructor.
*
* @param string $storageKey The key used to store flashes in the session.
*/
public function __construct($storageKey = '_sf2_attributes')
{
$this->storageKey = $storageKey;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function initialize(array &$attributes)
{
$this->attributes = &$attributes;
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function has($name)
{
return array_key_exists($name, $this->attributes);
}
/**
* {@inheritdoc}
*/
public function get($name, $default = null)
{
return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
}
/**
* {@inheritdoc}
*/
public function set($name, $value)
{
$this->attributes[$name] = $value;
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->attributes;
}
/**
* {@inheritdoc}
*/
public function replace(array $attributes)
{
$this->attributes = array();
foreach ($attributes as $key => $value) {
$this->set($key, $value);
}
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
$retval = null;
if (array_key_exists($name, $this->attributes)) {
$retval = $this->attributes[$name];
unset($this->attributes[$name]);
}
return $retval;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$return = $this->attributes;
$this->attributes = array();
return $return;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Attribute;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
/**
* Attributes store.
*
* @author Drak <drak@zikula.org>
*/
interface AttributeBagInterface extends SessionBagInterface
{
/**
* Checks if an attribute is defined.
*
* @param string $name The attribute name
*
* @return Boolean true if the attribute is defined, false otherwise
*/
function has($name);
/**
* Returns an attribute.
*
* @param string $name The attribute name
* @param mixed $default The default value if not found.
*
* @return mixed
*/
function get($name, $default = null);
/**
* Sets an attribute.
*
* @param string $name
* @param mixed $value
*/
function set($name, $value);
/**
* Returns attributes.
*
* @return array Attributes
*/
function all();
/**
* Sets attributes.
*
* @param array $attributes Attributes
*/
function replace(array $attributes);
/**
* Removes an attribute.
*
* @param string $name
*
* @return mixed The removed value
*/
function remove($name);
}

View File

@@ -0,0 +1,154 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Attribute;
/**
* This class provides structured storage of session attributes using
* a name spacing character in the key.
*
* @author Drak <drak@zikula.org>
*/
class NamespacedAttributeBag extends AttributeBag
{
/**
* Namespace character.
*
* @var string
*/
private $namespaceCharacter;
/**
* Constructor.
*
* @param string $storageKey Session storage key.
* @param string $namespaceCharacter Namespace character to use in keys.
*/
public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/')
{
$this->namespaceCharacter = $namespaceCharacter;
parent::__construct($storageKey);
}
/**
* {@inheritdoc}
*/
public function has($name)
{
$attributes = $this->resolveAttributePath($name);
$name = $this->resolveKey($name);
return array_key_exists($name, $attributes);
}
/**
* {@inheritdoc}
*/
public function get($name, $default = null)
{
$attributes = $this->resolveAttributePath($name);
$name = $this->resolveKey($name);
return array_key_exists($name, $attributes) ? $attributes[$name] : $default;
}
/**
* {@inheritdoc}
*/
public function set($name, $value)
{
$attributes = & $this->resolveAttributePath($name, true);
$name = $this->resolveKey($name);
$attributes[$name] = $value;
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
$retval = null;
$attributes = & $this->resolveAttributePath($name);
$name = $this->resolveKey($name);
if (array_key_exists($name, $attributes)) {
$retval = $attributes[$name];
unset($attributes[$name]);
}
return $retval;
}
/**
* Resolves a path in attributes property and returns it as a reference.
*
* This method allows structured namespacing of session attributes.
*
* @param string $name Key name
* @param boolean $writeContext Write context, default false
*
* @return array
*/
protected function &resolveAttributePath($name, $writeContext = false)
{
$array = & $this->attributes;
$name = (strpos($name, $this->namespaceCharacter) === 0) ? substr($name, 1) : $name;
// Check if there is anything to do, else return
if (!$name) {
return $array;
}
$parts = explode($this->namespaceCharacter, $name);
if (count($parts) < 2) {
if (!$writeContext) {
return $array;
}
$array[$parts[0]] = array();
return $array;
}
unset($parts[count($parts)-1]);
foreach ($parts as $part) {
if (!array_key_exists($part, $array)) {
if (!$writeContext) {
return $array;
}
$array[$part] = array();
}
$array = & $array[$part];
}
return $array;
}
/**
* Resolves the key from the name.
*
* This is the last part in a dot separated string.
*
* @param string $name
*
* @return string
*/
protected function resolveKey($name)
{
if (strpos($name, $this->namespaceCharacter) !== false) {
$name = substr($name, strrpos($name, $this->namespaceCharacter)+1, strlen($name));
}
return $name;
}
}

View File

@@ -0,0 +1,171 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Flash;
/**
* AutoExpireFlashBag flash message container.
*
* @author Drak <drak@zikula.org>
*/
class AutoExpireFlashBag implements FlashBagInterface
{
private $name = 'flashes';
/**
* Flash messages.
*
* @var array
*/
private $flashes = array();
/**
* The storage key for flashes in the session
*
* @var string
*/
private $storageKey;
/**
* Constructor.
*
* @param string $storageKey The key used to store flashes in the session.
*/
public function __construct($storageKey = '_sf2_flashes')
{
$this->storageKey = $storageKey;
$this->flashes = array('display' => array(), 'new' => array());
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function initialize(array &$flashes)
{
$this->flashes = &$flashes;
// The logic: messages from the last request will be stored in new, so we move them to previous
// This request we will show what is in 'display'. What is placed into 'new' this time round will
// be moved to display next time round.
$this->flashes['display'] = array_key_exists('new', $this->flashes) ? $this->flashes['new'] : array();
$this->flashes['new'] = array();
}
/**
* {@inheritdoc}
*/
public function peek($type, $default = null)
{
return $this->has($type) ? $this->flashes['display'][$type] : $default;
}
/**
* {@inheritdoc}
*/
public function peekAll()
{
return array_key_exists('display', $this->flashes) ? (array)$this->flashes['display'] : array();
}
/**
* {@inheritdoc}
*/
public function get($type, $default = null)
{
$return = $default;
if (!$this->has($type)) {
return $return;
}
if (isset($this->flashes['display'][$type])) {
$return = $this->flashes['display'][$type];
unset($this->flashes['display'][$type]);
}
return $return;
}
/**
* {@inheritdoc}
*/
public function all()
{
$return = $this->flashes['display'];
$this->flashes = array('new' => array(), 'display' => array());
return $return;
}
/**
* {@inheritdoc}
*/
public function setAll(array $messages)
{
$this->flashes['new'] = $messages;
}
/**
* {@inheritdoc}
*/
public function set($type, $message)
{
$this->flashes['new'][$type] = $message;
}
/**
* {@inheritdoc}
*/
public function has($type)
{
return array_key_exists($type, $this->flashes['display']);
}
/**
* {@inheritdoc}
*/
public function keys()
{
return array_keys($this->flashes['display']);
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$return = $this->all();
$this->flashes = array('display' => array(), 'new' => array());
return $return;
}
}

View File

@@ -0,0 +1,158 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Flash;
/**
* FlashBag flash message container.
*
* @author Drak <drak@zikula.org>
*/
class FlashBag implements FlashBagInterface
{
private $name = 'flashes';
/**
* Flash messages.
*
* @var array
*/
private $flashes = array();
/**
* The storage key for flashes in the session
*
* @var string
*/
private $storageKey;
/**
* Constructor.
*
* @param string $storageKey The key used to store flashes in the session.
*/
public function __construct($storageKey = '_sf2_flashes')
{
$this->storageKey = $storageKey;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function initialize(array &$flashes)
{
$this->flashes = &$flashes;
}
/**
* {@inheritdoc}
*/
public function peek($type, $default = null)
{
return $this->has($type) ? $this->flashes[$type] : $default;
}
/**
* {@inheritdoc}
*/
public function peekAll()
{
return $this->flashes;
}
/**
* {@inheritdoc}
*/
public function get($type, $default = null)
{
if (!$this->has($type)) {
return $default;
}
$return = $this->flashes[$type];
unset($this->flashes[$type]);
return $return;
}
/**
* {@inheritdoc}
*/
public function all()
{
$return = $this->peekAll();
$this->flashes = array();
return $return;
}
/**
* {@inheritdoc}
*/
public function set($type, $message)
{
$this->flashes[$type] = $message;
}
/**
* {@inheritdoc}
*/
public function setAll(array $messages)
{
$this->flashes = $messages;
}
/**
* {@inheritdoc}
*/
public function has($type)
{
return array_key_exists($type, $this->flashes);
}
/**
* {@inheritdoc}
*/
public function keys()
{
return array_keys($this->flashes);
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->all();
}
}

View File

@@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Flash;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
/**
* FlashBagInterface.
*
* @author Drak <drak@zikula.org>
*/
interface FlashBagInterface extends SessionBagInterface
{
/**
* Registers a message for a given type.
*
* @param string $type
* @param string $message
*/
function set($type, $message);
/**
* Gets flash message for a given type.
*
* @param string $type Message category type.
* @param string $default Default value if $type doee not exist.
*
* @return string
*/
function peek($type, $default = null);
/**
* Gets all flash messages.
*
* @return array
*/
function peekAll();
/**
* Gets and clears flash from the stack.
*
* @param string $type
* @param string $default Default value if $type doee not exist.
*
* @return string
*/
function get($type, $default = null);
/**
* Gets and clears flashes from the stack.
*
* @return array
*/
function all();
/**
* Sets all flash messages.
*/
function setAll(array $messages);
/**
* Has flash messages for a given type?
*
* @param string $type
*
* @return boolean
*/
function has($type);
/**
* Returns a list of all defined types.
*
* @return array
*/
function keys();
}

View File

@@ -0,0 +1,300 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
/**
* Session.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Drak <drak@zikula.org>
*
* @api
*/
class Session implements SessionInterface
{
/**
* Storage driver.
*
* @var SessionStorageInterface
*/
protected $storage;
/**
* @var string
*/
private $flashName;
/**
* @var string
*/
private $attributeName;
/**
* Constructor.
*
* @param SessionStorageInterface $storage A SessionStorageInterface instance.
* @param AttributeBagInterface $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag)
* @param FlashBagInterface $flashes A FlashBagInterface instance (defaults null for default FlashBag)
*/
public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
{
$this->storage = $storage ?: new NativeSessionStorage();
$attributeBag = $attributes ?: new AttributeBag();
$this->attributeName = $attributeBag->getName();
$this->registerBag($attributeBag);
$flashBag = $flashes ?: new FlashBag();
$this->flashName = $flashBag->getName();
$this->registerBag($flashBag);
}
/**
* {@inheritdoc}
*/
public function start()
{
return $this->storage->start();
}
/**
* {@inheritdoc}
*/
public function has($name)
{
return $this->storage->getBag($this->attributeName)->has($name);
}
/**
* {@inheritdoc}
*/
public function get($name, $default = null)
{
return $this->storage->getBag($this->attributeName)->get($name, $default);
}
/**
* {@inheritdoc}
*/
public function set($name, $value)
{
$this->storage->getBag($this->attributeName)->set($name, $value);
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->storage->getBag($this->attributeName)->all();
}
/**
* {@inheritdoc}
*/
public function replace(array $attributes)
{
$this->storage->getBag($this->attributeName)->replace($attributes);
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
return $this->storage->getBag($this->attributeName)->remove($name);
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->storage->getBag($this->attributeName)->clear();
}
/**
* {@inheritdoc}
*/
public function invalidate()
{
$this->storage->clear();
return $this->storage->regenerate(true);
}
/**
* {@inheritdoc}
*/
public function migrate($destroy = false)
{
return $this->storage->regenerate($destroy);
}
/**
* {@inheritdoc}
*/
public function save()
{
$this->storage->save();
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->storage->getId();
}
/**
* {@inheritdoc}
*/
public function setId($id)
{
$this->storage->setId($id);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->storage->getName();
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->storage->setName($name);
}
/**
* Registers a SessionBagInterface with the session.
*
* @param SessionBagInterface $bag
*/
public function registerBag(SessionBagInterface $bag)
{
$this->storage->registerBag($bag);
}
/**
* Get's a bag instance.
*
* @param string $name
*
* @return SessionBagInterface
*/
public function getBag($name)
{
return $this->storage->getBag($name);
}
/**
* Gets the flashbag interface.
*
* @return FlashBagInterface
*/
public function getFlashBag()
{
return $this->getBag($this->flashName);
}
// the following methods are kept for compatibility with Symfony 2.0 (they will be removed for Symfony 2.3)
/**
* @return array
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function getFlashes()
{
return $this->getBag('flashes')->all();
}
/**
* @param array $values
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function setFlashes($values)
{
$this->getBag('flashes')->setAll($values);
}
/**
* @param string $name
* @param string $default
*
* @return string
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function getFlash($name, $default = null)
{
return $this->getBag('flashes')->get($name, $default);
}
/**
* @param string $name
* @param string $value
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function setFlash($name, $value)
{
$this->getBag('flashes')->set($name, $value);
}
/**
* @param string $name
*
* @return Boolean
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function hasFlash($name)
{
return $this->getBag('flashes')->has($name);
}
/**
* @param string $name
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function removeFlash($name)
{
$this->getBag('flashes')->get($name);
}
/**
* @return array
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function clearFlashes()
{
return $this->getBag('flashes')->clear();
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session;
/**
* Session Bag store.
*
* @author Drak <drak@zikula.org>
*/
interface SessionBagInterface
{
/**
* Gets this bag's name
*
* @return string
*/
function getName();
/**
* Initializes the Bag
*
* @param array $array
*/
function initialize(array &$array);
/**
* Gets the storage key for this bag.
*
* @return string
*/
function getStorageKey();
/**
* Clears out data from bag.
*
* @return mixed Whatever data was contained.
*/
function clear();
}

View File

@@ -0,0 +1,167 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session;
/**
* Interface for the session.
*
* @author Drak <drak@zikula.org>
*/
interface SessionInterface
{
/**
* Starts the session storage.
*
* @return Boolean True if session started.
*
* @throws \RuntimeException If session fails to start.
*
* @api
*/
function start();
/**
* Returns the session ID.
*
* @return string The session ID.
*
* @api
*/
function getId();
/**
* Sets the session ID
*
* @param string $id
*
* @api
*/
function setId($id);
/**
* Returns the session name.
*
* @return mixed The session name.
*
* @api
*/
function getName();
/**
* Sets the session name.
*
* @param string $name
*
* @api
*/
function setName($name);
/**
* Invalidates the current session.
*
* Clears all session attributes and flashes and regenerates the
* session and deletes the old session from persistence.
*
* @return Boolean True if session invalidated, false if error.
*
* @api
*/
function invalidate();
/**
* Migrates the current session to a new session id while maintaining all
* session attributes.
*
* @param Boolean $destroy Whether to delete the old session or leave it to garbage collection.
*
* @return Boolean True if session migrated, false if error.
*
* @api
*/
function migrate($destroy = false);
/**
* Force the session to be saved and closed.
*
* This method is generally not required for real sessions as
* the session will be automatically saved at the end of
* code execution.
*/
function save();
/**
* Checks if an attribute is defined.
*
* @param string $name The attribute name
*
* @return Boolean true if the attribute is defined, false otherwise
*
* @api
*/
function has($name);
/**
* Returns an attribute.
*
* @param string $name The attribute name
* @param mixed $default The default value if not found.
*
* @return mixed
*
* @api
*/
function get($name, $default = null);
/**
* Sets an attribute.
*
* @param string $name
* @param mixed $value
*
* @api
*/
function set($name, $value);
/**
* Returns attributes.
*
* @return array Attributes
*
* @api
*/
function all();
/**
* Sets attributes.
*
* @param array $attributes Attributes
*/
function replace(array $attributes);
/**
* Removes an attribute.
*
* @param string $name
*
* @return mixed The removed value
*
* @api
*/
function remove($name);
/**
* Clears all attributes.
*
* @api
*/
function clear();
}

View File

@@ -0,0 +1,139 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* MemcacheSessionHandler.
*
* @author Drak <drak@zikula.org>
*/
class MemcacheSessionHandler implements \SessionHandlerInterface
{
/**
* Memcache driver.
*
* @var \Memcache
*/
private $memcache;
/**
* Configuration options.
*
* @var array
*/
private $memcacheOptions;
/**
* Key prefix for shared environments.
*
* @var string
*/
private $prefix;
/**
* Constructor.
*
* @param \Memcache $memcache A \Memcache instance
* @param array $memcacheOptions An associative array of Memcache options
* @param array $options Session configuration options.
*/
public function __construct(\Memcache $memcache, array $memcacheOptions = array(), array $options = array())
{
$this->memcache = $memcache;
// defaults
if (!isset($memcacheOptions['serverpool'])) {
$memcacheOptions['serverpool'] = array(array(
'host' => '127.0.0.1',
'port' => 11211,
'timeout' => 1,
'persistent' => false,
'weight' => 1,
'retry_interval' => 15,
));
}
$memcacheOptions['expiretime'] = isset($memcacheOptions['expiretime']) ? (int)$memcacheOptions['expiretime'] : 86400;
$this->prefix = isset($memcacheOptions['prefix']) ? $memcacheOptions['prefix'] : 'sf2s';
$this->memcacheOptions = $memcacheOptions;
}
protected function addServer(array $server)
{
if (!array_key_exists('host', $server)) {
throw new \InvalidArgumentException('host key must be set');
}
$server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
$server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
$server['persistent'] = isset($server['persistent']) ? (bool)$server['persistent'] : false;
$server['weight'] = isset($server['weight']) ? (int)$server['weight'] : 1;
$server['retry_interval'] = isset($server['retry_interval']) ? (int)$server['retry_interval'] : 15;
$this->memcache->addserver($server['host'], $server['port'], $server['persistent'],$server['weight'],$server['timeout'],$server['retry_interval']);
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
foreach ($this->memcacheOptions['serverpool'] as $server) {
$this->addServer($server);
}
return true;
}
/**
* {@inheritdoc}
*/
public function close()
{
return $this->memcache->close();
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
return $this->memcache->get($this->prefix.$sessionId) ?: '';
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $data)
{
return $this->memcache->set($this->prefix.$sessionId, $data, 0, $this->memcacheOptions['expiretime']);
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
return $this->memcache->delete($this->prefix.$sessionId);
}
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
// not required here because memcache will auto expire the records anyhow.
return true;
}
}

View File

@@ -0,0 +1,130 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* MemcachedSessionHandler.
*
* Memcached based session storage handler based on the Memcached class
* provided by the PHP memcached extension.
*
* @see http://php.net/memcached
*
* @author Drak <drak@zikula.org>
*/
class MemcachedSessionHandler implements \SessionHandlerInterface
{
/**
* Memcached driver.
*
* @var \Memcached
*/
private $memcached;
/**
* Configuration options.
*
* @var array
*/
private $memcachedOptions;
/**
* Constructor.
*
* @param \Memcached $memcached A \Memcached instance
* @param array $memcachedOptions An associative array of Memcached options
* @param array $options Session configuration options.
*/
public function __construct(\Memcached $memcached, array $memcachedOptions = array(), array $options = array())
{
$this->memcached = $memcached;
// defaults
if (!isset($memcachedOptions['serverpool'])) {
$memcachedOptions['serverpool'][] = array(
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 1);
}
$memcachedOptions['expiretime'] = isset($memcachedOptions['expiretime']) ? (int)$memcachedOptions['expiretime'] : 86400;
$this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, isset($memcachedOptions['prefix']) ? $memcachedOptions['prefix'] : 'sf2s');
$this->memcachedOptions = $memcachedOptions;
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
return $this->memcached->addServers($this->memcachedOptions['serverpool']);
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
return $this->memcached->get($sessionId) ?: '';
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $data)
{
return $this->memcached->set($sessionId, $data, $this->memcachedOptions['expiretime']);
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
return $this->memcached->delete($sessionId);
}
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
// not required here because memcached will auto expire the records anyhow.
return true;
}
/**
* Adds a server to the memcached handler.
*
* @param array $server
*/
protected function addServer(array $server)
{
if (array_key_exists('host', $server)) {
throw new \InvalidArgumentException('host key must be set');
}
$server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
$server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
$server['presistent'] = isset($server['presistent']) ? (bool)$server['presistent'] : false;
$server['weight'] = isset($server['weight']) ? (bool)$server['weight'] : 1;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* NativeFileSessionHandler.
*
* Native session handler using PHP's built in file storage.
*
* @author Drak <drak@zikula.org>
*/
class NativeFileSessionHandler extends NativeSessionHandler
{
/**
* Constructor.
*
* @param string $savePath Path of directory to save session files. Default null will leave setting as defined by PHP.
*/
public function __construct($savePath = null)
{
if (null === $savePath) {
$savePath = ini_get('session.save_path');
}
if ($savePath && !is_dir($savePath)) {
mkdir($savePath, 0777, true);
}
ini_set('session.save_handler', 'files');
ini_set('session.save_path', $savePath);
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* NativeMemcacheSessionHandler.
*
* Driver for the memcache session save hadlers provided by the memcache PHP extension.
*
* @see http://php.net/memcache
*
* @author Drak <drak@zikula.org>
*/
class NativeMemcacheSessionHandler extends NativeSessionHandler
{
/**
* Constructor.
*
* @param string $savePath Path of memcache server.
* @param array $options Session configuration options.
*/
public function __construct($savePath = 'tcp://127.0.0.1:11211?persistent=0', array $options = array())
{
if (!extension_loaded('memcache')) {
throw new \RuntimeException('PHP does not have "memcache" session module registered');
}
if (null === $savePath) {
$savePath = ini_get('session.save_path');
}
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', $savePath);
$this->setOptions($options);
}
/**
* Set any memcached ini values.
*
* @see http://php.net/memcache.ini
*/
protected function setOptions(array $options)
{
foreach ($options as $key => $value) {
if (in_array($key, array(
'memcache.allow_failover', 'memcache.max_failover_attempts',
'memcache.chunk_size', 'memcache.default_port', 'memcache.hash_strategy',
'memcache.hash_function', 'memcache.protocol', 'memcache.redundancy',
'memcache.session_redundancy', 'memcache.compress_threshold',
'memcache.lock_timeout'))) {
ini_set($key, $value);
}
}
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* NativeMemcachedSessionHandler.
*
* Driver for the memcached session save hadlers provided by the memcached PHP extension.
*
* @see http://php.net/memcached.sessions
*
* @author Drak <drak@zikula.org>
*/
class NativeMemcachedSessionHandler extends NativeSessionHandler
{
/**
* Constructor.
*
* @param string $savePath Comma separated list of servers: e.g. memcache1.example.com:11211,memcache2.example.com:11211
* @param array $options Session configuration options.
*/
public function __construct($savePath = '127.0.0.1:11211', array $options = array())
{
if (!extension_loaded('memcached')) {
throw new \RuntimeException('PHP does not have "memcached" session module registered');
}
if (null === $savePath) {
$savePath = ini_get('session.save_path');
}
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', $savePath);
$this->setOptions($options);
}
/**
* Set any memcached ini values.
*
* @see https://github.com/php-memcached-dev/php-memcached/blob/master/memcached.ini
*/
protected function setOptions(array $options)
{
foreach ($options as $key => $value) {
if (in_array($key, array(
'memcached.sess_locking', 'memcached.sess_lock_wait',
'memcached.sess_prefix', 'memcached.compression_type',
'memcached.compression_factor', 'memcached.compression_threshold',
'memcached.serializer'))) {
ini_set($key, $value);
}
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* Adds SessionHandler functionality if available.
*
* @see http://php.net/sessionhandler
*/
if (version_compare(phpversion(), '5.4.0', '>=')) {
class NativeSessionHandler extends \SessionHandler {}
} else {
class NativeSessionHandler {}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* NativeSqliteSessionHandler.
*
* Driver for the sqlite session save hadlers provided by the SQLite PHP extension.
*
* @author Drak <drak@zikula.org>
*/
class NativeSqliteSessionHandler extends NativeSessionHandler
{
/**
* Constructor.
*
* @param string $savePath Path to SQLite database file itself.
* @param array $options Session configuration options.
*/
public function __construct($savePath, array $options = array())
{
if (!extension_loaded('sqlite')) {
throw new \RuntimeException('PHP does not have "sqlite" session module registered');
}
if (null === $savePath) {
$savePath = ini_get('session.save_path');
}
ini_set('session.save_handler', 'sqlite');
ini_set('session.save_path', $savePath);
$this->setOptions($options);
}
/**
* Set any sqlite ini values.
*
* @see http://php.net/sqlite.configuration
*/
protected function setOptions(array $options)
{
foreach ($options as $key => $value) {
if (in_array($key, array('sqlite.assoc_case'))) {
ini_set($key, $value);
}
}
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* NullSessionHandler.
*
* Can be used in unit testing or in a sitation where persisted sessions are not desired.
*
* @author Drak <drak@zikula.org>
*
* @api
*/
class NullSessionHandler implements \SessionHandlerInterface
{
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
return '';
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $data)
{
return true;
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
return true;
}
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
return true;
}
}

View File

@@ -0,0 +1,221 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* PdoSessionHandler.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Michael Williams <michael.williams@funsational.com>
*/
class PdoSessionHandler implements \SessionHandlerInterface
{
/**
* PDO instance.
*
* @var \PDO
*/
private $pdo;
/**
* Database options.
*
*
* @var array
*/
private $dbOptions;
/**
* Constructor.
*
* @param \PDO $pdo A \PDO instance
* @param array $dbOptions An associative array of DB options
* @param array $options Session configuration options
*
* @throws \InvalidArgumentException When "db_table" option is not provided
*/
public function __construct(\PDO $pdo, array $dbOptions = array(), array $options = array())
{
if (!array_key_exists('db_table', $dbOptions)) {
throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
}
$this->pdo = $pdo;
$this->dbOptions = array_merge(array(
'db_id_col' => 'sess_id',
'db_data_col' => 'sess_data',
'db_time_col' => 'sess_time',
), $dbOptions);
}
/**
* {@inheritdoc}
*/
public function open($path, $name)
{
return true;
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function destroy($id)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
$dbIdCol = $this->dbOptions['db_id_col'];
// delete the record associated with this id
$sql = "DELETE FROM $dbTable WHERE $dbIdCol = :id";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->execute();
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
$dbTimeCol = $this->dbOptions['db_time_col'];
// delete the session records that have expired
$sql = "DELETE FROM $dbTable WHERE $dbTimeCol < (:time - $lifetime)";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* {@inheritdoc}
*/
public function read($id)
{
// get table/columns
$dbTable = $this->dbOptions['db_table'];
$dbDataCol = $this->dbOptions['db_data_col'];
$dbIdCol = $this->dbOptions['db_id_col'];
try {
$sql = "SELECT $dbDataCol FROM $dbTable WHERE $dbIdCol = :id";
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->execute();
// it is recommended to use fetchAll so that PDO can close the DB cursor
// we anyway expect either no rows, or one row with one column. fetchColumn, seems to be buggy #4777
$sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM);
if (count($sessionRows) == 1) {
return base64_decode($sessionRows[0][0]);
}
// session does not exist, create it
$this->createNewSession($id);
return '';
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
}
}
/**
* {@inheritdoc}
*/
public function write($id, $data)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
$dbDataCol = $this->dbOptions['db_data_col'];
$dbIdCol = $this->dbOptions['db_id_col'];
$dbTimeCol = $this->dbOptions['db_time_col'];
$sql = ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME))
? "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) "
."ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = CASE WHEN $dbTimeCol = :time THEN (VALUES($dbTimeCol) + 1) ELSE VALUES($dbTimeCol) END"
: "UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id";
try {
//session data can contain non binary safe characters so we need to encode it
$encoded = base64_encode($data);
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
if (!$stmt->rowCount()) {
// No session exists in the database to update. This happens when we have called
// session_regenerate_id()
$this->createNewSession($id, $data);
}
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* Creates a new session with the given $id and $data
*
* @param string $id
* @param string $data
*
* @return boolean True.
*/
private function createNewSession($id, $data = '')
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
$dbDataCol = $this->dbOptions['db_data_col'];
$dbIdCol = $this->dbOptions['db_id_col'];
$dbTimeCol = $this->dbOptions['db_time_col'];
$sql = "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time)";
//session data can contain non binary safe characters so we need to encode it
$encoded = base64_encode($data);
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
return true;
}
}

View File

@@ -0,0 +1,218 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
/**
* MockArraySessionStorage mocks the session for unit tests.
*
* No PHP session is actually started since a session can be initialized
* and shutdown only once per PHP execution cycle.
*
* When doing functional testing, you should use MockFileSessionStorage instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Drak <drak@zikula.org>
*/
class MockArraySessionStorage implements SessionStorageInterface
{
/**
* @var string
*/
protected $id = '';
/**
* @var string
*/
protected $name;
/**
* @var boolean
*/
protected $started = false;
/**
* @var boolean
*/
protected $closed = false;
/**
* @var array
*/
protected $data = array();
/**
* Constructor.
*
* @param string $name Session name
*/
public function __construct($name = 'MOCKSESSID')
{
$this->name = $name;
}
/**
* Sets the session data.
*
* @param array $array
*/
public function setSessionData(array $array)
{
$this->data = $array;
}
/**
* {@inheritdoc}
*/
public function start()
{
if ($this->started && !$this->closed) {
return true;
}
if (empty($this->id)) {
$this->id = $this->generateId();
}
$this->loadSession();
return true;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false)
{
if (!$this->started) {
$this->start();
}
$this->id = $this->generateId();
return true;
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function setId($id)
{
if ($this->started) {
throw new \LogicException('Cannot set session ID after the session has started.');
}
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function save()
{
// nothing to do since we don't persist the session data
$this->closed = false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
// clear out the bags
foreach ($this->bags as $bag) {
$bag->clear();
}
// clear out the session
$this->data = array();
// reconnect the bags to the session
$this->loadSession();
}
/**
* {@inheritdoc}
*/
public function registerBag(SessionBagInterface $bag)
{
$this->bags[$bag->getName()] = $bag;
}
/**
* {@inheritdoc}
*/
public function getBag($name)
{
if (!isset($this->bags[$name])) {
throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
}
if (!$this->started) {
$this->start();
}
return $this->bags[$name];
}
/**
* Generates a session ID.
*
* This doesn't need to be particularly cryptographically secure since this is just
* a mock.
*
* @return string
*/
protected function generateId()
{
return sha1(uniqid(mt_rand()));
}
protected function loadSession()
{
foreach ($this->bags as $bag) {
$key = $bag->getStorageKey();
$this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : array();
$bag->initialize($this->data[$key]);
}
$this->started = true;
$this->closed = false;
}
}

View File

@@ -0,0 +1,126 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage;
/**
* MockFileSessionStorage is used to mock sessions for
* functional testing when done in a single PHP process.
*
* No PHP session is actually started since a session can be initialized
* and shutdown only once per PHP execution cycle and this class does
* not pollute any session related globals, including session_*() functions
* or session.* PHP ini directives.
*
* @author Drak <drak@zikula.org>
*/
class MockFileSessionStorage extends MockArraySessionStorage
{
/**
* @var string
*/
private $savePath;
/**
* Constructor.
*
* @param string $savePath Path of directory to save session files.
* @param string $name Session name.
*/
public function __construct($savePath = null, $name = 'MOCKSESSID')
{
if (null === $savePath) {
$savePath = sys_get_temp_dir();
}
if (!is_dir($savePath)) {
mkdir($savePath, 0777, true);
}
$this->savePath = $savePath;
parent::__construct($name);
}
/**
* {@inheritdoc}
*/
public function start()
{
if ($this->started) {
return true;
}
if (!$this->id) {
$this->id = $this->generateId();
}
$this->read();
$this->started = true;
return true;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false)
{
if ($destroy) {
$this->destroy();
}
$this->id = $this->generateId();
return true;
}
/**
* {@inheritdoc}
*/
public function save()
{
file_put_contents($this->getFilePath(), serialize($this->data));
}
/**
* Deletes a session from persistent storage.
* Deliberately leaves session data in memory intact.
*/
private function destroy()
{
if (is_file($this->getFilePath())) {
unlink($this->getFilePath());
}
}
/**
* Calculate path to file.
*
* @return string File path
*/
private function getFilePath()
{
return $this->savePath.'/'.$this->id.'.mocksess';
}
/**
* Reads session from storage and loads session.
*/
private function read()
{
$filePath = $this->getFilePath();
$this->data = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array();
$this->loadSession();
}
}

View File

@@ -0,0 +1,347 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
/**
* This provides a base class for session attribute storage.
*
* @author Drak <drak@zikula.org>
*/
class NativeSessionStorage implements SessionStorageInterface
{
/**
* Array of SessionBagInterface
*
* @var array
*/
protected $bags;
/**
* @var boolean
*/
protected $started = false;
/**
* @var boolean
*/
protected $closed = false;
/**
* @var AbstractProxy
*/
protected $saveHandler;
/**
* Constructor.
*
* Depending on how you want the storage driver to behave you probably
* want top override this constructor entirely.
*
* List of options for $options array with their defaults.
* @see http://php.net/session.configuration for options
* but we omit 'session.' from the beginning of the keys for convenience.
*
* auto_start, "0"
* cache_limiter, "nocache" (use "0" to prevent headers from being sent entirely).
* cookie_domain, ""
* cookie_httponly, ""
* cookie_lifetime, "0"
* cookie_path, "/"
* cookie_secure, ""
* entropy_file, ""
* entropy_length, "0"
* gc_divisor, "100"
* gc_maxlifetime, "1440"
* gc_probability, "1"
* hash_bits_per_character, "4"
* hash_function, "0"
* name, "PHPSESSID"
* referer_check, ""
* serialize_handler, "php"
* use_cookies, "1"
* use_only_cookies, "1"
* use_trans_sid, "0"
* upload_progress.enabled, "1"
* upload_progress.cleanup, "1"
* upload_progress.prefix, "upload_progress_"
* upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS"
* upload_progress.freq, "1%"
* upload_progress.min-freq, "1"
* url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
*
* @param array $options Session configuration options.
* @param object $handler SessionHandlerInterface.
*/
public function __construct(array $options = array(), $handler = null)
{
// sensible defaults
ini_set('session.auto_start', 0); // by default we prefer to explicitly start the session using the class.
ini_set('session.cache_limiter', ''); // disable by default because it's managed by HeaderBag (if used)
ini_set('session.use_cookies', 1);
if (version_compare(phpversion(), '5.4.0', '>=')) {
session_register_shutdown();
} else {
register_shutdown_function('session_write_close');
}
$this->setOptions($options);
$this->setSaveHandler($handler);
}
/**
* Gets the save handler instance.
*
* @return AbstractProxy
*/
public function getSaveHandler()
{
return $this->saveHandler;
}
/**
* {@inheritdoc}
*/
public function start()
{
if ($this->started && !$this->closed) {
return true;
}
// catch condition where session was started automatically by PHP
if (!$this->started && !$this->closed && $this->saveHandler->isActive()
&& $this->saveHandler->isSessionHandlerInterface()) {
$this->loadSession();
return true;
}
if (ini_get('session.use_cookies') && headers_sent()) {
throw new \RuntimeException('Failed to start the session because headers have already been sent.');
}
// start the session
if (!session_start()) {
throw new \RuntimeException('Failed to start the session');
}
$this->loadSession();
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
$this->saveHandler->setActive(false);
}
return true;
}
/**
* {@inheritdoc}
*/
public function getId()
{
if (!$this->started) {
return ''; // returning empty is consistent with session_id() behaviour
}
return $this->saveHandler->getId();
}
/**
* {@inheritdoc}
*/
public function setId($id)
{
return $this->saveHandler->setId($id);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->saveHandler->getName();
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->saveHandler->setName($name);
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false)
{
return session_regenerate_id($destroy);
}
/**
* {@inheritdoc}
*/
public function save()
{
session_write_close();
if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) {
$this->saveHandler->setActive(false);
}
$this->closed = true;
}
/**
* {@inheritdoc}
*/
public function clear()
{
// clear out the bags
foreach ($this->bags as $bag) {
$bag->clear();
}
// clear out the session
$_SESSION = array();
// reconnect the bags to the session
$this->loadSession();
}
/**
* {@inheritdoc}
*/
public function registerBag(SessionBagInterface $bag)
{
$this->bags[$bag->getName()] = $bag;
}
/**
* {@inheritdoc}
*/
public function getBag($name)
{
if (!isset($this->bags[$name])) {
throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
}
if (ini_get('session.auto_start') && !$this->started) {
$this->start();
} elseif ($this->saveHandler->isActive() && !$this->started) {
$this->loadSession();
}
return $this->bags[$name];
}
/**
* Sets session.* ini variables.
*
* For convenience we omit 'session.' from the beginning of the keys.
* Explicitly ignores other ini keys.
*
* @param array $options Session ini directives array(key => value).
*
* @see http://php.net/session.configuration
*/
public function setOptions(array $options)
{
foreach ($options as $key => $value) {
if (in_array($key, array(
'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly',
'cookie_lifetime', 'cookie_path', 'cookie_secure',
'entropy_file', 'entropy_length', 'gc_divisor',
'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
'hash_function', 'name', 'referer_check',
'serialize_handler', 'use_cookies',
'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags'))) {
ini_set('session.'.$key, $value);
}
}
}
/**
* Registers save handler as a PHP session handler.
*
* To use internal PHP session save handlers, override this method using ini_set with
* session.save_handlers and session.save_path e.g.
*
* ini_set('session.save_handlers', 'files');
* ini_set('session.save_path', /tmp');
*
* @see http://php.net/session-set-save-handler
* @see http://php.net/sessionhandlerinterface
* @see http://php.net/sessionhandler
*
* @param object $saveHandler Default null means NativeProxy.
*/
public function setSaveHandler($saveHandler = null)
{
// Wrap $saveHandler in proxy
if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
$saveHandler = new SessionHandlerProxy($saveHandler);
} elseif (!$saveHandler instanceof AbstractProxy) {
$saveHandler = new NativeProxy($saveHandler);
}
$this->saveHandler = $saveHandler;
if ($this->saveHandler instanceof \SessionHandlerInterface) {
if (version_compare(phpversion(), '5.4.0', '>=')) {
session_set_save_handler($this->saveHandler, false);
} else {
session_set_save_handler(
array($this->saveHandler, 'open'),
array($this->saveHandler, 'close'),
array($this->saveHandler, 'read'),
array($this->saveHandler, 'write'),
array($this->saveHandler, 'destroy'),
array($this->saveHandler, 'gc')
);
}
}
}
/**
* Load the session with attributes.
*
* After starting the session, PHP retrieves the session from whatever handlers
* are set to (either PHP's internal, or a custom save handler set with session_set_save_handler()).
* PHP takes the return value from the read() handler, unserializes it
* and populates $_SESSION with the result automatically.
*
* @param array|null $session
*/
protected function loadSession(array &$session = null)
{
if (null === $session) {
$session = &$_SESSION;
}
foreach ($this->bags as $bag) {
$key = $bag->getStorageKey();
$session[$key] = isset($session[$key]) ? $session[$key] : array();
$bag->initialize($session[$key]);
}
$this->started = true;
$this->closed = false;
}
}

View File

@@ -0,0 +1,135 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
/**
* AbstractProxy.
*
* @author Drak <drak@zikula.org>
*/
abstract class AbstractProxy
{
/**
* Flag if handler wraps an internal PHP session handler (using \SessionHandler).
*
* @var boolean
*/
protected $wrapper = false;
/**
* @var boolean
*/
protected $active = false;
/**
* @var string
*/
protected $saveHandlerName;
/**
* Gets the session.save_handler name.
*
* @return string
*/
public function getSaveHandlerName()
{
return $this->saveHandlerName;
}
/**
* Is this proxy handler and instance of \SessionHandlerInterface.
*
* @return boolean
*/
public function isSessionHandlerInterface()
{
return ($this instanceof \SessionHandlerInterface);
}
/**
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
*
* @return bool
*/
public function isWrapper()
{
return $this->wrapper;
}
/**
* Has a session started?
*
* @return bool
*/
public function isActive()
{
return $this->active;
}
/**
* Sets the active flag.
*
* @param bool $flag
*/
public function setActive($flag)
{
$this->active = (bool) $flag;
}
/**
* Gets the session ID.
*
* @return string
*/
public function getId()
{
return session_id();
}
/**
* Sets the session ID.
*
* @param string $id
*/
public function setId($id)
{
if ($this->isActive()) {
throw new \LogicException('Cannot change the ID of an active session');
}
session_id($id);
}
/**
* Gets the session name.
*
* @return string
*/
public function getName()
{
return session_name();
}
/**
* Sets the session name.
*
* @param string $name
*/
public function setName($name)
{
if ($this->isActive()) {
throw new \LogicException('Cannot change the name of an active session');
}
session_name($name);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
/**
* NativeProxy.
*
* This proxy is built-in session handlers in PHP 5.3.x
*
* @author Drak <drak@zikula.org>
*/
class NativeProxy extends AbstractProxy
{
/**
* Constructor.
*/
public function __construct()
{
// this makes an educated guess as to what the handler is since it should already be set.
$this->saveHandlerName = ini_get('session.save_handler');
}
/**
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
*
* @return bool False.
*/
public function isWrapper()
{
return false;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
/**
* SessionHandler proxy.
*
* @author Drak <drak@zikula.org>
*/
class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface
{
/**
* @var \SessionHandlerInterface
*/
protected $handler;
/**
* Constructor.
*
* @param \SessionHandlerInterface $handler
*/
public function __construct(\SessionHandlerInterface $handler)
{
$this->handler = $handler;
$this->wrapper = ($handler instanceof \SessionHandler);
$this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user';
}
// \SessionHandlerInterface
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
$return = (bool)$this->handler->open($savePath, $sessionName);
if (true === $return) {
$this->active = true;
}
return $return;
}
/**
* {@inheritdoc}
*/
public function close()
{
$this->active = false;
return (bool) $this->handler->close();
}
/**
* {@inheritdoc}
*/
public function read($id)
{
return (string) $this->handler->read($id);
}
/**
* {@inheritdoc}
*/
public function write($id, $data)
{
return (bool) $this->handler->write($id, $data);
}
/**
* {@inheritdoc}
*/
public function destroy($id)
{
return (bool) $this->handler->destroy($id);
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime)
{
return (bool) $this->handler->gc($maxlifetime);
}
}

View File

@@ -0,0 +1,126 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
/**
* StorageInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Drak <drak@zikula.org>
*
* @api
*/
interface SessionStorageInterface
{
/**
* Starts the session.
*
* @throws \RuntimeException If something goes wrong starting the session.
*
* @return boolean True if started.
*
* @api
*/
function start();
/**
* Returns the session ID
*
* @return string The session ID or empty.
*
* @api
*/
function getId();
/**
* Sets the session ID
*
* @param string $id
*
* @api
*/
function setId($id);
/**
* Returns the session name
*
* @return mixed The session name.
*
* @api
*/
function getName();
/**
* Sets the session name
*
* @param string $name
*
* @api
*/
function setName($name);
/**
* Regenerates id that represents this storage.
*
* This method must invoke session_regenerate_id($destroy) unless
* this interface is used for a storage object designed for unit
* or functional testing where a real PHP session would interfere
* with testing.
*
* Note regenerate+destroy should not clear the session data in memory
* only delete the session data from persistent storage.
*
* @param Boolean $destroy Destroy session when regenerating?
*
* @return Boolean True if session regenerated, false if error
*
* @throws \RuntimeException If an error occurs while regenerating this storage
*
* @api
*/
function regenerate($destroy = false);
/**
* Force the session to be saved and closed.
*
* This method must invoke session_write_close() unless this interface is
* used for a storage object design for unit or functional testing where
* a real PHP session would interfere with testing, in which case it
* it should actually persist the session data if required.
*/
function save();
/**
* Clear all session data in memory.
*/
function clear();
/**
* Gets a SessionBagInterface by name.
*
* @param string $name
*
* @return SessionBagInterface
*
* @throws \InvalidArgumentException If the bag does not exist
*/
function getBag($name);
/**
* Registers a SessionBagInterface for use.
*
* @param SessionBagInterface $bag
*/
function registerBag(SessionBagInterface $bag);
}