initial commit

This commit is contained in:
Manuel Raynaud
2012-10-02 14:13:48 +02:00
commit bb720731ae
838 changed files with 84954 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
<?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;
/**
* Request represents an HTTP request from an Apache server.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ApacheRequest extends Request
{
/**
* {@inheritdoc}
*/
protected function prepareRequestUri()
{
return $this->server->get('REQUEST_URI');
}
/**
* {@inheritdoc}
*/
protected function prepareBaseUrl()
{
$baseUrl = $this->server->get('SCRIPT_NAME');
if (false === strpos($this->server->get('REQUEST_URI'), $baseUrl)) {
// assume mod_rewrite
return rtrim(dirname($baseUrl), '/\\');
}
return $baseUrl;
}
/**
* {@inheritdoc}
*/
protected function preparePathInfo()
{
return $this->server->get('PATH_INFO') ?: substr($this->prepareRequestUri(), strlen($this->prepareBaseUrl())) ?: '/';
}
}

View File

@@ -0,0 +1,75 @@
CHANGELOG
=========
2.1.0
-----
* added Request::getSchemeAndHttpHost() and Request::getUserInfo()
* added a fluent interface to the Response class
* added Request::isProxyTrusted()
* added JsonResponse
* added a getTargetUrl method to RedirectResponse
* added support for streamed responses
* made Response::prepare() method the place to enforce HTTP specification
* [BC BREAK] moved management of the locale from the Session class to the Request class
* added a generic access to the PHP built-in filter mechanism: ParameterBag::filter()
* made FileBinaryMimeTypeGuesser command configurable
* added Request::getUser() and Request::getPassword()
* added support for the PATCH method in Request
* removed the ContentTypeMimeTypeGuesser class as it is deprecated and never used on PHP 5.3
* added ResponseHeaderBag::makeDisposition() (implements RFC 6266)
* made mimetype to extension conversion configurable
* [BC BREAK] Moved all session related classes and interfaces into own namespace, as
`Symfony\Component\HttpFoundation\Session` and renamed classes accordingly.
Session handlers are located in the subnamespace `Symfony\Component\HttpFoundation\Session\Handler`.
* SessionHandlers must implement `\SessionHandlerInterface` or extend from the
`Symfony\Component\HttpFoundation\Storage\Handler\NativeSessionHandler` base class.
* Added internal storage driver proxy mechanism for forward compatibility with
PHP 5.4 `\SessionHandler` class.
* Added session handlers for custom Memcache, Memcached and Null session save handlers.
* [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionHandler`.
* [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and
`remove()`. Added `getBag()`, `registerBag()`. The `NativeSessionStorage` class
is a mediator for the session storage internals including the session handlers
which do the real work of participating in the internal PHP session workflow.
* [BC BREAK] Introduced mock implementations of `SessionStorage` to enable unit
and functional testing without starting real PHP sessions. Removed
`ArraySessionStorage`, and replaced with `MockArraySessionStorage` for unit
tests; removed `FilesystemSessionStorage`, and replaced with`MockFileSessionStorage`
for functional tests. These do not interact with global session ini
configuration values, session functions or `$_SESSION` superglobal. This means
they can be configured directly allowing multiple instances to work without
conflicting in the same PHP process.
* [BC BREAK] Removed the `close()` method from the `Session` class, as this is
now redundant.
* Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()`
`getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead
which returns a `FlashBagInterface`.
* `Session->clear()` now only clears session attributes as before it cleared
flash messages and attributes. `Session->getFlashBag()->all()` clears flashes now.
* Session data is now managed by `SessionBagInterface` to better encapsulate
session data.
* Refactored session attribute and flash messages system to their own
`SessionBagInterface` implementations.
* Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. This
implementation is ESI compatible.
* Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire
behaviour of messages auto expiring after one page page load. Messages must
be retrieved by `get()` or `all()`.
* Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate
attributes storage behaviour from 2.0.x (default).
* Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for
namespace session attributes.
* Flash API can stores messages in an array so there may be multiple messages
per flash type. The old `Session` class API remains without BC break as it
will allow single messages as before.
* Added basic session meta-data to the session to record session create time,
last updated time, and the lifetime of the session cookie that was provided
to the client.
* Request::getClientIp() method doesn't take a parameter anymore but bases
itself on the trustProxy parameter.
* Added isMethod() to Request object.
* [BC BREAK] The methods `getPathInfo()`, `getBaseUrl()` and `getBasePath()` of
a `Request` now all return a raw value (vs a urldecoded value before). Any call
to one of these methods must be checked and wrapped in a `rawurldecode()` if
needed.

View File

@@ -0,0 +1,208 @@
<?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;
/**
* Represents a cookie
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class Cookie
{
protected $name;
protected $value;
protected $domain;
protected $expire;
protected $path;
protected $secure;
protected $httpOnly;
/**
* Constructor.
*
* @param string $name The name of the cookie
* @param string $value The value of the cookie
* @param integer|string|\DateTime $expire The time the cookie expires
* @param string $path The path on the server in which the cookie will be available on
* @param string $domain The domain that the cookie is available to
* @param Boolean $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
* @param Boolean $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
*
* @api
*/
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)
{
// from PHP source code
if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
}
if (empty($name)) {
throw new \InvalidArgumentException('The cookie name cannot be empty.');
}
// convert expiration time to a Unix timestamp
if ($expire instanceof \DateTime) {
$expire = $expire->format('U');
} elseif (!is_numeric($expire)) {
$expire = strtotime($expire);
if (false === $expire || -1 === $expire) {
throw new \InvalidArgumentException('The cookie expiration time is not valid.');
}
}
$this->name = $name;
$this->value = $value;
$this->domain = $domain;
$this->expire = $expire;
$this->path = empty($path) ? '/' : $path;
$this->secure = (Boolean) $secure;
$this->httpOnly = (Boolean) $httpOnly;
}
/**
* Returns the cookie as a string.
*
* @return string The cookie
*/
public function __toString()
{
$str = urlencode($this->getName()).'=';
if ('' === (string) $this->getValue()) {
$str .= 'deleted; expires='.gmdate("D, d-M-Y H:i:s T", time() - 31536001);
} else {
$str .= urlencode($this->getValue());
if ($this->getExpiresTime() !== 0) {
$str .= '; expires='.gmdate("D, d-M-Y H:i:s T", $this->getExpiresTime());
}
}
if ('/' !== $this->path) {
$str .= '; path='.$this->path;
}
if (null !== $this->getDomain()) {
$str .= '; domain='.$this->getDomain();
}
if (true === $this->isSecure()) {
$str .= '; secure';
}
if (true === $this->isHttpOnly()) {
$str .= '; httponly';
}
return $str;
}
/**
* Gets the name of the cookie.
*
* @return string
*
* @api
*/
public function getName()
{
return $this->name;
}
/**
* Gets the value of the cookie.
*
* @return string
*
* @api
*/
public function getValue()
{
return $this->value;
}
/**
* Gets the domain that the cookie is available to.
*
* @return string
*
* @api
*/
public function getDomain()
{
return $this->domain;
}
/**
* Gets the time the cookie expires.
*
* @return integer
*
* @api
*/
public function getExpiresTime()
{
return $this->expire;
}
/**
* Gets the path on the server in which the cookie will be available on.
*
* @return string
*
* @api
*/
public function getPath()
{
return $this->path;
}
/**
* Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client.
*
* @return Boolean
*
* @api
*/
public function isSecure()
{
return $this->secure;
}
/**
* Checks whether the cookie will be made accessible only through the HTTP protocol.
*
* @return Boolean
*
* @api
*/
public function isHttpOnly()
{
return $this->httpOnly;
}
/**
* Whether this cookie is about to be cleared
*
* @return Boolean
*
* @api
*/
public function isCleared()
{
return $this->expire < time();
}
}

View File

@@ -0,0 +1,30 @@
<?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\File\Exception;
/**
* Thrown when the access on a file was denied.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class AccessDeniedException extends FileException
{
/**
* Constructor.
*
* @param string $path The path to the accessed file
*/
public function __construct($path)
{
parent::__construct(sprintf('The file %s could not be accessed', $path));
}
}

View File

@@ -0,0 +1,21 @@
<?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\File\Exception;
/**
* Thrown when an error occurred in the component File
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FileException extends \RuntimeException
{
}

View File

@@ -0,0 +1,30 @@
<?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\File\Exception;
/**
* Thrown when a file was not found
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FileNotFoundException extends FileException
{
/**
* Constructor.
*
* @param string $path The path to the file that was not found
*/
public function __construct($path)
{
parent::__construct(sprintf('The file "%s" does not exist', $path));
}
}

View File

@@ -0,0 +1,20 @@
<?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\File\Exception;
class UnexpectedTypeException extends FileException
{
public function __construct($value, $expectedType)
{
parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
}
}

View File

@@ -0,0 +1,21 @@
<?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\File\Exception;
/**
* Thrown when an error occurred during file upload
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class UploadException extends FileException
{
}

View File

@@ -0,0 +1,129 @@
<?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\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
/**
* A file in the file system.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
class File extends \SplFileInfo
{
/**
* Constructs a new file from the given path.
*
* @param string $path The path to the file
* @param Boolean $checkPath Whether to check the path or not
*
* @throws FileNotFoundException If the given path is not a file
*
* @api
*/
public function __construct($path, $checkPath = true)
{
if ($checkPath && !is_file($path)) {
throw new FileNotFoundException($path);
}
parent::__construct($path);
}
/**
* Returns the extension based on the mime type.
*
* If the mime type is unknown, returns null.
*
* @return string|null The guessed extension or null if it cannot be guessed
*
* @api
*/
public function guessExtension()
{
$type = $this->getMimeType();
$guesser = ExtensionGuesser::getInstance();
return $guesser->guess($type);
}
/**
* Returns the mime type of the file.
*
* The mime type is guessed using the functions finfo(), mime_content_type()
* and the system binary "file" (in this order), depending on which of those
* is available on the current operating system.
*
* @return string|null The guessed mime type (i.e. "application/pdf")
*
* @api
*/
public function getMimeType()
{
$guesser = MimeTypeGuesser::getInstance();
return $guesser->guess($this->getPathname());
}
/**
* Returns the extension of the file.
*
* \SplFileInfo::getExtension() is not available before PHP 5.3.6
*
* @return string The extension
*
* @api
*/
public function getExtension()
{
return pathinfo($this->getBasename(), PATHINFO_EXTENSION);
}
/**
* Moves the file to a new location.
*
* @param string $directory The destination folder
* @param string $name The new file name
*
* @return File A File object representing the new file
*
* @throws FileException if the target file could not be created
*
* @api
*/
public function move($directory, $name = null)
{
if (!is_dir($directory)) {
if (false === @mkdir($directory, 0777, true)) {
throw new FileException(sprintf('Unable to create the "%s" directory', $directory));
}
} elseif (!is_writable($directory)) {
throw new FileException(sprintf('Unable to write in the "%s" directory', $directory));
}
$target = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : basename($name));
if (!@rename($this->getPathname(), $target)) {
$error = error_get_last();
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
}
@chmod($target, 0666 & ~umask());
return new File($target);
}
}

View File

@@ -0,0 +1,102 @@
<?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\File\MimeType;
/**
* A singleton mime type to file extension guesser.
*
* A default guesser is provided.
* You can register custom guessers by calling the register()
* method on the singleton instance.
*
* <code>
* $guesser = ExtensionGuesser::getInstance();
* $guesser->register(new MyCustomExtensionGuesser());
* </code>
*
* The last registered guesser is preferred over previously registered ones.
*
*/
class ExtensionGuesser implements ExtensionGuesserInterface
{
/**
* The singleton instance
*
* @var ExtensionGuesser
*/
private static $instance = null;
/**
* All registered ExtensionGuesserInterface instances
*
* @var array
*/
protected $guessers = array();
/**
* Returns the singleton instance
*
* @return ExtensionGuesser
*/
public static function getInstance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Registers all natively provided extension guessers
*/
private function __construct()
{
$this->register(new MimeTypeExtensionGuesser());
}
/**
* Registers a new extension guesser
*
* When guessing, this guesser is preferred over previously registered ones.
*
* @param ExtensionGuesserInterface $guesser
*/
public function register(ExtensionGuesserInterface $guesser)
{
array_unshift($this->guessers, $guesser);
}
/**
* Tries to guess the extension
*
* The mime type is passed to each registered mime type guesser in reverse order
* of their registration (last registered is queried first). Once a guesser
* returns a value that is not NULL, this method terminates and returns the
* value.
*
* @param string $mimeType The mime type
* @return string The guessed extension or NULL, if none could be guessed
*/
public function guess($mimeType)
{
foreach ($this->guessers as $guesser) {
$extension = $guesser->guess($mimeType);
if (null !== $extension) {
break;
}
}
return $extension;
}
}

View File

@@ -0,0 +1,26 @@
<?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\File\MimeType;
/**
* Guesses the file extension corresponding to a given mime type
*/
interface ExtensionGuesserInterface
{
/**
* Makes a best guess for a file extension, given a mime type
*
* @param string $mimeType The mime type
* @return string The guessed extension or NULL, if none could be guessed
*/
public function guess($mimeType);
}

View File

@@ -0,0 +1,87 @@
<?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\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
/**
* Guesses the mime type with the binary "file" (only available on *nix)
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
{
private $cmd;
/**
* Constructor.
*
* The $cmd pattern must contain a "%s" string that will be replaced
* with the file name to guess.
*
* The command output must start with the mime type of the file.
*
* @param string $cmd The command to run to get the mime type of a file
*/
public function __construct($cmd = 'file -b --mime %s 2>/dev/null')
{
$this->cmd = $cmd;
}
/**
* Returns whether this guesser is supported on the current OS
*
* @return Boolean
*/
public static function isSupported()
{
return !defined('PHP_WINDOWS_VERSION_BUILD');
}
/**
* {@inheritdoc}
*/
public function guess($path)
{
if (!is_file($path)) {
throw new FileNotFoundException($path);
}
if (!is_readable($path)) {
throw new AccessDeniedException($path);
}
if (!self::isSupported()) {
return null;
}
ob_start();
// need to use --mime instead of -i. see #6641
passthru(sprintf($this->cmd, escapeshellarg($path)), $return);
if ($return > 0) {
ob_end_clean();
return null;
}
$type = trim(ob_get_clean());
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-]+)#i', $type, $match)) {
// it's not a type, but an error message
return null;
}
return $match[1];
}
}

View File

@@ -0,0 +1,57 @@
<?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\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
/**
* Guesses the mime type using the PECL extension FileInfo
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
{
/**
* Returns whether this guesser is supported on the current OS/PHP setup
*
* @return Boolean
*/
public static function isSupported()
{
return function_exists('finfo_open');
}
/**
* {@inheritdoc}
*/
public function guess($path)
{
if (!is_file($path)) {
throw new FileNotFoundException($path);
}
if (!is_readable($path)) {
throw new AccessDeniedException($path);
}
if (!self::isSupported()) {
return null;
}
if (!$finfo = new \finfo(FILEINFO_MIME_TYPE)) {
return null;
}
return $finfo->file($path);
}
}

View File

@@ -0,0 +1,740 @@
<?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\File\MimeType;
/**
* Provides a best-guess mapping of mime type to file extension.
*/
class MimeTypeExtensionGuesser implements ExtensionGuesserInterface
{
/**
* A map of mime types and their default extensions.
*
* This list has been placed under the public domain by the Apache HTTPD project.
*
* @see http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
*
* @var array
*/
protected $defaultExtensions = array(
'application/andrew-inset' => 'ez',
'application/applixware' => 'aw',
'application/atom+xml' => 'atom',
'application/atomcat+xml' => 'atomcat',
'application/atomsvc+xml' => 'atomsvc',
'application/ccxml+xml' => 'ccxml',
'application/cdmi-capability' => 'cdmia',
'application/cdmi-container' => 'cdmic',
'application/cdmi-domain' => 'cdmid',
'application/cdmi-object' => 'cdmio',
'application/cdmi-queue' => 'cdmiq',
'application/cu-seeme' => 'cu',
'application/davmount+xml' => 'davmount',
'application/dssc+der' => 'dssc',
'application/dssc+xml' => 'xdssc',
'application/ecmascript' => 'ecma',
'application/emma+xml' => 'emma',
'application/epub+zip' => 'epub',
'application/exi' => 'exi',
'application/font-tdpfr' => 'pfr',
'application/hyperstudio' => 'stk',
'application/inkml+xml' => 'ink',
'application/ipfix' => 'ipfix',
'application/java-archive' => 'jar',
'application/java-serialized-object' => 'ser',
'application/java-vm' => 'class',
'application/javascript' => 'js',
'application/json' => 'json',
'application/lost+xml' => 'lostxml',
'application/mac-binhex40' => 'hqx',
'application/mac-compactpro' => 'cpt',
'application/mads+xml' => 'mads',
'application/marc' => 'mrc',
'application/marcxml+xml' => 'mrcx',
'application/mathematica' => 'ma',
'application/mathml+xml' => 'mathml',
'application/mbox' => 'mbox',
'application/mediaservercontrol+xml' => 'mscml',
'application/metalink4+xml' => 'meta4',
'application/mets+xml' => 'mets',
'application/mods+xml' => 'mods',
'application/mp21' => 'm21',
'application/mp4' => 'mp4s',
'application/msword' => 'doc',
'application/mxf' => 'mxf',
'application/octet-stream' => 'bin',
'application/oda' => 'oda',
'application/oebps-package+xml' => 'opf',
'application/ogg' => 'ogx',
'application/onenote' => 'onetoc',
'application/oxps' => 'oxps',
'application/patch-ops-error+xml' => 'xer',
'application/pdf' => 'pdf',
'application/pgp-encrypted' => 'pgp',
'application/pgp-signature' => 'asc',
'application/pics-rules' => 'prf',
'application/pkcs10' => 'p10',
'application/pkcs7-mime' => 'p7m',
'application/pkcs7-signature' => 'p7s',
'application/pkcs8' => 'p8',
'application/pkix-attr-cert' => 'ac',
'application/pkix-cert' => 'cer',
'application/pkix-crl' => 'crl',
'application/pkix-pkipath' => 'pkipath',
'application/pkixcmp' => 'pki',
'application/pls+xml' => 'pls',
'application/postscript' => 'ai',
'application/prs.cww' => 'cww',
'application/pskc+xml' => 'pskcxml',
'application/rdf+xml' => 'rdf',
'application/reginfo+xml' => 'rif',
'application/relax-ng-compact-syntax' => 'rnc',
'application/resource-lists+xml' => 'rl',
'application/resource-lists-diff+xml' => 'rld',
'application/rls-services+xml' => 'rs',
'application/rpki-ghostbusters' => 'gbr',
'application/rpki-manifest' => 'mft',
'application/rpki-roa' => 'roa',
'application/rsd+xml' => 'rsd',
'application/rss+xml' => 'rss',
'application/rtf' => 'rtf',
'application/sbml+xml' => 'sbml',
'application/scvp-cv-request' => 'scq',
'application/scvp-cv-response' => 'scs',
'application/scvp-vp-request' => 'spq',
'application/scvp-vp-response' => 'spp',
'application/sdp' => 'sdp',
'application/set-payment-initiation' => 'setpay',
'application/set-registration-initiation' => 'setreg',
'application/shf+xml' => 'shf',
'application/smil+xml' => 'smi',
'application/sparql-query' => 'rq',
'application/sparql-results+xml' => 'srx',
'application/srgs' => 'gram',
'application/srgs+xml' => 'grxml',
'application/sru+xml' => 'sru',
'application/ssml+xml' => 'ssml',
'application/tei+xml' => 'tei',
'application/thraud+xml' => 'tfi',
'application/timestamped-data' => 'tsd',
'application/vnd.3gpp.pic-bw-large' => 'plb',
'application/vnd.3gpp.pic-bw-small' => 'psb',
'application/vnd.3gpp.pic-bw-var' => 'pvb',
'application/vnd.3gpp2.tcap' => 'tcap',
'application/vnd.3m.post-it-notes' => 'pwn',
'application/vnd.accpac.simply.aso' => 'aso',
'application/vnd.accpac.simply.imp' => 'imp',
'application/vnd.acucobol' => 'acu',
'application/vnd.acucorp' => 'atc',
'application/vnd.adobe.air-application-installer-package+zip' => 'air',
'application/vnd.adobe.fxp' => 'fxp',
'application/vnd.adobe.xdp+xml' => 'xdp',
'application/vnd.adobe.xfdf' => 'xfdf',
'application/vnd.ahead.space' => 'ahead',
'application/vnd.airzip.filesecure.azf' => 'azf',
'application/vnd.airzip.filesecure.azs' => 'azs',
'application/vnd.amazon.ebook' => 'azw',
'application/vnd.americandynamics.acc' => 'acc',
'application/vnd.amiga.ami' => 'ami',
'application/vnd.android.package-archive' => 'apk',
'application/vnd.anser-web-certificate-issue-initiation' => 'cii',
'application/vnd.anser-web-funds-transfer-initiation' => 'fti',
'application/vnd.antix.game-component' => 'atx',
'application/vnd.apple.installer+xml' => 'mpkg',
'application/vnd.apple.mpegurl' => 'm3u8',
'application/vnd.aristanetworks.swi' => 'swi',
'application/vnd.astraea-software.iota' => 'iota',
'application/vnd.audiograph' => 'aep',
'application/vnd.blueice.multipass' => 'mpm',
'application/vnd.bmi' => 'bmi',
'application/vnd.businessobjects' => 'rep',
'application/vnd.chemdraw+xml' => 'cdxml',
'application/vnd.chipnuts.karaoke-mmd' => 'mmd',
'application/vnd.cinderella' => 'cdy',
'application/vnd.claymore' => 'cla',
'application/vnd.cloanto.rp9' => 'rp9',
'application/vnd.clonk.c4group' => 'c4g',
'application/vnd.cluetrust.cartomobile-config' => 'c11amc',
'application/vnd.cluetrust.cartomobile-config-pkg' => 'c11amz',
'application/vnd.commonspace' => 'csp',
'application/vnd.contact.cmsg' => 'cdbcmsg',
'application/vnd.cosmocaller' => 'cmc',
'application/vnd.crick.clicker' => 'clkx',
'application/vnd.crick.clicker.keyboard' => 'clkk',
'application/vnd.crick.clicker.palette' => 'clkp',
'application/vnd.crick.clicker.template' => 'clkt',
'application/vnd.crick.clicker.wordbank' => 'clkw',
'application/vnd.criticaltools.wbs+xml' => 'wbs',
'application/vnd.ctc-posml' => 'pml',
'application/vnd.cups-ppd' => 'ppd',
'application/vnd.curl.car' => 'car',
'application/vnd.curl.pcurl' => 'pcurl',
'application/vnd.data-vision.rdz' => 'rdz',
'application/vnd.dece.data' => 'uvf',
'application/vnd.dece.ttml+xml' => 'uvt',
'application/vnd.dece.unspecified' => 'uvx',
'application/vnd.dece.zip' => 'uvz',
'application/vnd.denovo.fcselayout-link' => 'fe_launch',
'application/vnd.dna' => 'dna',
'application/vnd.dolby.mlp' => 'mlp',
'application/vnd.dpgraph' => 'dpg',
'application/vnd.dreamfactory' => 'dfac',
'application/vnd.dvb.ait' => 'ait',
'application/vnd.dvb.service' => 'svc',
'application/vnd.dynageo' => 'geo',
'application/vnd.ecowin.chart' => 'mag',
'application/vnd.enliven' => 'nml',
'application/vnd.epson.esf' => 'esf',
'application/vnd.epson.msf' => 'msf',
'application/vnd.epson.quickanime' => 'qam',
'application/vnd.epson.salt' => 'slt',
'application/vnd.epson.ssf' => 'ssf',
'application/vnd.eszigno3+xml' => 'es3',
'application/vnd.ezpix-album' => 'ez2',
'application/vnd.ezpix-package' => 'ez3',
'application/vnd.fdf' => 'fdf',
'application/vnd.fdsn.mseed' => 'mseed',
'application/vnd.fdsn.seed' => 'seed',
'application/vnd.flographit' => 'gph',
'application/vnd.fluxtime.clip' => 'ftc',
'application/vnd.framemaker' => 'fm',
'application/vnd.frogans.fnc' => 'fnc',
'application/vnd.frogans.ltf' => 'ltf',
'application/vnd.fsc.weblaunch' => 'fsc',
'application/vnd.fujitsu.oasys' => 'oas',
'application/vnd.fujitsu.oasys2' => 'oa2',
'application/vnd.fujitsu.oasys3' => 'oa3',
'application/vnd.fujitsu.oasysgp' => 'fg5',
'application/vnd.fujitsu.oasysprs' => 'bh2',
'application/vnd.fujixerox.ddd' => 'ddd',
'application/vnd.fujixerox.docuworks' => 'xdw',
'application/vnd.fujixerox.docuworks.binder' => 'xbd',
'application/vnd.fuzzysheet' => 'fzs',
'application/vnd.genomatix.tuxedo' => 'txd',
'application/vnd.geogebra.file' => 'ggb',
'application/vnd.geogebra.tool' => 'ggt',
'application/vnd.geometry-explorer' => 'gex',
'application/vnd.geonext' => 'gxt',
'application/vnd.geoplan' => 'g2w',
'application/vnd.geospace' => 'g3w',
'application/vnd.gmx' => 'gmx',
'application/vnd.google-earth.kml+xml' => 'kml',
'application/vnd.google-earth.kmz' => 'kmz',
'application/vnd.grafeq' => 'gqf',
'application/vnd.groove-account' => 'gac',
'application/vnd.groove-help' => 'ghf',
'application/vnd.groove-identity-message' => 'gim',
'application/vnd.groove-injector' => 'grv',
'application/vnd.groove-tool-message' => 'gtm',
'application/vnd.groove-tool-template' => 'tpl',
'application/vnd.groove-vcard' => 'vcg',
'application/vnd.hal+xml' => 'hal',
'application/vnd.handheld-entertainment+xml' => 'zmm',
'application/vnd.hbci' => 'hbci',
'application/vnd.hhe.lesson-player' => 'les',
'application/vnd.hp-hpgl' => 'hpgl',
'application/vnd.hp-hpid' => 'hpid',
'application/vnd.hp-hps' => 'hps',
'application/vnd.hp-jlyt' => 'jlt',
'application/vnd.hp-pcl' => 'pcl',
'application/vnd.hp-pclxl' => 'pclxl',
'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx',
'application/vnd.hzn-3d-crossword' => 'x3d',
'application/vnd.ibm.minipay' => 'mpy',
'application/vnd.ibm.modcap' => 'afp',
'application/vnd.ibm.rights-management' => 'irm',
'application/vnd.ibm.secure-container' => 'sc',
'application/vnd.iccprofile' => 'icc',
'application/vnd.igloader' => 'igl',
'application/vnd.immervision-ivp' => 'ivp',
'application/vnd.immervision-ivu' => 'ivu',
'application/vnd.insors.igm' => 'igm',
'application/vnd.intercon.formnet' => 'xpw',
'application/vnd.intergeo' => 'i2g',
'application/vnd.intu.qbo' => 'qbo',
'application/vnd.intu.qfx' => 'qfx',
'application/vnd.ipunplugged.rcprofile' => 'rcprofile',
'application/vnd.irepository.package+xml' => 'irp',
'application/vnd.is-xpr' => 'xpr',
'application/vnd.isac.fcs' => 'fcs',
'application/vnd.jam' => 'jam',
'application/vnd.jcp.javame.midlet-rms' => 'rms',
'application/vnd.jisp' => 'jisp',
'application/vnd.joost.joda-archive' => 'joda',
'application/vnd.kahootz' => 'ktz',
'application/vnd.kde.karbon' => 'karbon',
'application/vnd.kde.kchart' => 'chrt',
'application/vnd.kde.kformula' => 'kfo',
'application/vnd.kde.kivio' => 'flw',
'application/vnd.kde.kontour' => 'kon',
'application/vnd.kde.kpresenter' => 'kpr',
'application/vnd.kde.kspread' => 'ksp',
'application/vnd.kde.kword' => 'kwd',
'application/vnd.kenameaapp' => 'htke',
'application/vnd.kidspiration' => 'kia',
'application/vnd.kinar' => 'kne',
'application/vnd.koan' => 'skp',
'application/vnd.kodak-descriptor' => 'sse',
'application/vnd.las.las+xml' => 'lasxml',
'application/vnd.llamagraphics.life-balance.desktop' => 'lbd',
'application/vnd.llamagraphics.life-balance.exchange+xml' => 'lbe',
'application/vnd.lotus-1-2-3' => '123',
'application/vnd.lotus-approach' => 'apr',
'application/vnd.lotus-freelance' => 'pre',
'application/vnd.lotus-notes' => 'nsf',
'application/vnd.lotus-organizer' => 'org',
'application/vnd.lotus-screencam' => 'scm',
'application/vnd.lotus-wordpro' => 'lwp',
'application/vnd.macports.portpkg' => 'portpkg',
'application/vnd.mcd' => 'mcd',
'application/vnd.medcalcdata' => 'mc1',
'application/vnd.mediastation.cdkey' => 'cdkey',
'application/vnd.mfer' => 'mwf',
'application/vnd.mfmp' => 'mfm',
'application/vnd.micrografx.flo' => 'flo',
'application/vnd.micrografx.igx' => 'igx',
'application/vnd.mif' => 'mif',
'application/vnd.mobius.daf' => 'daf',
'application/vnd.mobius.dis' => 'dis',
'application/vnd.mobius.mbk' => 'mbk',
'application/vnd.mobius.mqy' => 'mqy',
'application/vnd.mobius.msl' => 'msl',
'application/vnd.mobius.plc' => 'plc',
'application/vnd.mobius.txf' => 'txf',
'application/vnd.mophun.application' => 'mpn',
'application/vnd.mophun.certificate' => 'mpc',
'application/vnd.mozilla.xul+xml' => 'xul',
'application/vnd.ms-artgalry' => 'cil',
'application/vnd.ms-cab-compressed' => 'cab',
'application/vnd.ms-excel' => 'xls',
'application/vnd.ms-excel.addin.macroenabled.12' => 'xlam',
'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 'xlsb',
'application/vnd.ms-excel.sheet.macroenabled.12' => 'xlsm',
'application/vnd.ms-excel.template.macroenabled.12' => 'xltm',
'application/vnd.ms-fontobject' => 'eot',
'application/vnd.ms-htmlhelp' => 'chm',
'application/vnd.ms-ims' => 'ims',
'application/vnd.ms-lrm' => 'lrm',
'application/vnd.ms-officetheme' => 'thmx',
'application/vnd.ms-pki.seccat' => 'cat',
'application/vnd.ms-pki.stl' => 'stl',
'application/vnd.ms-powerpoint' => 'ppt',
'application/vnd.ms-powerpoint.addin.macroenabled.12' => 'ppam',
'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'pptm',
'application/vnd.ms-powerpoint.slide.macroenabled.12' => 'sldm',
'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'ppsm',
'application/vnd.ms-powerpoint.template.macroenabled.12' => 'potm',
'application/vnd.ms-project' => 'mpp',
'application/vnd.ms-word.document.macroenabled.12' => 'docm',
'application/vnd.ms-word.template.macroenabled.12' => 'dotm',
'application/vnd.ms-works' => 'wps',
'application/vnd.ms-wpl' => 'wpl',
'application/vnd.ms-xpsdocument' => 'xps',
'application/vnd.mseq' => 'mseq',
'application/vnd.musician' => 'mus',
'application/vnd.muvee.style' => 'msty',
'application/vnd.mynfc' => 'taglet',
'application/vnd.neurolanguage.nlu' => 'nlu',
'application/vnd.noblenet-directory' => 'nnd',
'application/vnd.noblenet-sealer' => 'nns',
'application/vnd.noblenet-web' => 'nnw',
'application/vnd.nokia.n-gage.data' => 'ngdat',
'application/vnd.nokia.n-gage.symbian.install' => 'n-gage',
'application/vnd.nokia.radio-preset' => 'rpst',
'application/vnd.nokia.radio-presets' => 'rpss',
'application/vnd.novadigm.edm' => 'edm',
'application/vnd.novadigm.edx' => 'edx',
'application/vnd.novadigm.ext' => 'ext',
'application/vnd.oasis.opendocument.chart' => 'odc',
'application/vnd.oasis.opendocument.chart-template' => 'otc',
'application/vnd.oasis.opendocument.database' => 'odb',
'application/vnd.oasis.opendocument.formula' => 'odf',
'application/vnd.oasis.opendocument.formula-template' => 'odft',
'application/vnd.oasis.opendocument.graphics' => 'odg',
'application/vnd.oasis.opendocument.graphics-template' => 'otg',
'application/vnd.oasis.opendocument.image' => 'odi',
'application/vnd.oasis.opendocument.image-template' => 'oti',
'application/vnd.oasis.opendocument.presentation' => 'odp',
'application/vnd.oasis.opendocument.presentation-template' => 'otp',
'application/vnd.oasis.opendocument.spreadsheet' => 'ods',
'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots',
'application/vnd.oasis.opendocument.text' => 'odt',
'application/vnd.oasis.opendocument.text-master' => 'odm',
'application/vnd.oasis.opendocument.text-template' => 'ott',
'application/vnd.oasis.opendocument.text-web' => 'oth',
'application/vnd.olpc-sugar' => 'xo',
'application/vnd.oma.dd2+xml' => 'dd2',
'application/vnd.openofficeorg.extension' => 'oxt',
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
'application/vnd.openxmlformats-officedocument.presentationml.slide' => 'sldx',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx',
'application/vnd.openxmlformats-officedocument.presentationml.template' => 'potx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'xltx',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx',
'application/vnd.osgeo.mapguide.package' => 'mgp',
'application/vnd.osgi.dp' => 'dp',
'application/vnd.palm' => 'pdb',
'application/vnd.pawaafile' => 'paw',
'application/vnd.pg.format' => 'str',
'application/vnd.pg.osasli' => 'ei6',
'application/vnd.picsel' => 'efif',
'application/vnd.pmi.widget' => 'wg',
'application/vnd.pocketlearn' => 'plf',
'application/vnd.powerbuilder6' => 'pbd',
'application/vnd.previewsystems.box' => 'box',
'application/vnd.proteus.magazine' => 'mgz',
'application/vnd.publishare-delta-tree' => 'qps',
'application/vnd.pvi.ptid1' => 'ptid',
'application/vnd.quark.quarkxpress' => 'qxd',
'application/vnd.realvnc.bed' => 'bed',
'application/vnd.recordare.musicxml' => 'mxl',
'application/vnd.recordare.musicxml+xml' => 'musicxml',
'application/vnd.rig.cryptonote' => 'cryptonote',
'application/vnd.rim.cod' => 'cod',
'application/vnd.rn-realmedia' => 'rm',
'application/vnd.route66.link66+xml' => 'link66',
'application/vnd.sailingtracker.track' => 'st',
'application/vnd.seemail' => 'see',
'application/vnd.sema' => 'sema',
'application/vnd.semd' => 'semd',
'application/vnd.semf' => 'semf',
'application/vnd.shana.informed.formdata' => 'ifm',
'application/vnd.shana.informed.formtemplate' => 'itp',
'application/vnd.shana.informed.interchange' => 'iif',
'application/vnd.shana.informed.package' => 'ipk',
'application/vnd.simtech-mindmapper' => 'twd',
'application/vnd.smaf' => 'mmf',
'application/vnd.smart.teacher' => 'teacher',
'application/vnd.solent.sdkm+xml' => 'sdkm',
'application/vnd.spotfire.dxp' => 'dxp',
'application/vnd.spotfire.sfs' => 'sfs',
'application/vnd.stardivision.calc' => 'sdc',
'application/vnd.stardivision.draw' => 'sda',
'application/vnd.stardivision.impress' => 'sdd',
'application/vnd.stardivision.math' => 'smf',
'application/vnd.stardivision.writer' => 'sdw',
'application/vnd.stardivision.writer-global' => 'sgl',
'application/vnd.stepmania.package' => 'smzip',
'application/vnd.stepmania.stepchart' => 'sm',
'application/vnd.sun.xml.calc' => 'sxc',
'application/vnd.sun.xml.calc.template' => 'stc',
'application/vnd.sun.xml.draw' => 'sxd',
'application/vnd.sun.xml.draw.template' => 'std',
'application/vnd.sun.xml.impress' => 'sxi',
'application/vnd.sun.xml.impress.template' => 'sti',
'application/vnd.sun.xml.math' => 'sxm',
'application/vnd.sun.xml.writer' => 'sxw',
'application/vnd.sun.xml.writer.global' => 'sxg',
'application/vnd.sun.xml.writer.template' => 'stw',
'application/vnd.sus-calendar' => 'sus',
'application/vnd.svd' => 'svd',
'application/vnd.symbian.install' => 'sis',
'application/vnd.syncml+xml' => 'xsm',
'application/vnd.syncml.dm+wbxml' => 'bdm',
'application/vnd.syncml.dm+xml' => 'xdm',
'application/vnd.tao.intent-module-archive' => 'tao',
'application/vnd.tcpdump.pcap' => 'pcap',
'application/vnd.tmobile-livetv' => 'tmo',
'application/vnd.trid.tpt' => 'tpt',
'application/vnd.triscape.mxs' => 'mxs',
'application/vnd.trueapp' => 'tra',
'application/vnd.ufdl' => 'ufd',
'application/vnd.uiq.theme' => 'utz',
'application/vnd.umajin' => 'umj',
'application/vnd.unity' => 'unityweb',
'application/vnd.uoml+xml' => 'uoml',
'application/vnd.vcx' => 'vcx',
'application/vnd.visio' => 'vsd',
'application/vnd.visionary' => 'vis',
'application/vnd.vsf' => 'vsf',
'application/vnd.wap.wbxml' => 'wbxml',
'application/vnd.wap.wmlc' => 'wmlc',
'application/vnd.wap.wmlscriptc' => 'wmlsc',
'application/vnd.webturbo' => 'wtb',
'application/vnd.wolfram.player' => 'nbp',
'application/vnd.wordperfect' => 'wpd',
'application/vnd.wqd' => 'wqd',
'application/vnd.wt.stf' => 'stf',
'application/vnd.xara' => 'xar',
'application/vnd.xfdl' => 'xfdl',
'application/vnd.yamaha.hv-dic' => 'hvd',
'application/vnd.yamaha.hv-script' => 'hvs',
'application/vnd.yamaha.hv-voice' => 'hvp',
'application/vnd.yamaha.openscoreformat' => 'osf',
'application/vnd.yamaha.openscoreformat.osfpvg+xml' => 'osfpvg',
'application/vnd.yamaha.smaf-audio' => 'saf',
'application/vnd.yamaha.smaf-phrase' => 'spf',
'application/vnd.yellowriver-custom-menu' => 'cmp',
'application/vnd.zul' => 'zir',
'application/vnd.zzazz.deck+xml' => 'zaz',
'application/voicexml+xml' => 'vxml',
'application/widget' => 'wgt',
'application/winhlp' => 'hlp',
'application/wsdl+xml' => 'wsdl',
'application/wspolicy+xml' => 'wspolicy',
'application/x-7z-compressed' => '7z',
'application/x-abiword' => 'abw',
'application/x-ace-compressed' => 'ace',
'application/x-authorware-bin' => 'aab',
'application/x-authorware-map' => 'aam',
'application/x-authorware-seg' => 'aas',
'application/x-bcpio' => 'bcpio',
'application/x-bittorrent' => 'torrent',
'application/x-bzip' => 'bz',
'application/x-bzip2' => 'bz2',
'application/x-cdlink' => 'vcd',
'application/x-chat' => 'chat',
'application/x-chess-pgn' => 'pgn',
'application/x-cpio' => 'cpio',
'application/x-csh' => 'csh',
'application/x-debian-package' => 'deb',
'application/x-director' => 'dir',
'application/x-doom' => 'wad',
'application/x-dtbncx+xml' => 'ncx',
'application/x-dtbook+xml' => 'dtb',
'application/x-dtbresource+xml' => 'res',
'application/x-dvi' => 'dvi',
'application/x-font-bdf' => 'bdf',
'application/x-font-ghostscript' => 'gsf',
'application/x-font-linux-psf' => 'psf',
'application/x-font-otf' => 'otf',
'application/x-font-pcf' => 'pcf',
'application/x-font-snf' => 'snf',
'application/x-font-ttf' => 'ttf',
'application/x-font-type1' => 'pfa',
'application/x-font-woff' => 'woff',
'application/x-futuresplash' => 'spl',
'application/x-gnumeric' => 'gnumeric',
'application/x-gtar' => 'gtar',
'application/x-hdf' => 'hdf',
'application/x-java-jnlp-file' => 'jnlp',
'application/x-latex' => 'latex',
'application/x-mobipocket-ebook' => 'prc',
'application/x-ms-application' => 'application',
'application/x-ms-wmd' => 'wmd',
'application/x-ms-wmz' => 'wmz',
'application/x-ms-xbap' => 'xbap',
'application/x-msaccess' => 'mdb',
'application/x-msbinder' => 'obd',
'application/x-mscardfile' => 'crd',
'application/x-msclip' => 'clp',
'application/x-msdownload' => 'exe',
'application/x-msmediaview' => 'mvb',
'application/x-msmetafile' => 'wmf',
'application/x-msmoney' => 'mny',
'application/x-mspublisher' => 'pub',
'application/x-msschedule' => 'scd',
'application/x-msterminal' => 'trm',
'application/x-mswrite' => 'wri',
'application/x-netcdf' => 'nc',
'application/x-pkcs12' => 'p12',
'application/x-pkcs7-certificates' => 'p7b',
'application/x-pkcs7-certreqresp' => 'p7r',
'application/x-rar-compressed' => 'rar',
'application/x-rar' => 'rar',
'application/x-sh' => 'sh',
'application/x-shar' => 'shar',
'application/x-shockwave-flash' => 'swf',
'application/x-silverlight-app' => 'xap',
'application/x-stuffit' => 'sit',
'application/x-stuffitx' => 'sitx',
'application/x-sv4cpio' => 'sv4cpio',
'application/x-sv4crc' => 'sv4crc',
'application/x-tar' => 'tar',
'application/x-tcl' => 'tcl',
'application/x-tex' => 'tex',
'application/x-tex-tfm' => 'tfm',
'application/x-texinfo' => 'texinfo',
'application/x-ustar' => 'ustar',
'application/x-wais-source' => 'src',
'application/x-x509-ca-cert' => 'der',
'application/x-xfig' => 'fig',
'application/x-xpinstall' => 'xpi',
'application/xcap-diff+xml' => 'xdf',
'application/xenc+xml' => 'xenc',
'application/xhtml+xml' => 'xhtml',
'application/xml' => 'xml',
'application/xml-dtd' => 'dtd',
'application/xop+xml' => 'xop',
'application/xslt+xml' => 'xslt',
'application/xspf+xml' => 'xspf',
'application/xv+xml' => 'mxml',
'application/yang' => 'yang',
'application/yin+xml' => 'yin',
'application/zip' => 'zip',
'audio/adpcm' => 'adp',
'audio/basic' => 'au',
'audio/midi' => 'mid',
'audio/mp4' => 'mp4a',
'audio/mpeg' => 'mpga',
'audio/ogg' => 'oga',
'audio/vnd.dece.audio' => 'uva',
'audio/vnd.digital-winds' => 'eol',
'audio/vnd.dra' => 'dra',
'audio/vnd.dts' => 'dts',
'audio/vnd.dts.hd' => 'dtshd',
'audio/vnd.lucent.voice' => 'lvp',
'audio/vnd.ms-playready.media.pya' => 'pya',
'audio/vnd.nuera.ecelp4800' => 'ecelp4800',
'audio/vnd.nuera.ecelp7470' => 'ecelp7470',
'audio/vnd.nuera.ecelp9600' => 'ecelp9600',
'audio/vnd.rip' => 'rip',
'audio/webm' => 'weba',
'audio/x-aac' => 'aac',
'audio/x-aiff' => 'aif',
'audio/x-mpegurl' => 'm3u',
'audio/x-ms-wax' => 'wax',
'audio/x-ms-wma' => 'wma',
'audio/x-pn-realaudio' => 'ram',
'audio/x-pn-realaudio-plugin' => 'rmp',
'audio/x-wav' => 'wav',
'chemical/x-cdx' => 'cdx',
'chemical/x-cif' => 'cif',
'chemical/x-cmdf' => 'cmdf',
'chemical/x-cml' => 'cml',
'chemical/x-csml' => 'csml',
'chemical/x-xyz' => 'xyz',
'image/bmp' => 'bmp',
'image/cgm' => 'cgm',
'image/g3fax' => 'g3',
'image/gif' => 'gif',
'image/ief' => 'ief',
'image/jpeg' => 'jpeg',
'image/ktx' => 'ktx',
'image/png' => 'png',
'image/prs.btif' => 'btif',
'image/svg+xml' => 'svg',
'image/tiff' => 'tiff',
'image/vnd.adobe.photoshop' => 'psd',
'image/vnd.dece.graphic' => 'uvi',
'image/vnd.dvb.subtitle' => 'sub',
'image/vnd.djvu' => 'djvu',
'image/vnd.dwg' => 'dwg',
'image/vnd.dxf' => 'dxf',
'image/vnd.fastbidsheet' => 'fbs',
'image/vnd.fpx' => 'fpx',
'image/vnd.fst' => 'fst',
'image/vnd.fujixerox.edmics-mmr' => 'mmr',
'image/vnd.fujixerox.edmics-rlc' => 'rlc',
'image/vnd.ms-modi' => 'mdi',
'image/vnd.net-fpx' => 'npx',
'image/vnd.wap.wbmp' => 'wbmp',
'image/vnd.xiff' => 'xif',
'image/webp' => 'webp',
'image/x-cmu-raster' => 'ras',
'image/x-cmx' => 'cmx',
'image/x-freehand' => 'fh',
'image/x-icon' => 'ico',
'image/x-pcx' => 'pcx',
'image/x-pict' => 'pic',
'image/x-portable-anymap' => 'pnm',
'image/x-portable-bitmap' => 'pbm',
'image/x-portable-graymap' => 'pgm',
'image/x-portable-pixmap' => 'ppm',
'image/x-rgb' => 'rgb',
'image/x-xbitmap' => 'xbm',
'image/x-xpixmap' => 'xpm',
'image/x-xwindowdump' => 'xwd',
'message/rfc822' => 'eml',
'model/iges' => 'igs',
'model/mesh' => 'msh',
'model/vnd.collada+xml' => 'dae',
'model/vnd.dwf' => 'dwf',
'model/vnd.gdl' => 'gdl',
'model/vnd.gtw' => 'gtw',
'model/vnd.mts' => 'mts',
'model/vnd.vtu' => 'vtu',
'model/vrml' => 'wrl',
'text/calendar' => 'ics',
'text/css' => 'css',
'text/csv' => 'csv',
'text/html' => 'html',
'text/n3' => 'n3',
'text/plain' => 'txt',
'text/prs.lines.tag' => 'dsc',
'text/richtext' => 'rtx',
'text/sgml' => 'sgml',
'text/tab-separated-values' => 'tsv',
'text/troff' => 't',
'text/turtle' => 'ttl',
'text/uri-list' => 'uri',
'text/vcard' => 'vcard',
'text/vnd.curl' => 'curl',
'text/vnd.curl.dcurl' => 'dcurl',
'text/vnd.curl.scurl' => 'scurl',
'text/vnd.curl.mcurl' => 'mcurl',
'text/vnd.dvb.subtitle' => 'sub',
'text/vnd.fly' => 'fly',
'text/vnd.fmi.flexstor' => 'flx',
'text/vnd.graphviz' => 'gv',
'text/vnd.in3d.3dml' => '3dml',
'text/vnd.in3d.spot' => 'spot',
'text/vnd.sun.j2me.app-descriptor' => 'jad',
'text/vnd.wap.wml' => 'wml',
'text/vnd.wap.wmlscript' => 'wmls',
'text/x-asm' => 's',
'text/x-c' => 'c',
'text/x-fortran' => 'f',
'text/x-pascal' => 'p',
'text/x-java-source' => 'java',
'text/x-setext' => 'etx',
'text/x-uuencode' => 'uu',
'text/x-vcalendar' => 'vcs',
'text/x-vcard' => 'vcf',
'video/3gpp' => '3gp',
'video/3gpp2' => '3g2',
'video/h261' => 'h261',
'video/h263' => 'h263',
'video/h264' => 'h264',
'video/jpeg' => 'jpgv',
'video/jpm' => 'jpm',
'video/mj2' => 'mj2',
'video/mp4' => 'mp4',
'video/mpeg' => 'mpeg',
'video/ogg' => 'ogv',
'video/quicktime' => 'qt',
'video/vnd.dece.hd' => 'uvh',
'video/vnd.dece.mobile' => 'uvm',
'video/vnd.dece.pd' => 'uvp',
'video/vnd.dece.sd' => 'uvs',
'video/vnd.dece.video' => 'uvv',
'video/vnd.dvb.file' => 'dvb',
'video/vnd.fvt' => 'fvt',
'video/vnd.mpegurl' => 'mxu',
'video/vnd.ms-playready.media.pyv' => 'pyv',
'video/vnd.uvvu.mp4' => 'uvu',
'video/vnd.vivo' => 'viv',
'video/webm' => 'webm',
'video/x-f4v' => 'f4v',
'video/x-fli' => 'fli',
'video/x-flv' => 'flv',
'video/x-m4v' => 'm4v',
'video/x-ms-asf' => 'asf',
'video/x-ms-wm' => 'wm',
'video/x-ms-wmv' => 'wmv',
'video/x-ms-wmx' => 'wmx',
'video/x-ms-wvx' => 'wvx',
'video/x-msvideo' => 'avi',
'video/x-sgi-movie' => 'movie',
'x-conference/x-cooltalk' => 'ice',
);
/**
* {@inheritdoc}
*/
public function guess($mimeType)
{
return isset($this->defaultExtensions[$mimeType]) ? $this->defaultExtensions[$mimeType] : null;
}
}

View File

@@ -0,0 +1,124 @@
<?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\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
/**
* A singleton mime type guesser.
*
* By default, all mime type guessers provided by the framework are installed
* (if available on the current OS/PHP setup). You can register custom
* guessers by calling the register() method on the singleton instance.
*
* <code>
* $guesser = MimeTypeGuesser::getInstance();
* $guesser->register(new MyCustomMimeTypeGuesser());
* </code>
*
* The last registered guesser is preferred over previously registered ones.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class MimeTypeGuesser implements MimeTypeGuesserInterface
{
/**
* The singleton instance
*
* @var MimeTypeGuesser
*/
private static $instance = null;
/**
* All registered MimeTypeGuesserInterface instances
*
* @var array
*/
protected $guessers = array();
/**
* Returns the singleton instance
*
* @return MimeTypeGuesser
*/
public static function getInstance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Registers all natively provided mime type guessers
*/
private function __construct()
{
if (FileBinaryMimeTypeGuesser::isSupported()) {
$this->register(new FileBinaryMimeTypeGuesser());
}
if (FileinfoMimeTypeGuesser::isSupported()) {
$this->register(new FileinfoMimeTypeGuesser());
}
}
/**
* Registers a new mime type guesser
*
* When guessing, this guesser is preferred over previously registered ones.
*
* @param MimeTypeGuesserInterface $guesser
*/
public function register(MimeTypeGuesserInterface $guesser)
{
array_unshift($this->guessers, $guesser);
}
/**
* Tries to guess the mime type of the given file
*
* The file is passed to each registered mime type guesser in reverse order
* of their registration (last registered is queried first). Once a guesser
* returns a value that is not NULL, this method terminates and returns the
* value.
*
* @param string $path The path to the file
*
* @return string The mime type or NULL, if none could be guessed
*
* @throws FileException If the file does not exist
*/
public function guess($path)
{
if (!is_file($path)) {
throw new FileNotFoundException($path);
}
if (!is_readable($path)) {
throw new AccessDeniedException($path);
}
if (!$this->guessers) {
throw new \LogicException('Unable to guess the mime type as no guessers are available (Did you enable the php_fileinfo extension?)');
}
foreach ($this->guessers as $guesser) {
if (null !== $mimeType = $guesser->guess($path)) {
return $mimeType;
}
}
}
}

View File

@@ -0,0 +1,35 @@
<?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\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
/**
* Guesses the mime type of a file
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface MimeTypeGuesserInterface
{
/**
* Guesses the mime type of the file with the given path.
*
* @param string $path The path to the file
*
* @return string The mime type or NULL, if none could be guessed
*
* @throws FileNotFoundException If the file does not exist
* @throws AccessDeniedException If the file could not be read
*/
public function guess($path);
}

View File

@@ -0,0 +1,223 @@
<?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\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
/**
* A file uploaded through a form.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Florian Eckerstorfer <florian@eckerstorfer.org>
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class UploadedFile extends File
{
/**
* Whether the test mode is activated.
*
* Local files are used in test mode hence the code should not enforce HTTP uploads.
*
* @var Boolean
*/
private $test = false;
/**
* The original name of the uploaded file.
*
* @var string
*/
private $originalName;
/**
* The mime type provided by the uploader.
*
* @var string
*/
private $mimeType;
/**
* The file size provided by the uploader.
*
* @var string
*/
private $size;
/**
* The UPLOAD_ERR_XXX constant provided by the uploader.
*
* @var integer
*/
private $error;
/**
* Accepts the information of the uploaded file as provided by the PHP global $_FILES.
*
* The file object is only created when the uploaded file is valid (i.e. when the
* isValid() method returns true). Otherwise the only methods that could be called
* on an UploadedFile instance are:
*
* * getClientOriginalName,
* * getClientMimeType,
* * isValid,
* * getError.
*
* Calling any other method on an non-valid instance will cause an unpredictable result.
*
* @param string $path The full temporary path to the file
* @param string $originalName The original file name
* @param string $mimeType The type of the file as provided by PHP
* @param integer $size The file size
* @param integer $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants)
* @param Boolean $test Whether the test mode is active
*
* @throws FileException If file_uploads is disabled
* @throws FileNotFoundException If the file does not exist
*
* @api
*/
public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null, $test = false)
{
if (!ini_get('file_uploads')) {
throw new FileException(sprintf('Unable to create UploadedFile because "file_uploads" is disabled in your php.ini file (%s)', get_cfg_var('cfg_file_path')));
}
$this->originalName = basename($originalName);
$this->mimeType = $mimeType ?: 'application/octet-stream';
$this->size = $size;
$this->error = $error ?: UPLOAD_ERR_OK;
$this->test = (Boolean) $test;
parent::__construct($path, UPLOAD_ERR_OK === $this->error);
}
/**
* Returns the original file name.
*
* It is extracted from the request from which the file has been uploaded.
* Then is should not be considered as a safe value.
*
* @return string|null The original name
*
* @api
*/
public function getClientOriginalName()
{
return $this->originalName;
}
/**
* Returns the file mime type.
*
* It is extracted from the request from which the file has been uploaded.
* Then is should not be considered as a safe value.
*
* @return string|null The mime type
*
* @api
*/
public function getClientMimeType()
{
return $this->mimeType;
}
/**
* Returns the file size.
*
* It is extracted from the request from which the file has been uploaded.
* Then is should not be considered as a safe value.
*
* @return integer|null The file size
*
* @api
*/
public function getClientSize()
{
return $this->size;
}
/**
* Returns the upload error.
*
* If the upload was successful, the constant UPLOAD_ERR_OK is returned.
* Otherwise one of the other UPLOAD_ERR_XXX constants is returned.
*
* @return integer The upload error
*
* @api
*/
public function getError()
{
return $this->error;
}
/**
* Returns whether the file was uploaded successfully.
*
* @return Boolean True if no error occurred during uploading
*
* @api
*/
public function isValid()
{
return $this->error === UPLOAD_ERR_OK;
}
/**
* Moves the file to a new location.
*
* @param string $directory The destination folder
* @param string $name The new file name
*
* @return File A File object representing the new file
*
* @throws FileException if the file has not been uploaded via Http
*
* @api
*/
public function move($directory, $name = null)
{
if ($this->isValid() && ($this->test || is_uploaded_file($this->getPathname()))) {
return parent::move($directory, $name);
}
throw new FileException(sprintf('The file "%s" has not been uploaded via Http', $this->getPathname()));
}
/**
* Returns the maximum size of an uploaded file as configured in php.ini
*
* @return int The maximum size of an uploaded file in bytes
*/
public static function getMaxFilesize()
{
$max = trim(ini_get('upload_max_filesize'));
if ('' === $max) {
return PHP_INT_MAX;
}
switch (strtolower(substr($max, -1))) {
case 'g':
$max *= 1024;
case 'm':
$max *= 1024;
case 'k':
$max *= 1024;
}
return (integer) $max;
}
}

View File

@@ -0,0 +1,155 @@
<?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;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* FileBag is a container for HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
*
* @api
*/
class FileBag extends ParameterBag
{
private static $fileKeys = array('error', 'name', 'size', 'tmp_name', 'type');
/**
* Constructor.
*
* @param array $parameters An array of HTTP files
*
* @api
*/
public function __construct(array $parameters = array())
{
$this->replace($parameters);
}
/**
* {@inheritdoc}
*
* @api
*/
public function replace(array $files = array())
{
$this->parameters = array();
$this->add($files);
}
/**
* {@inheritdoc}
*
* @api
*/
public function set($key, $value)
{
if (!is_array($value) && !$value instanceof UploadedFile) {
throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.');
}
parent::set($key, $this->convertFileInformation($value));
}
/**
* {@inheritdoc}
*
* @api
*/
public function add(array $files = array())
{
foreach ($files as $key => $file) {
$this->set($key, $file);
}
}
/**
* Converts uploaded files to UploadedFile instances.
*
* @param array|UploadedFile $file A (multi-dimensional) array of uploaded file information
*
* @return array A (multi-dimensional) array of UploadedFile instances
*/
protected function convertFileInformation($file)
{
if ($file instanceof UploadedFile) {
return $file;
}
$file = $this->fixPhpFilesArray($file);
if (is_array($file)) {
$keys = array_keys($file);
sort($keys);
if ($keys == self::$fileKeys) {
if (UPLOAD_ERR_NO_FILE == $file['error']) {
$file = null;
} else {
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']);
}
} else {
$file = array_map(array($this, 'convertFileInformation'), $file);
}
}
return $file;
}
/**
* Fixes a malformed PHP $_FILES array.
*
* PHP has a bug that the format of the $_FILES array differs, depending on
* whether the uploaded file fields had normal field names or array-like
* field names ("normal" vs. "parent[child]").
*
* This method fixes the array to look like the "normal" $_FILES array.
*
* It's safe to pass an already converted array, in which case this method
* just returns the original array unmodified.
*
* @param array $data
*
* @return array
*/
protected function fixPhpFilesArray($data)
{
if (!is_array($data)) {
return $data;
}
$keys = array_keys($data);
sort($keys);
if (self::$fileKeys != $keys || !isset($data['name']) || !is_array($data['name'])) {
return $data;
}
$files = $data;
foreach (self::$fileKeys as $k) {
unset($files[$k]);
}
foreach (array_keys($data['name']) as $key) {
$files[$key] = $this->fixPhpFilesArray(array(
'error' => $data['error'][$key],
'name' => $data['name'][$key],
'type' => $data['type'][$key],
'tmp_name' => $data['tmp_name'][$key],
'size' => $data['size'][$key]
));
}
return $files;
}
}

View File

@@ -0,0 +1,323 @@
<?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;
/**
* HeaderBag is a container for HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class HeaderBag implements \IteratorAggregate, \Countable
{
protected $headers;
protected $cacheControl;
/**
* Constructor.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function __construct(array $headers = array())
{
$this->cacheControl = array();
$this->headers = array();
foreach ($headers as $key => $values) {
$this->set($key, $values);
}
}
/**
* Returns the headers as a string.
*
* @return string The headers
*/
public function __toString()
{
if (!$this->headers) {
return '';
}
$max = max(array_map('strlen', array_keys($this->headers))) + 1;
$content = '';
ksort($this->headers);
foreach ($this->headers as $name => $values) {
$name = implode('-', array_map('ucfirst', explode('-', $name)));
foreach ($values as $value) {
$content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
}
}
return $content;
}
/**
* Returns the headers.
*
* @return array An array of headers
*
* @api
*/
public function all()
{
return $this->headers;
}
/**
* Returns the parameter keys.
*
* @return array An array of parameter keys
*
* @api
*/
public function keys()
{
return array_keys($this->headers);
}
/**
* Replaces the current HTTP headers by a new set.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function replace(array $headers = array())
{
$this->headers = array();
$this->add($headers);
}
/**
* Adds new headers the current HTTP headers set.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function add(array $headers)
{
foreach ($headers as $key => $values) {
$this->set($key, $values);
}
}
/**
* Returns a header value by name.
*
* @param string $key The header name
* @param mixed $default The default value
* @param Boolean $first Whether to return the first value or all header values
*
* @return string|array The first header value if $first is true, an array of values otherwise
*
* @api
*/
public function get($key, $default = null, $first = true)
{
$key = strtr(strtolower($key), '_', '-');
if (!array_key_exists($key, $this->headers)) {
if (null === $default) {
return $first ? null : array();
}
return $first ? $default : array($default);
}
if ($first) {
return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
}
return $this->headers[$key];
}
/**
* Sets a header by name.
*
* @param string $key The key
* @param string|array $values The value or an array of values
* @param Boolean $replace Whether to replace the actual value of not (true by default)
*
* @api
*/
public function set($key, $values, $replace = true)
{
$key = strtr(strtolower($key), '_', '-');
$values = array_values((array) $values);
if (true === $replace || !isset($this->headers[$key])) {
$this->headers[$key] = $values;
} else {
$this->headers[$key] = array_merge($this->headers[$key], $values);
}
if ('cache-control' === $key) {
$this->cacheControl = $this->parseCacheControl($values[0]);
}
}
/**
* Returns true if the HTTP header is defined.
*
* @param string $key The HTTP header
*
* @return Boolean true if the parameter exists, false otherwise
*
* @api
*/
public function has($key)
{
return array_key_exists(strtr(strtolower($key), '_', '-'), $this->headers);
}
/**
* Returns true if the given HTTP header contains the given value.
*
* @param string $key The HTTP header name
* @param string $value The HTTP value
*
* @return Boolean true if the value is contained in the header, false otherwise
*
* @api
*/
public function contains($key, $value)
{
return in_array($value, $this->get($key, null, false));
}
/**
* Removes a header.
*
* @param string $key The HTTP header name
*
* @api
*/
public function remove($key)
{
$key = strtr(strtolower($key), '_', '-');
unset($this->headers[$key]);
if ('cache-control' === $key) {
$this->cacheControl = array();
}
}
/**
* Returns the HTTP header value converted to a date.
*
* @param string $key The parameter key
* @param \DateTime $default The default value
*
* @return \DateTime The filtered value
*
* @api
*/
public function getDate($key, \DateTime $default = null)
{
if (null === $value = $this->get($key)) {
return $default;
}
if (false === $date = \DateTime::createFromFormat(DATE_RFC2822, $value)) {
throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).', $key, $value));
}
return $date;
}
public function addCacheControlDirective($key, $value = true)
{
$this->cacheControl[$key] = $value;
$this->set('Cache-Control', $this->getCacheControlHeader());
}
public function hasCacheControlDirective($key)
{
return array_key_exists($key, $this->cacheControl);
}
public function getCacheControlDirective($key)
{
return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null;
}
public function removeCacheControlDirective($key)
{
unset($this->cacheControl[$key]);
$this->set('Cache-Control', $this->getCacheControlHeader());
}
/**
* Returns an iterator for headers.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->headers);
}
/**
* Returns the number of headers.
*
* @return int The number of headers
*/
public function count()
{
return count($this->headers);
}
protected function getCacheControlHeader()
{
$parts = array();
ksort($this->cacheControl);
foreach ($this->cacheControl as $key => $value) {
if (true === $value) {
$parts[] = $key;
} else {
if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
$value = '"'.$value.'"';
}
$parts[] = "$key=$value";
}
}
return implode(', ', $parts);
}
/**
* Parses a Cache-Control HTTP header.
*
* @param string $header The value of the Cache-Control HTTP header
*
* @return array An array representing the attribute values
*/
protected function parseCacheControl($header)
{
$cacheControl = array();
preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$cacheControl[strtolower($match[1])] = isset($match[2]) && $match[2] ? $match[2] : (isset($match[3]) ? $match[3] : true);
}
return $cacheControl;
}
}

View File

@@ -0,0 +1,113 @@
<?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;
/**
* Response represents an HTTP response in JSON format.
*
* @author Igor Wiedler <igor@wiedler.ch>
*/
class JsonResponse extends Response
{
protected $data;
protected $callback;
/**
* Constructor.
*
* @param mixed $data The response data
* @param integer $status The response status code
* @param array $headers An array of response headers
*/
public function __construct($data = array(), $status = 200, $headers = array())
{
parent::__construct('', $status, $headers);
$this->setData($data);
}
/**
* {@inheritDoc}
*/
public static function create($data = array(), $status = 200, $headers = array())
{
return new static($data, $status, $headers);
}
/**
* Sets the JSONP callback.
*
* @param string $callback
*
* @return JsonResponse
*/
public function setCallback($callback = null)
{
if (null !== $callback) {
// taken from http://www.geekality.net/2011/08/03/valid-javascript-identifier/
$pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*+$/u';
$parts = explode('.', $callback);
foreach ($parts as $part) {
if (!preg_match($pattern, $part)) {
throw new \InvalidArgumentException('The callback name is not valid.');
}
}
}
$this->callback = $callback;
return $this->update();
}
/**
* Sets the data to be sent as json.
*
* @param mixed $data
*
* @return JsonResponse
*/
public function setData($data = array())
{
// root should be JSON object, not array
if (is_array($data) && 0 === count($data)) {
$data = new \ArrayObject();
}
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
return $this->update();
}
/**
* Updates the content and headers according to the json data and callback.
*
* @return JsonResponse
*/
protected function update()
{
if (null !== $this->callback) {
// Not using application/javascript for compatibility reasons with older browsers.
$this->headers->set('Content-Type', 'text/javascript');
return $this->setContent(sprintf('%s(%s);', $this->callback, $this->data));
}
// Only set the header when there is none or when it equals 'text/javascript' (from a previous update with callback)
// in order to not overwrite a custom definition.
if (!$this->headers->has('Content-Type') || 'text/javascript' === $this->headers->get('Content-Type')) {
$this->headers->set('Content-Type', 'application/json');
}
return $this->setContent($this->data);
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-2012 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,303 @@
<?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;
/**
* ParameterBag is a container for key/value pairs.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ParameterBag implements \IteratorAggregate, \Countable
{
/**
* Parameter storage.
*
* @var array
*/
protected $parameters;
/**
* Constructor.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function __construct(array $parameters = array())
{
$this->parameters = $parameters;
}
/**
* Returns the parameters.
*
* @return array An array of parameters
*
* @api
*/
public function all()
{
return $this->parameters;
}
/**
* Returns the parameter keys.
*
* @return array An array of parameter keys
*
* @api
*/
public function keys()
{
return array_keys($this->parameters);
}
/**
* Replaces the current parameters by a new set.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function replace(array $parameters = array())
{
$this->parameters = $parameters;
}
/**
* Adds parameters.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function add(array $parameters = array())
{
$this->parameters = array_replace($this->parameters, $parameters);
}
/**
* Returns a parameter by name.
*
* @param string $path The key
* @param mixed $default The default value if the parameter key does not exist
* @param boolean $deep If true, a path like foo[bar] will find deeper items
*
* @return mixed
*
* @api
*/
public function get($path, $default = null, $deep = false)
{
if (!$deep || false === $pos = strpos($path, '[')) {
return array_key_exists($path, $this->parameters) ? $this->parameters[$path] : $default;
}
$root = substr($path, 0, $pos);
if (!array_key_exists($root, $this->parameters)) {
return $default;
}
$value = $this->parameters[$root];
$currentKey = null;
for ($i = $pos, $c = strlen($path); $i < $c; $i++) {
$char = $path[$i];
if ('[' === $char) {
if (null !== $currentKey) {
throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "[" at position %d.', $i));
}
$currentKey = '';
} elseif (']' === $char) {
if (null === $currentKey) {
throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "]" at position %d.', $i));
}
if (!is_array($value) || !array_key_exists($currentKey, $value)) {
return $default;
}
$value = $value[$currentKey];
$currentKey = null;
} else {
if (null === $currentKey) {
throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "%s" at position %d.', $char, $i));
}
$currentKey .= $char;
}
}
if (null !== $currentKey) {
throw new \InvalidArgumentException(sprintf('Malformed path. Path must end with "]".'));
}
return $value;
}
/**
* Sets a parameter by name.
*
* @param string $key The key
* @param mixed $value The value
*
* @api
*/
public function set($key, $value)
{
$this->parameters[$key] = $value;
}
/**
* Returns true if the parameter is defined.
*
* @param string $key The key
*
* @return Boolean true if the parameter exists, false otherwise
*
* @api
*/
public function has($key)
{
return array_key_exists($key, $this->parameters);
}
/**
* Removes a parameter.
*
* @param string $key The key
*
* @api
*/
public function remove($key)
{
unset($this->parameters[$key]);
}
/**
* Returns the alphabetic characters of the parameter value.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter key does not exist
* @param boolean $deep If true, a path like foo[bar] will find deeper items
*
* @return string The filtered value
*
* @api
*/
public function getAlpha($key, $default = '', $deep = false)
{
return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default, $deep));
}
/**
* Returns the alphabetic characters and digits of the parameter value.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter key does not exist
* @param boolean $deep If true, a path like foo[bar] will find deeper items
*
* @return string The filtered value
*
* @api
*/
public function getAlnum($key, $default = '', $deep = false)
{
return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default, $deep));
}
/**
* Returns the digits of the parameter value.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter key does not exist
* @param boolean $deep If true, a path like foo[bar] will find deeper items
*
* @return string The filtered value
*
* @api
*/
public function getDigits($key, $default = '', $deep = false)
{
// we need to remove - and + because they're allowed in the filter
return str_replace(array('-', '+'), '', $this->filter($key, $default, $deep, FILTER_SANITIZE_NUMBER_INT));
}
/**
* Returns the parameter value converted to integer.
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter key does not exist
* @param boolean $deep If true, a path like foo[bar] will find deeper items
*
* @return integer The filtered value
*
* @api
*/
public function getInt($key, $default = 0, $deep = false)
{
return (int) $this->get($key, $default, $deep);
}
/**
* Filter key.
*
* @param string $key Key.
* @param mixed $default Default = null.
* @param boolean $deep Default = false.
* @param integer $filter FILTER_* constant.
* @param mixed $options Filter options.
*
* @see http://php.net/manual/en/function.filter-var.php
*
* @return mixed
*/
public function filter($key, $default = null, $deep = false, $filter=FILTER_DEFAULT, $options=array())
{
$value = $this->get($key, $default, $deep);
// Always turn $options into an array - this allows filter_var option shortcuts.
if (!is_array($options) && $options) {
$options = array('flags' => $options);
}
// Add a convenience check for arrays.
if (is_array($value) && !isset($options['flags'])) {
$options['flags'] = FILTER_REQUIRE_ARRAY;
}
return filter_var($value, $filter, $options);
}
/**
* Returns an iterator for parameters.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->parameters);
}
/**
* Returns the number of parameters.
*
* @return int The number of parameters
*/
public function count()
{
return count($this->parameters);
}
}

View File

@@ -0,0 +1,46 @@
HttpFoundation Component
========================
HttpFoundation defines an object-oriented layer for the HTTP specification.
It provides an abstraction for requests, responses, uploaded files, cookies,
sessions, ...
In this example, we get a Request object from the current PHP global
variables:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
echo $request->getPathInfo();
You can also create a Request directly -- that's interesting for unit testing:
$request = Request::create('/?foo=bar', 'GET');
echo $request->getPathInfo();
And here is how to create and send a Response:
$response = new Response('Not Found', 404, array('Content-Type' => 'text/plain'));
$response->send();
The Request and the Response classes have many other methods that implement
the HTTP specification.
Loading
-------
If you are using PHP 5.3.x you must add the following to your autoloader:
// SessionHandlerInterface
if (!interface_exists('SessionHandlerInterface')) {
$loader->registerPrefixFallback(__DIR__.'/../vendor/symfony/src/Symfony/Component/HttpFoundation/Resources/stubs');
}
Resources
---------
You can run the unit tests with the following command:
phpunit

View File

@@ -0,0 +1,102 @@
<?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;
/**
* RedirectResponse represents an HTTP response doing a redirect.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class RedirectResponse extends Response
{
protected $targetUrl;
/**
* Creates a redirect response so that it conforms to the rules defined for a redirect status code.
*
* @param string $url The URL to redirect to
* @param integer $status The status code (302 by default)
* @param array $headers The headers (Location is always set to the given url)
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3
*
* @api
*/
public function __construct($url, $status = 302, $headers = array())
{
if (empty($url)) {
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
}
parent::__construct('', $status, $headers);
$this->setTargetUrl($url);
if (!$this->isRedirect()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status));
}
}
/**
* {@inheritDoc}
*/
public static function create($url = '', $status = 302, $headers = array())
{
return new static($url, $status, $headers);
}
/**
* Returns the target URL.
*
* @return string target URL
*/
public function getTargetUrl()
{
return $this->targetUrl;
}
/**
* Sets the redirect target of this response.
*
* @param string $url The URL to redirect to
*
* @return RedirectResponse The current response.
*/
public function setTargetUrl($url)
{
if (empty($url)) {
throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
}
$this->targetUrl = $url;
$this->setContent(
sprintf('<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="1;url=%1$s" />
<title>Redirecting to %1$s</title>
</head>
<body>
Redirecting to <a href="%1$s">%1$s</a>.
</body>
</html>', htmlspecialchars($url, ENT_QUOTES, 'UTF-8')));
$this->headers->set('Location', $url);
return $this;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
<?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;
/**
* RequestMatcher compares a pre-defined set of checks against a Request instance.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class RequestMatcher implements RequestMatcherInterface
{
/**
* @var string
*/
private $path;
/**
* @var string
*/
private $host;
/**
* @var array
*/
private $methods;
/**
* @var string
*/
private $ip;
/**
* Attributes.
*
* @var array
*/
private $attributes;
public function __construct($path = null, $host = null, $methods = null, $ip = null, array $attributes = array())
{
$this->path = $path;
$this->host = $host;
$this->methods = $methods;
$this->ip = $ip;
$this->attributes = $attributes;
}
/**
* Adds a check for the URL host name.
*
* @param string $regexp A Regexp
*/
public function matchHost($regexp)
{
$this->host = $regexp;
}
/**
* Adds a check for the URL path info.
*
* @param string $regexp A Regexp
*/
public function matchPath($regexp)
{
$this->path = $regexp;
}
/**
* Adds a check for the client IP.
*
* @param string $ip A specific IP address or a range specified using IP/netmask like 192.168.1.0/24
*/
public function matchIp($ip)
{
$this->ip = $ip;
}
/**
* Adds a check for the HTTP method.
*
* @param string|array $method An HTTP method or an array of HTTP methods
*/
public function matchMethod($method)
{
$this->methods = array_map('strtoupper', is_array($method) ? $method : array($method));
}
/**
* Adds a check for request attribute.
*
* @param string $key The request attribute name
* @param string $regexp A Regexp
*/
public function matchAttribute($key, $regexp)
{
$this->attributes[$key] = $regexp;
}
/**
* {@inheritdoc}
*
* @api
*/
public function matches(Request $request)
{
if (null !== $this->methods && !in_array($request->getMethod(), $this->methods)) {
return false;
}
foreach ($this->attributes as $key => $pattern) {
if (!preg_match('#'.str_replace('#', '\\#', $pattern).'#', $request->attributes->get($key))) {
return false;
}
}
if (null !== $this->path) {
$path = str_replace('#', '\\#', $this->path);
if (!preg_match('#'.$path.'#', rawurldecode($request->getPathInfo()))) {
return false;
}
}
if (null !== $this->host && !preg_match('#'.str_replace('#', '\\#', $this->host).'#', $request->getHost())) {
return false;
}
if (null !== $this->ip && !$this->checkIp($request->getClientIp(), $this->ip)) {
return false;
}
return true;
}
/**
* Validates an IP address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp($requestIp, $ip)
{
// IPv6 address
if (false !== strpos($requestIp, ':')) {
return $this->checkIp6($requestIp, $ip);
} else {
return $this->checkIp4($requestIp, $ip);
}
}
/**
* Validates an IPv4 address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp4($requestIp, $ip)
{
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 32) {
return false;
}
} else {
$address = $ip;
$netmask = 32;
}
return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
}
/**
* Validates an IPv6 address.
*
* @author David Soria Parra <dsp at php dot net>
* @see https://github.com/dsp/v6tools
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp6($requestIp, $ip)
{
if (!defined('AF_INET6')) {
throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
}
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 128) {
return false;
}
} else {
$address = $ip;
$netmask = 128;
}
$bytesAddr = unpack("n*", inet_pton($address));
$bytesTest = unpack("n*", inet_pton($requestIp));
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
$left = $netmask - 16 * ($i-1);
$left = ($left <= 16) ? $left : 16;
$mask = ~(0xffff >> $left) & 0xffff;
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,33 @@
<?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;
/**
* RequestMatcherInterface is an interface for strategies to match a Request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface RequestMatcherInterface
{
/**
* Decides whether the rule(s) implemented by the strategy matches the supplied request.
*
* @param Request $request The request to check for a match
*
* @return Boolean true if the request matches, false otherwise
*
* @api
*/
public function matches(Request $request);
}

View File

@@ -0,0 +1,98 @@
<?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.
*/
/**
* SessionHandlerInterface
*
* Provides forward compatibility with PHP 5.4
*
* Extensive documentation can be found at php.net, see links:
*
* @see http://php.net/sessionhandlerinterface
* @see http://php.net/session.customhandler
* @see http://php.net/session-set-save-handler
*
* @author Drak <drak@zikula.org>
*/
interface SessionHandlerInterface
{
/**
* Open session.
*
* @see http://php.net/sessionhandlerinterface.open
*
* @param string $savePath Save path.
* @param string $sessionName Session Name.
*
* @throws \RuntimeException If something goes wrong starting the session.
*
* @return boolean
*/
public function open($savePath, $sessionName);
/**
* Close session.
*
* @see http://php.net/sessionhandlerinterface.close
*
* @return boolean
*/
public function close();
/**
* Read session.
*
* @see http://php.net/sessionhandlerinterface.read
*
* @throws \RuntimeException On fatal error but not "record not found".
*
* @return string String as stored in persistent storage or empty string in all other cases.
*/
public function read($sessionId);
/**
* Commit session to storage.
*
* @see http://php.net/sessionhandlerinterface.write
*
* @param string $sessionId Session ID.
* @param string $data Session serialized data to save.
*
* @return boolean
*/
public function write($sessionId, $data);
/**
* Destroys this session.
*
* @see http://php.net/sessionhandlerinterface.destroy
*
* @param string $sessionId Session ID.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
public function destroy($sessionId);
/**
* Garbage collection for storage.
*
* @see http://php.net/sessionhandlerinterface.gc
*
* @param integer $lifetime Max lifetime in seconds to keep sessions stored.
*
* @throws \RuntimeException On fatal error.
*
* @return boolean
*/
public function gc($lifetime);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,293 @@
<?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;
/**
* ResponseHeaderBag is a container for Response HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ResponseHeaderBag extends HeaderBag
{
const COOKIES_FLAT = 'flat';
const COOKIES_ARRAY = 'array';
const DISPOSITION_ATTACHMENT = 'attachment';
const DISPOSITION_INLINE = 'inline';
/**
* @var array
*/
protected $computedCacheControl = array();
/**
* @var array
*/
protected $cookies = array();
/**
* Constructor.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function __construct(array $headers = array())
{
parent::__construct($headers);
if (!isset($this->headers['cache-control'])) {
$this->set('cache-control', '');
}
}
/**
* {@inheritdoc}
*/
public function __toString()
{
$cookies = '';
foreach ($this->getCookies() as $cookie) {
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
}
return parent::__toString().$cookies;
}
/**
* {@inheritdoc}
*
* @api
*/
public function replace(array $headers = array())
{
parent::replace($headers);
if (!isset($this->headers['cache-control'])) {
$this->set('cache-control', '');
}
}
/**
* {@inheritdoc}
*
* @api
*/
public function set($key, $values, $replace = true)
{
parent::set($key, $values, $replace);
// ensure the cache-control header has sensible defaults
if (in_array(strtr(strtolower($key), '_', '-'), array('cache-control', 'etag', 'last-modified', 'expires'))) {
$computed = $this->computeCacheControlValue();
$this->headers['cache-control'] = array($computed);
$this->computedCacheControl = $this->parseCacheControl($computed);
}
}
/**
* {@inheritdoc}
*
* @api
*/
public function remove($key)
{
parent::remove($key);
if ('cache-control' === strtr(strtolower($key), '_', '-')) {
$this->computedCacheControl = array();
}
}
/**
* {@inheritdoc}
*/
public function hasCacheControlDirective($key)
{
return array_key_exists($key, $this->computedCacheControl);
}
/**
* {@inheritdoc}
*/
public function getCacheControlDirective($key)
{
return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
}
/**
* Sets a cookie.
*
* @param Cookie $cookie
*
* @api
*/
public function setCookie(Cookie $cookie)
{
$this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
}
/**
* Removes a cookie from the array, but does not unset it in the browser
*
* @param string $name
* @param string $path
* @param string $domain
*
* @api
*/
public function removeCookie($name, $path = '/', $domain = null)
{
if (null === $path) {
$path = '/';
}
unset($this->cookies[$domain][$path][$name]);
if (empty($this->cookies[$domain][$path])) {
unset($this->cookies[$domain][$path]);
if (empty($this->cookies[$domain])) {
unset($this->cookies[$domain]);
}
}
}
/**
* Returns an array with all cookies
*
* @param string $format
*
* @throws \InvalidArgumentException When the $format is invalid
*
* @return array
*
* @api
*/
public function getCookies($format = self::COOKIES_FLAT)
{
if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
}
if (self::COOKIES_ARRAY === $format) {
return $this->cookies;
}
$flattenedCookies = array();
foreach ($this->cookies as $path) {
foreach ($path as $cookies) {
foreach ($cookies as $cookie) {
$flattenedCookies[] = $cookie;
}
}
}
return $flattenedCookies;
}
/**
* Clears a cookie in the browser
*
* @param string $name
* @param string $path
* @param string $domain
*
* @api
*/
public function clearCookie($name, $path = '/', $domain = null)
{
$this->setCookie(new Cookie($name, null, 1, $path, $domain));
}
/**
* Generates a HTTP Content-Disposition field-value.
*
* @param string $disposition One of "inline" or "attachment"
* @param string $filename A unicode string
* @param string $filenameFallback A string containing only ASCII characters that
* is semantically equivalent to $filename. If the filename is already ASCII,
* it can be omitted, or just copied from $filename
*
* @return string A string suitable for use as a Content-Disposition field-value.
*
* @throws \InvalidArgumentException
* @see RFC 6266
*/
public function makeDisposition($disposition, $filename, $filenameFallback = '')
{
if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
}
if ('' == $filenameFallback) {
$filenameFallback = $filename;
}
// filenameFallback is not ASCII.
if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
}
// percent characters aren't safe in fallback.
if (false !== strpos($filenameFallback, '%')) {
throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
}
// path separators aren't allowed in either.
if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) {
throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
}
$output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
if ($filename !== $filenameFallback) {
$output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
}
return $output;
}
/**
* Returns the calculated value of the cache-control header.
*
* This considers several other headers and calculates or modifies the
* cache-control header to a sensible, conservative value.
*
* @return string
*/
protected function computeCacheControlValue()
{
if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) {
return 'no-cache';
}
if (!$this->cacheControl) {
// conservative by default
return 'private, must-revalidate';
}
$header = $this->getCacheControlHeader();
if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
return $header;
}
// public if s-maxage is defined, private otherwise
if (!isset($this->cacheControl['s-maxage'])) {
return $header.', private';
}
return $header;
}
}

View File

@@ -0,0 +1,82 @@
<?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;
/**
* ServerBag is a container for HTTP headers from the $_SERVER variable.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Robert Kiss <kepten@gmail.com>
*/
class ServerBag extends ParameterBag
{
/**
* Gets the HTTP headers.
*
* @return string
*/
public function getHeaders()
{
$headers = array();
foreach ($this->parameters as $key => $value) {
if (0 === strpos($key, 'HTTP_')) {
$headers[substr($key, 5)] = $value;
}
// CONTENT_* are not prefixed with HTTP_
elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) {
$headers[$key] = $value;
}
}
if (isset($this->parameters['PHP_AUTH_USER'])) {
$headers['PHP_AUTH_USER'] = $this->parameters['PHP_AUTH_USER'];
$headers['PHP_AUTH_PW'] = isset($this->parameters['PHP_AUTH_PW']) ? $this->parameters['PHP_AUTH_PW'] : '';
} else {
/*
* php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
* For this workaround to work, add these lines to your .htaccess file:
* RewriteCond %{HTTP:Authorization} ^(.+)$
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
*
* A sample .htaccess file:
* RewriteEngine On
* RewriteCond %{HTTP:Authorization} ^(.+)$
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
* RewriteCond %{REQUEST_FILENAME} !-f
* RewriteRule ^(.*)$ app.php [QSA,L]
*/
$authorizationHeader = null;
if (isset($this->parameters['HTTP_AUTHORIZATION'])) {
$authorizationHeader = $this->parameters['HTTP_AUTHORIZATION'];
} elseif (isset($this->parameters['REDIRECT_HTTP_AUTHORIZATION'])) {
$authorizationHeader = $this->parameters['REDIRECT_HTTP_AUTHORIZATION'];
}
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
if ((null !== $authorizationHeader) && (0 === stripos($authorizationHeader, 'basic'))) {
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)));
if (count($exploded) == 2) {
list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
}
}
}
// PHP_AUTH_USER/PHP_AUTH_PW
if (isset($headers['PHP_AUTH_USER'])) {
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']);
}
return $headers;
}
}

View File

@@ -0,0 +1,157 @@
<?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, \IteratorAggregate, \Countable
{
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;
}
/**
* Returns an iterator for attributes.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->attributes);
}
/**
* Returns the number of attributes.
*
* @return int The number of attributes
*/
public function count()
{
return count($this->attributes);
}
}

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
*/
public function has($name);
/**
* Returns an attribute.
*
* @param string $name The attribute name
* @param mixed $default The default value if not found.
*
* @return mixed
*/
public function get($name, $default = null);
/**
* Sets an attribute.
*
* @param string $name
* @param mixed $value
*/
public function set($name, $value);
/**
* Returns attributes.
*
* @return array Attributes
*/
public function all();
/**
* Sets attributes.
*
* @param array $attributes Attributes
*/
public function replace(array $attributes);
/**
* Removes an attribute.
*
* @param string $name
*
* @return mixed The removed value
*/
public 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,176 @@
<?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 add($type, $message)
{
$this->flashes['new'][$type][] = $message;
}
/**
* {@inheritdoc}
*/
public function peek($type, array $default = array())
{
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, array $default = array())
{
$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, $messages)
{
$this->flashes['new'][$type] = (array) $messages;
}
/**
* {@inheritdoc}
*/
public function has($type)
{
return array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type];
}
/**
* {@inheritdoc}
*/
public function keys()
{
return array_keys($this->flashes['display']);
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->all();
}
}

View File

@@ -0,0 +1,186 @@
<?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, \IteratorAggregate, \Countable
{
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 add($type, $message)
{
$this->flashes[$type][] = $message;
}
/**
* {@inheritdoc}
*/
public function peek($type, array $default =array())
{
return $this->has($type) ? $this->flashes[$type] : $default;
}
/**
* {@inheritdoc}
*/
public function peekAll()
{
return $this->flashes;
}
/**
* {@inheritdoc}
*/
public function get($type, array $default = array())
{
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, $messages)
{
$this->flashes[$type] = (array) $messages;
}
/**
* {@inheritdoc}
*/
public function setAll(array $messages)
{
$this->flashes = $messages;
}
/**
* {@inheritdoc}
*/
public function has($type)
{
return array_key_exists($type, $this->flashes) && $this->flashes[$type];
}
/**
* {@inheritdoc}
*/
public function keys()
{
return array_keys($this->flashes);
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->all();
}
/**
* Returns an iterator for flashes.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->all());
}
/**
* Returns the number of flashes.
*
* @return int The number of flashes
*/
public function count()
{
return count($this->flashes);
}
}

View File

@@ -0,0 +1,93 @@
<?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
{
/**
* Adds a flash message for type.
*
* @param string $type
* @param string $message
*/
public function add($type, $message);
/**
* Registers a message for a given type.
*
* @param string $type
* @param string $message
*/
public function set($type, $message);
/**
* Gets flash message for a given type.
*
* @param string $type Message category type.
* @param array $default Default value if $type doee not exist.
*
* @return string
*/
public function peek($type, array $default = array());
/**
* Gets all flash messages.
*
* @return array
*/
public function peekAll();
/**
* Gets and clears flash from the stack.
*
* @param string $type
* @param array $default Default value if $type doee not exist.
*
* @return string
*/
public function get($type, array $default = array());
/**
* Gets and clears flashes from the stack.
*
* @return array
*/
public function all();
/**
* Sets all flash messages.
*/
public function setAll(array $messages);
/**
* Has flash messages for a given type?
*
* @param string $type
*
* @return boolean
*/
public function has($type);
/**
* Returns a list of all defined types.
*
* @return array
*/
public function keys();
}

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;
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, \IteratorAggregate, \Countable
{
/**
* 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();
$attributes = $attributes ?: new AttributeBag();
$this->attributeName = $attributes->getName();
$this->registerBag($attributes);
$flashes = $flashes ?: new FlashBag();
$this->flashName = $flashes->getName();
$this->registerBag($flashes);
}
/**
* {@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 isStarted()
{
return $this->storage->isStarted();
}
/**
* Returns an iterator for attributes.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->storage->getBag($this->attributeName)->all());
}
/**
* Returns the number of attributes.
*
* @return int The number of attributes
*/
public function count()
{
return count($this->storage->getBag($this->attributeName)->all());
}
/**
* {@inheritdoc}
*/
public function invalidate($lifetime = null)
{
$this->storage->clear();
return $this->migrate(true, $lifetime);
}
/**
* {@inheritdoc}
*/
public function migrate($destroy = false, $lifetime = null)
{
return $this->storage->regenerate($destroy, $lifetime);
}
/**
* {@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);
}
/**
* {@inheritdoc}
*/
public function getMetadataBag()
{
return $this->storage->getMetadataBag();
}
/**
* {@inheritdoc}
*/
public function registerBag(SessionBagInterface $bag)
{
$this->storage->registerBag($bag);
}
/**
* {@inheritdoc}
*/
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()
{
$all = $this->getBag($this->flashName)->all();
$return = array();
if ($all) {
foreach ($all as $name => $array) {
if (is_numeric(key($array))) {
$return[$name] = reset($array);
} else {
$return[$name] = $array;
}
}
}
return $return;
}
/**
* @param array $values
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function setFlashes($values)
{
foreach ($values as $name => $value) {
$this->getBag($this->flashName)->set($name, $value);
}
}
/**
* @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($this->flashName)->get($name);
return empty($return) ? $default : reset($return);
}
/**
* @param string $name
* @param string $value
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function setFlash($name, $value)
{
$this->getBag($this->flashName)->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($this->flashName)->has($name);
}
/**
* @param string $name
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function removeFlash($name)
{
$this->getBag($this->flashName)->get($name);
}
/**
* @return array
*
* @deprecated since 2.1, will be removed from 2.3
*/
public function clearFlashes()
{
return $this->getBag($this->flashName)->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
*/
public function getName();
/**
* Initializes the Bag
*
* @param array $array
*/
public function initialize(array &$array);
/**
* Gets the storage key for this bag.
*
* @return string
*/
public function getStorageKey();
/**
* Clears out data from bag.
*
* @return mixed Whatever data was contained.
*/
public function clear();
}

View File

@@ -0,0 +1,208 @@
<?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\MetadataBag;
/**
* 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
*/
public function start();
/**
* Returns the session ID.
*
* @return string The session ID.
*
* @api
*/
public function getId();
/**
* Sets the session ID
*
* @param string $id
*
* @api
*/
public function setId($id);
/**
* Returns the session name.
*
* @return mixed The session name.
*
* @api
*/
public function getName();
/**
* Sets the session name.
*
* @param string $name
*
* @api
*/
public function setName($name);
/**
* Invalidates the current session.
*
* Clears all session attributes and flashes and regenerates the
* session and deletes the old session from persistence.
*
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return Boolean True if session invalidated, false if error.
*
* @api
*/
public function invalidate($lifetime = null);
/**
* 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.
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return Boolean True if session migrated, false if error.
*
* @api
*/
public function migrate($destroy = false, $lifetime = null);
/**
* 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.
*/
public 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
*/
public function has($name);
/**
* Returns an attribute.
*
* @param string $name The attribute name
* @param mixed $default The default value if not found.
*
* @return mixed
*
* @api
*/
public function get($name, $default = null);
/**
* Sets an attribute.
*
* @param string $name
* @param mixed $value
*
* @api
*/
public function set($name, $value);
/**
* Returns attributes.
*
* @return array Attributes
*
* @api
*/
public function all();
/**
* Sets attributes.
*
* @param array $attributes Attributes
*/
public function replace(array $attributes);
/**
* Removes an attribute.
*
* @param string $name
*
* @return mixed The removed value
*
* @api
*/
public function remove($name);
/**
* Clears all attributes.
*
* @api
*/
public function clear();
/**
* Checks if the session was started.
*
* @return Boolean
*/
public function isStarted();
/**
* Registers a SessionBagInterface with the session.
*
* @param SessionBagInterface $bag
*/
public function registerBag(SessionBagInterface $bag);
/**
* Gets a bag instance by name.
*
* @param string $name
*
* @return SessionBagInterface
*/
public function getBag($name);
/**
* Gets session meta.
*
* @return MetadataBag
*/
public function getMetadataBag();
}

View File

@@ -0,0 +1,109 @@
<?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
{
/**
* @var \Memcache Memcache driver.
*/
private $memcache;
/**
* @var integer Time to live in seconds
*/
private $ttl;
/**
* @var string Key prefix for shared environments.
*/
private $prefix;
/**
* Constructor.
*
* List of available options:
* * prefix: The prefix to use for the memcache keys in order to avoid collision
* * expiretime: The time to live in seconds
*
* @param \Memcache $memcache A \Memcache instance
* @param array $options An associative array of Memcache options
*
* @throws \InvalidArgumentException When unsupported options are passed
*/
public function __construct(\Memcache $memcache, array $options = array())
{
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
throw new \InvalidArgumentException(sprintf(
'The following options are not supported "%s"', implode(', ', $diff)
));
}
$this->memcache = $memcache;
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
}
/**
* {@inheritDoc}
*/
public function open($savePath, $sessionName)
{
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, time() + $this->ttl);
}
/**
* {@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,115 @@
<?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
{
/**
* @var \Memcached Memcached driver.
*/
private $memcached;
/**
* @var integer Time to live in seconds
*/
private $ttl;
/**
* @var string Key prefix for shared environments.
*/
private $prefix;
/**
* Constructor.
*
* List of available options:
* * prefix: The prefix to use for the memcached keys in order to avoid collision
* * expiretime: The time to live in seconds
*
* @param \Memcached $memcached A \Memcached instance
* @param array $options An associative array of Memcached options
*
* @throws \InvalidArgumentException When unsupported options are passed
*/
public function __construct(\Memcached $memcached, array $options = array())
{
$this->memcached = $memcached;
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
throw new \InvalidArgumentException(sprintf(
'The following options are not supported "%s"', implode(', ', $diff)
));
}
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
}
/**
* {@inheritDoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritDoc}
*/
public function close()
{
return true;
}
/**
* {@inheritDoc}
*/
public function read($sessionId)
{
return $this->memcached->get($this->prefix.$sessionId) ?: '';
}
/**
* {@inheritDoc}
*/
public function write($sessionId, $data)
{
return $this->memcached->set($this->prefix.$sessionId, $data, time() + $this->ttl);
}
/**
* {@inheritDoc}
*/
public function destroy($sessionId)
{
return $this->memcached->delete($this->prefix.$sessionId);
}
/**
* {@inheritDoc}
*/
public function gc($lifetime)
{
// not required here because memcached will auto expire the records anyhow.
return true;
}
}

View File

@@ -0,0 +1,145 @@
<?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;
/**
* MongoDB session handler
*
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class MongoDbSessionHandler implements \SessionHandlerInterface
{
/**
* @var \Mongo
*/
private $mongo;
/**
* @var \MongoCollection
*/
private $collection;
/**
* @var array
*/
private $options;
/**
* Constructor.
*
* @param \Mongo $mongo A "Mongo" instance
* @param array $options An associative array of field options
*
* @throws \InvalidArgumentException When "database" or "collection" not provided
*/
public function __construct(\Mongo $mongo, array $options)
{
if (!isset($options['database']) || !isset($options['collection'])) {
throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler');
}
$this->mongo = $mongo;
$this->options = array_merge(array(
'id_field' => 'sess_id',
'data_field' => 'sess_data',
'time_field' => 'sess_time',
), $options);
}
/**
* {@inheritDoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritDoc}
*/
public function close()
{
return true;
}
/**
* {@inheritDoc}
*/
public function destroy($sessionId)
{
$this->getCollection()->remove(
array($this->options['id_field'] => $sessionId),
array('justOne' => true)
);
return true;
}
/**
* {@inheritDoc}
*/
public function gc($lifetime)
{
$time = new \MongoTimestamp(time() - $lifetime);
$this->getCollection()->remove(array(
$this->options['time_field'] => array('$lt' => $time),
));
}
/**
* {@inheritDoc]
*/
public function write($sessionId, $data)
{
$data = array(
$this->options['id_field'] => $sessionId,
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
$this->options['time_field'] => new \MongoTimestamp()
);
$this->getCollection()->update(
array($this->options['id_field'] => $sessionId),
array('$set' => $data),
array('upsert' => true)
);
return true;
}
/**
* {@inheritDoc}
*/
public function read($sessionId)
{
$dbData = $this->getCollection()->findOne(array(
$this->options['id_field'] => $sessionId,
));
return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin;
}
/**
* Return a "MongoCollection" instance
*
* @return \MongoCollection
*/
private function getCollection()
{
if (null === $this->collection) {
$this->collection = $this->mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']);
}
return $this->collection;
}
}

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;
/**
* 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.
* '/path', 'N;/path', or 'N;octal-mode;/path
*
* @see http://php.net/session.configuration.php#ini.session.save-path for further details.
*
* @throws \InvalidArgumentException On invalid $savePath
*/
public function __construct($savePath = null)
{
if (null === $savePath) {
$savePath = ini_get('session.save_path');
}
$baseDir = $savePath;
if ($count = substr_count($savePath, ';')) {
if ($count > 2) {
throw new \InvalidArgumentException(sprintf('Invalid argument $savePath \'%s\'', $savePath));
}
// characters after last ';' are the path
$baseDir = ltrim(strrchr($savePath, ';'), ';');
}
if ($baseDir && !is_dir($baseDir)) {
mkdir($baseDir, 0777, true);
}
ini_set('session.save_path', $savePath);
ini_set('session.save_handler', 'files');
}
}

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,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 situations 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,231 @@
<?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
{
/**
* @var \PDO PDO instance.
*/
private $pdo;
/**
* @var array Database options.
*/
private $dbOptions;
/**
* Constructor.
*
* List of available options:
* * db_table: The name of the table [required]
* * db_id_col: The column where to store the session id [default: sess_id]
* * db_data_col: The column where to store the session data [default: sess_data]
* * db_time_col: The column where to store the timestamp [default: sess_time]
*
* @param \PDO $pdo A \PDO instance
* @param array $dbOptions An associative array of DB options
*
* @throws \InvalidArgumentException When "db_table" option is not provided
*/
public function __construct(\PDO $pdo, array $dbOptions = 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";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':time', time() - $lifetime, \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'];
//session data can contain non binary safe characters so we need to encode it
$encoded = base64_encode($data);
try {
if ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
// MySQL would report $stmt->rowCount() = 0 on UPDATE when the data is left unchanged
// it could result in calling createNewSession() whereas the session already exists in
// the DB which would fail as the id is unique
$stmt = $this->pdo->prepare(
"INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) " .
"ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = VALUES($dbTimeCol)"
);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
} else {
$stmt = $this->pdo->prepare("UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id");
$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,160 @@
<?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;
/**
* Metadata container.
*
* Adds metadata to the session.
*
* @author Drak <drak@zikula.org>
*/
class MetadataBag implements SessionBagInterface
{
const CREATED = 'c';
const UPDATED = 'u';
const LIFETIME = 'l';
/**
* @var string
*/
private $name = '__metadata';
/**
* @var string
*/
private $storageKey;
/**
* @var array
*/
protected $meta = array();
/**
* Unix timestamp.
*
* @var integer
*/
private $lastUsed;
/**
* Constructor.
*
* @param string $storageKey The key used to store bag in the session.
*/
public function __construct($storageKey = '_sf2_meta')
{
$this->storageKey = $storageKey;
$this->meta = array(self::CREATED => 0, self::UPDATED => 0, self::LIFETIME => 0);
}
/**
* {@inheritdoc}
*/
public function initialize(array &$array)
{
$this->meta = &$array;
if (isset($array[self::CREATED])) {
$this->lastUsed = $this->meta[self::UPDATED];
$this->meta[self::UPDATED] = time();
} else {
$this->stampCreated();
}
}
/**
* Gets the lifetime that the session cookie was set with.
*
* @return integer
*/
public function getLifetime()
{
return $this->meta[self::LIFETIME];
}
/**
* Stamps a new session's metadata.
*
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*/
public function stampNew($lifetime = null)
{
$this->stampCreated($lifetime);
}
/**
* {@inheritdoc}
*/
public function getStorageKey()
{
return $this->storageKey;
}
/**
* Gets the created timestamp metadata.
*
* @return integer Unix timestamp
*/
public function getCreated()
{
return $this->meta[self::CREATED];
}
/**
* Gets the last used metadata.
*
* @return integer Unix timestamp
*/
public function getLastUsed()
{
return $this->lastUsed;
}
/**
* {@inheritdoc}
*/
public function clear()
{
// nothing to do
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* Sets name.
*
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
private function stampCreated($lifetime = null)
{
$timeStamp = time();
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
$this->meta[self::LIFETIME] = (null === $lifetime) ? ini_get('session.cookie_lifetime') : $lifetime;
}
}

View File

@@ -0,0 +1,265 @@
<?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\MetadataBag;
/**
* 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();
/**
* @var MetadataBag
*/
protected $metadataBag;
/**
* @var array
*/
protected $bags;
/**
* Constructor.
*
* @param string $name Session name
* @param MetadataBag $metaBag MetadataBag instance.
*/
public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null)
{
$this->name = $name;
$this->setMetadataBag($metaBag);
}
/**
* 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, $lifetime = null)
{
if (!$this->started) {
$this->start();
}
$this->metadataBag->stampNew($lifetime);
$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];
}
/**
* {@inheritdoc}
*/
public function isStarted()
{
return $this->started;
}
/**
* Sets the MetadataBag.
*
* @param MetadataBag $bag
*/
public function setMetadataBag(MetadataBag $bag = null)
{
if (null === $bag) {
$bag = new MetadataBag();
}
$this->metadataBag = $bag;
}
/**
* Gets the MetadataBag.
*
* @return MetadataBag
*/
public function getMetadataBag()
{
return $this->metadataBag;
}
/**
* 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()
{
$bags = array_merge($this->bags, array($this->metadataBag));
foreach ($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,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;
/**
* 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;
/**
* @var array
*/
private $sessionData;
/**
* Constructor.
*
* @param string $savePath Path of directory to save session files.
* @param string $name Session name.
* @param MetadataBag $metaBag MetadataBag instance.
*/
public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null)
{
if (null === $savePath) {
$savePath = sys_get_temp_dir();
}
if (!is_dir($savePath)) {
mkdir($savePath, 0777, true);
}
$this->savePath = $savePath;
parent::__construct($name, $metaBag);
}
/**
* {@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, $lifetime = null)
{
if (!$this->started) {
$this->start();
}
if ($destroy) {
$this->destroy();
}
return parent::regenerate($destroy, $lifetime);
}
/**
* {@inheritdoc}
*/
public function save()
{
file_put_contents($this->getFilePath(), serialize($this->data));
// this is needed for Silex, where the session object is re-used across requests
// in functional tests. In Symfony, the container is rebooted, so we don't have
// this issue
$this->started = false;
}
/**
* 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,400 @@
<?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\MetadataBag;
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;
/**
* @var MetadataBag
*/
protected $metadataBag;
/**
* 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", is not supported as it tells PHP to start a session before
* PHP starts to execute user-land code. Setting during runtime has no effect).
*
* 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.
* @param MetadataBag $metaBag MetadataBag.
*/
public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
{
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->setMetadataBag($metaBag);
$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)
{
$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, $lifetime = null)
{
if (null !== $lifetime) {
ini_set('session.cookie_lifetime', $lifetime);
}
if ($destroy) {
$this->metadataBag->stampNew();
}
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 ($this->saveHandler->isActive() && !$this->started) {
$this->loadSession();
} elseif (!$this->started) {
$this->start();
}
return $this->bags[$name];
}
/**
* Sets the MetadataBag.
*
* @param MetadataBag $metaBag
*/
public function setMetadataBag(MetadataBag $metaBag = null)
{
if (null === $metaBag) {
$metaBag = new MetadataBag();
}
$this->metadataBag = $metaBag;
}
/**
* Gets the MetadataBag.
*
* @return MetadataBag
*/
public function getMetadataBag()
{
return $this->metadataBag;
}
/**
* {@inheritdoc}
*/
public function isStarted()
{
return $this->started;
}
/**
* 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)
{
$validOptions = array_flip(array(
'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',
));
foreach ($options as $key => $value) {
if (isset($validOptions[$key])) {
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();
}
$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;
}
$bags = array_merge($this->bags, array($this->metadataBag));
foreach ($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 Boolean
*/
public function isWrapper()
{
return $this->wrapper;
}
/**
* Has a session started?
*
* @return Boolean
*/
public function isActive()
{
return $this->active;
}
/**
* Sets the active flag.
*
* @param Boolean $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 Boolean 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,143 @@
<?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\MetadataBag;
/**
* 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
*/
public function start();
/**
* Checks if the session is started.
*
* @return boolean True if started, false otherwise.
*/
public function isStarted();
/**
* Returns the session ID
*
* @return string The session ID or empty.
*
* @api
*/
public function getId();
/**
* Sets the session ID
*
* @param string $id
*
* @api
*/
public function setId($id);
/**
* Returns the session name
*
* @return mixed The session name.
*
* @api
*/
public function getName();
/**
* Sets the session name
*
* @param string $name
*
* @api
*/
public 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?
* @param integer $lifetime Sets the cookie lifetime for the session cookie. A null value
* will leave the system settings unchanged, 0 sets the cookie
* to expire with browser session. Time is in seconds, and is
* not a Unix timestamp.
*
* @return Boolean True if session regenerated, false if error
*
* @throws \RuntimeException If an error occurs while regenerating this storage
*
* @api
*/
public function regenerate($destroy = false, $lifetime = null);
/**
* 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.
*/
public function save();
/**
* Clear all session data in memory.
*/
public function clear();
/**
* Gets a SessionBagInterface by name.
*
* @param string $name
*
* @return SessionBagInterface
*
* @throws \InvalidArgumentException If the bag does not exist
*/
public function getBag($name);
/**
* Registers a SessionBagInterface for use.
*
* @param SessionBagInterface $bag
*/
public function registerBag(SessionBagInterface $bag);
/**
* @return MetadataBag
*/
public function getMetadataBag();
}

View File

@@ -0,0 +1,129 @@
<?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;
/**
* StreamedResponse represents a streamed HTTP response.
*
* A StreamedResponse uses a callback for its content.
*
* The callback should use the standard PHP functions like echo
* to stream the response back to the client. The flush() method
* can also be used if needed.
*
* @see flush()
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class StreamedResponse extends Response
{
protected $callback;
protected $streamed;
/**
* Constructor.
*
* @param mixed $callback A valid PHP callback
* @param integer $status The response status code
* @param array $headers An array of response headers
*
* @api
*/
public function __construct($callback = null, $status = 200, $headers = array())
{
parent::__construct(null, $status, $headers);
if (null !== $callback) {
$this->setCallback($callback);
}
$this->streamed = false;
}
/**
* {@inheritDoc}
*/
public static function create($callback = null, $status = 200, $headers = array())
{
return new static($callback, $status, $headers);
}
/**
* Sets the PHP callback associated with this Response.
*
* @param mixed $callback A valid PHP callback
*/
public function setCallback($callback)
{
if (!is_callable($callback)) {
throw new \LogicException('The Response callback must be a valid PHP callable.');
}
$this->callback = $callback;
}
/**
* {@inheritdoc}
*/
public function prepare(Request $request)
{
if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) {
$this->setProtocolVersion('1.1');
}
$this->headers->set('Cache-Control', 'no-cache');
return parent::prepare($request);
}
/**
* {@inheritdoc}
*
* This method only sends the content once.
*/
public function sendContent()
{
if ($this->streamed) {
return;
}
$this->streamed = true;
if (null === $this->callback) {
throw new \LogicException('The Response callback must not be null.');
}
call_user_func($this->callback);
}
/**
* {@inheritdoc}
*
* @throws \LogicException when the content is not null
*/
public function setContent($content)
{
if (null !== $content) {
throw new \LogicException('The content cannot be set on a StreamedResponse instance.');
}
}
/**
* {@inheritdoc}
*
* @return false
*/
public function getContent()
{
return false;
}
}

View File

@@ -0,0 +1,92 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\ApacheRequest;
class ApacheRequestTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider provideServerVars
*/
public function testUriMethods($server, $expectedRequestUri, $expectedBaseUrl, $expectedPathInfo)
{
$request = new ApacheRequest();
$request->server->replace($server);
$this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct');
$this->assertEquals($expectedBaseUrl, $request->getBaseUrl(), '->getBaseUrl() is correct');
$this->assertEquals($expectedPathInfo, $request->getPathInfo(), '->getPathInfo() is correct');
}
public function provideServerVars()
{
return array(
array(
array(
'REQUEST_URI' => '/foo/app_dev.php/bar',
'SCRIPT_NAME' => '/foo/app_dev.php',
'PATH_INFO' => '/bar',
),
'/foo/app_dev.php/bar',
'/foo/app_dev.php',
'/bar'
),
array(
array(
'REQUEST_URI' => '/foo/bar',
'SCRIPT_NAME' => '/foo/app_dev.php',
),
'/foo/bar',
'/foo',
'/bar',
),
array(
array(
'REQUEST_URI' => '/app_dev.php/foo/bar',
'SCRIPT_NAME' => '/app_dev.php',
'PATH_INFO' => '/foo/bar',
),
'/app_dev.php/foo/bar',
'/app_dev.php',
'/foo/bar',
),
array(
array(
'REQUEST_URI' => '/foo/bar',
'SCRIPT_NAME' => '/app_dev.php',
),
'/foo/bar',
'',
'/foo/bar',
),
array(
array(
'REQUEST_URI' => '/app_dev.php',
'SCRIPT_NAME' => '/app_dev.php',
),
'/app_dev.php',
'/app_dev.php',
'/',
),
array(
array(
'REQUEST_URI' => '/',
'SCRIPT_NAME' => '/app_dev.php',
),
'/',
'',
'/',
),
);
}
}

View File

@@ -0,0 +1,127 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\Cookie;
/**
* CookieTest
*
* @author John Kary <john@johnkary.net>
* @author Hugo Hamon <hugo.hamon@sensio.com>
*/
class CookieTest extends \PHPUnit_Framework_TestCase
{
public function invalidNames()
{
return array(
array(''),
array(",MyName"),
array(";MyName"),
array(" MyName"),
array("\tMyName"),
array("\rMyName"),
array("\nMyName"),
array("\013MyName"),
array("\014MyName"),
);
}
/**
* @dataProvider invalidNames
* @expectedException InvalidArgumentException
* @covers Symfony\Component\HttpFoundation\Cookie::__construct
*/
public function testInstantiationThrowsExceptionIfCookieNameContainsInvalidCharacters($name)
{
new Cookie($name);
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidExpiration()
{
$cookie = new Cookie('MyCookie', 'foo','bar');
}
/**
* @covers Symfony\Component\HttpFoundation\Cookie::getValue
*/
public function testGetValue()
{
$value = 'MyValue';
$cookie = new Cookie('MyCookie', $value);
$this->assertSame($value, $cookie->getValue(), '->getValue() returns the proper value');
}
public function testGetPath()
{
$cookie = new Cookie('foo', 'bar');
$this->assertSame('/', $cookie->getPath(), '->getPath() returns / as the default path');
}
public function testGetExpiresTime()
{
$cookie = new Cookie('foo', 'bar', 3600);
$this->assertEquals(3600, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date');
}
public function testGetDomain()
{
$cookie = new Cookie('foo', 'bar', 3600, '/', '.myfoodomain.com');
$this->assertEquals('.myfoodomain.com', $cookie->getDomain(), '->getDomain() returns the domain name on which the cookie is valid');
}
public function testIsSecure()
{
$cookie = new Cookie('foo', 'bar', 3600, '/', '.myfoodomain.com', true);
$this->assertTrue($cookie->isSecure(), '->isSecure() returns whether the cookie is transmitted over HTTPS');
}
public function testIsHttpOnly()
{
$cookie = new Cookie('foo', 'bar', 3600, '/', '.myfoodomain.com', false, true);
$this->assertTrue($cookie->isHttpOnly(), '->isHttpOnly() returns whether the cookie is only transmitted over HTTP');
}
public function testCookieIsNotCleared()
{
$cookie = new Cookie('foo', 'bar', time()+3600*24);
$this->assertFalse($cookie->isCleared(), '->isCleared() returns false if the cookie did not expire yet');
}
public function testCookieIsCleared()
{
$cookie = new Cookie('foo', 'bar', time()-20);
$this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired');
}
public function testToString()
{
$cookie = new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; domain=.myfoodomain.com; secure; httponly', $cookie->__toString(), '->__toString() returns string representation of the cookie');
$cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com');
$this->assertEquals('foo=deleted; expires=' . gmdate("D, d-M-Y H:i:s T", time()-31536001) . '; path=/admin/; domain=.myfoodomain.com; httponly', $cookie->__toString(), '->__toString() returns string representation of a cleared cookie if value is NULL');
}
}

View File

@@ -0,0 +1,134 @@
<?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\Tests\File;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
class FileTest extends \PHPUnit_Framework_TestCase
{
protected $file;
public function testGetMimeTypeUsesMimeTypeGuessers()
{
$file = new File(__DIR__.'/Fixtures/test.gif');
$guesser = $this->createMockGuesser($file->getPathname(), 'image/gif');
MimeTypeGuesser::getInstance()->register($guesser);
$this->assertEquals('image/gif', $file->getMimeType());
}
public function testGuessExtensionWithoutGuesser()
{
$file = new File(__DIR__.'/Fixtures/directory/.empty');
$this->assertNull($file->guessExtension());
}
public function testGuessExtensionIsBasedOnMimeType()
{
$file = new File(__DIR__.'/Fixtures/test');
$guesser = $this->createMockGuesser($file->getPathname(), 'image/gif');
MimeTypeGuesser::getInstance()->register($guesser);
$this->assertEquals('gif', $file->guessExtension());
}
public function testConstructWhenFileNotExists()
{
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
new File(__DIR__.'/Fixtures/not_here');
}
public function testMove()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.'/test.copy.gif';
@unlink($path);
@unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new File($path);
$movedFile = $file->move($targetDir);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile);
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
}
public function testMoveWithNewName()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.'/test.newname.gif';
@unlink($path);
@unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new File($path);
$movedFile = $file->move($targetDir, 'test.newname.gif');
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
}
public function testMoveToAnUnexistentDirectory()
{
$sourcePath = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.'/Fixtures/directory/sub';
$targetPath = $targetDir.'/test.copy.gif';
@unlink($sourcePath);
@unlink($targetPath);
@rmdir($targetDir);
copy(__DIR__.'/Fixtures/test.gif', $sourcePath);
$file = new File($sourcePath);
$movedFile = $file->move($targetDir);
$this->assertFileExists($targetPath);
$this->assertFileNotExists($sourcePath);
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($sourcePath);
@unlink($targetPath);
@rmdir($targetDir);
}
public function testGetExtension()
{
$file = new File(__DIR__.'/Fixtures/test.gif');
$this->assertEquals('gif', $file->getExtension());
}
protected function createMockGuesser($path, $mimeType)
{
$guesser = $this->getMock('Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface');
$guesser
->expects($this->once())
->method('guess')
->with($this->equalTo($path))
->will($this->returnValue($mimeType))
;
return $guesser;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

View File

@@ -0,0 +1,105 @@
<?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\Tests\File;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
class MimeTypeTest extends \PHPUnit_Framework_TestCase
{
protected $path;
public function testGuessImageWithoutExtension()
{
if (extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
} else {
$this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
}
}
public function testGuessImageWithDirectory()
{
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/directory');
}
public function testGuessImageWithFileBinaryMimeTypeGuesser()
{
$guesser = MimeTypeGuesser::getInstance();
$guesser->register(new FileBinaryMimeTypeGuesser());
if (extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
} else {
$this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
}
}
public function testGuessImageWithKnownExtension()
{
if (extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif'));
} else {
$this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif'));
}
}
public function testGuessFileWithUnknownExtension()
{
if (extension_loaded('fileinfo')) {
$this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension'));
} else {
$this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension'));
}
}
public function testGuessWithIncorrectPath()
{
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/not_here');
}
public function testGuessWithNonReadablePath()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('Can not verify chmod operations on Windows');
}
if (in_array(get_current_user(), array('root'))) {
$this->markTestSkipped('This test will fail if run under superuser');
}
$path = __DIR__.'/../Fixtures/to_delete';
touch($path);
@chmod($path, 0333);
if (get_current_user() != 'root' && substr(sprintf('%o', fileperms($path)), -4) == '0333') {
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException');
MimeTypeGuesser::getInstance()->guess($path);
} else {
$this->markTestSkipped('Can not verify chmod operations, change of file permissions failed');
}
}
public static function tearDownAfterClass()
{
$path = __DIR__.'/../Fixtures/to_delete';
if (file_exists($path)) {
@chmod($path, 0666);
@unlink($path);
}
}
}

View File

@@ -0,0 +1,219 @@
<?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\Tests\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class UploadedFileTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!ini_get('file_uploads')) {
$this->markTestSkipped('file_uploads is disabled in php.ini');
}
}
public function testConstructWhenFileNotExists()
{
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
new UploadedFile(
__DIR__.'/Fixtures/not_here',
'original.gif',
null
);
}
public function testFileUploadsWithNoMimeType()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$this->assertEquals('application/octet-stream', $file->getClientMimeType());
if (extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', $file->getMimeType());
}
}
public function testFileUploadsWithUnknownMimeType()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/.unknownextension',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/.unknownextension'),
UPLOAD_ERR_OK
);
$this->assertEquals('application/octet-stream', $file->getClientMimeType());
}
public function testErrorIsOkByDefault()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
$this->assertEquals(UPLOAD_ERR_OK, $file->getError());
}
public function testGetClientOriginalName()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
$this->assertEquals('original.gif', $file->getClientOriginalName());
}
/**
* @expectedException Symfony\Component\HttpFoundation\File\Exception\FileException
*/
public function testMoveLocalFileIsNotAllowed()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
}
public function testMoveLocalFileIsAllowedInTestMode()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.'/test.copy.gif';
@unlink($path);
@unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new UploadedFile(
$path,
'original.gif',
'image/gif',
filesize($path),
UPLOAD_ERR_OK,
true
);
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
}
public function testGetClientOriginalNameSanitizeFilename()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'../../original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
$this->assertEquals('original.gif', $file->getClientOriginalName());
}
public function testGetSize()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
$this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize());
$file = new UploadedFile(
__DIR__.'/Fixtures/test',
'original.gif',
'image/gif'
);
$this->assertEquals(filesize(__DIR__.'/Fixtures/test'), $file->getSize());
}
public function testGetExtension()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
null
);
$this->assertEquals('gif', $file->getExtension());
}
public function testIsValid()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$this->assertTrue($file->isValid());
}
/**
* @dataProvider uploadedFileErrorProvider
*/
public function testIsInvalidOnUploadError($error)
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
$error
);
$this->assertFalse($file->isValid());
}
public function uploadedFileErrorProvider()
{
return array(
array(UPLOAD_ERR_INI_SIZE),
array(UPLOAD_ERR_FORM_SIZE),
array(UPLOAD_ERR_PARTIAL),
array(UPLOAD_ERR_NO_TMP_DIR),
array(UPLOAD_ERR_EXTENSION),
);
}
}

View File

@@ -0,0 +1,148 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\FileBag;
/**
* FileBagTest.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
*/
class FileBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \InvalidArgumentException
*/
public function testFileMustBeAnArrayOrUploadedFile()
{
new FileBag(array('file' => 'foo'));
}
public function testShouldConvertsUploadedFiles()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$bag = new FileBag(array('file' => array(
'name' => basename($tmpFile),
'type' => 'text/plain',
'tmp_name' => $tmpFile,
'error' => 0,
'size' => 100
)));
$this->assertEquals($file, $bag->get('file'));
}
public function testShouldSetEmptyUploadedFilesToNull()
{
$bag = new FileBag(array('file' => array(
'name' => '',
'type' => '',
'tmp_name' => '',
'error' => UPLOAD_ERR_NO_FILE,
'size' => 0
)));
$this->assertNull($bag->get('file'));
}
public function testShouldConvertUploadedFilesWithPhpBug()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$bag = new FileBag(array(
'child' => array(
'name' => array(
'file' => basename($tmpFile),
),
'type' => array(
'file' => 'text/plain',
),
'tmp_name' => array(
'file' => $tmpFile,
),
'error' => array(
'file' => 0,
),
'size' => array(
'file' => 100,
),
)
));
$files = $bag->all();
$this->assertEquals($file, $files['child']['file']);
}
public function testShouldConvertNestedUploadedFilesWithPhpBug()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$bag = new FileBag(array(
'child' => array(
'name' => array(
'sub' => array('file' => basename($tmpFile))
),
'type' => array(
'sub' => array('file' => 'text/plain')
),
'tmp_name' => array(
'sub' => array('file' => $tmpFile)
),
'error' => array(
'sub' => array('file' => 0)
),
'size' => array(
'sub' => array('file' => 100)
),
)
));
$files = $bag->all();
$this->assertEquals($file, $files['child']['sub']['file']);
}
public function testShouldNotConvertNestedUploadedFiles()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$bag = new FileBag(array('image' => array('file' => $file)));
$files = $bag->all();
$this->assertEquals($file, $files['image']['file']);
}
protected function createTempFile()
{
return tempnam(sys_get_temp_dir().'/form_test', 'FormTest');
}
protected function setUp()
{
mkdir(sys_get_temp_dir().'/form_test', 0777, true);
}
protected function tearDown()
{
foreach (glob(sys_get_temp_dir().'/form_test/*') as $file) {
unlink($file);
}
rmdir(sys_get_temp_dir().'/form_test');
}
}

View File

@@ -0,0 +1,166 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\HeaderBag;
class HeaderBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::__construct
*/
public function testConstructor()
{
$bag = new HeaderBag(array('foo' => 'bar'));
$this->assertTrue($bag->has('foo'));
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::all
*/
public function testAll()
{
$bag = new HeaderBag(array('foo' => 'bar'));
$this->assertEquals(array('foo' => array('bar')), $bag->all(), '->all() gets all the input');
$bag = new HeaderBag(array('FOO' => 'BAR'));
$this->assertEquals(array('foo' => array('BAR')), $bag->all(), '->all() gets all the input key are lower case');
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::replace
*/
public function testReplace()
{
$bag = new HeaderBag(array('foo' => 'bar'));
$bag->replace(array('NOPE' => 'BAR'));
$this->assertEquals(array('nope' => array('BAR')), $bag->all(), '->replace() replaces the input with the argument');
$this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input');
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::get
*/
public function testGet()
{
$bag = new HeaderBag(array('foo' => 'bar', 'fuzz' => 'bizz'));
$this->assertEquals( 'bar', $bag->get('foo'), '->get return current value');
$this->assertEquals( 'bar', $bag->get('FoO'), '->get key in case insensitive');
$this->assertEquals( array('bar'), $bag->get('foo', 'nope', false), '->get return the value as array');
// defaults
$this->assertNull($bag->get('none'), '->get unknown values returns null');
$this->assertEquals( 'default', $bag->get('none', 'default'), '->get unknown values returns default');
$this->assertEquals( array('default'), $bag->get('none', 'default', false), '->get unknown values returns default as array');
$bag->set('foo', 'bor', false);
$this->assertEquals( 'bar', $bag->get('foo'), '->get return first value');
$this->assertEquals( array('bar', 'bor'), $bag->get('foo', 'nope', false), '->get return all values as array');
}
public function testSetAssociativeArray()
{
$bag = new HeaderBag();
$bag->set('foo', array('bad-assoc-index' => 'value'));
$this->assertSame('value', $bag->get('foo'));
$this->assertEquals(array('value'), $bag->get('foo', 'nope', false), 'assoc indices of multi-valued headers are ignored');
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::contains
*/
public function testContains()
{
$bag = new HeaderBag(array('foo' => 'bar', 'fuzz' => 'bizz'));
$this->assertTrue( $bag->contains('foo', 'bar'), '->contains first value');
$this->assertTrue( $bag->contains('fuzz', 'bizz'), '->contains second value');
$this->assertFalse( $bag->contains('nope', 'nope'), '->contains unknown value');
$this->assertFalse( $bag->contains('foo', 'nope'), '->contains unknown value');
// Multiple values
$bag->set('foo', 'bor', false);
$this->assertTrue( $bag->contains('foo', 'bar'), '->contains first value');
$this->assertTrue( $bag->contains('foo', 'bor'), '->contains second value');
$this->assertFalse( $bag->contains('foo', 'nope'), '->contains unknown value');
}
public function testCacheControlDirectiveAccessors()
{
$bag = new HeaderBag();
$bag->addCacheControlDirective('public');
$this->assertTrue($bag->hasCacheControlDirective('public'));
$this->assertTrue($bag->getCacheControlDirective('public'));
$this->assertEquals('public', $bag->get('cache-control'));
$bag->addCacheControlDirective('max-age', 10);
$this->assertTrue($bag->hasCacheControlDirective('max-age'));
$this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
$this->assertEquals('max-age=10, public', $bag->get('cache-control'));
$bag->removeCacheControlDirective('max-age');
$this->assertFalse($bag->hasCacheControlDirective('max-age'));
}
public function testCacheControlDirectiveParsing()
{
$bag = new HeaderBag(array('cache-control' => 'public, max-age=10'));
$this->assertTrue($bag->hasCacheControlDirective('public'));
$this->assertTrue($bag->getCacheControlDirective('public'));
$this->assertTrue($bag->hasCacheControlDirective('max-age'));
$this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
$bag->addCacheControlDirective('s-maxage', 100);
$this->assertEquals('max-age=10, public, s-maxage=100', $bag->get('cache-control'));
}
public function testCacheControlDirectiveOverrideWithReplace()
{
$bag = new HeaderBag(array('cache-control' => 'private, max-age=100'));
$bag->replace(array('cache-control' => 'public, max-age=10'));
$this->assertTrue($bag->hasCacheControlDirective('public'));
$this->assertTrue($bag->getCacheControlDirective('public'));
$this->assertTrue($bag->hasCacheControlDirective('max-age'));
$this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::getIterator
*/
public function testGetIterator()
{
$headers = array('foo' => 'bar', 'hello' => 'world', 'third' => 'charm');
$headerBag = new HeaderBag($headers);
$i = 0;
foreach ($headerBag as $key => $val) {
$i++;
$this->assertEquals(array($headers[$key]), $val);
}
$this->assertEquals(count($headers), $i);
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::count
*/
public function testCount()
{
$headers = array('foo' => 'bar', 'HELLO' => 'WORLD');
$headerBag = new HeaderBag($headers);
$this->assertEquals(count($headers), count($headerBag));
}
}

View File

@@ -0,0 +1,176 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\JsonResponse;
class JsonResponseTest extends \PHPUnit_Framework_TestCase
{
public function testConstructorEmptyCreatesJsonObject()
{
$response = new JsonResponse();
$this->assertSame('{}', $response->getContent());
}
public function testConstructorWithArrayCreatesJsonArray()
{
$response = new JsonResponse(array(0, 1, 2, 3));
$this->assertSame('[0,1,2,3]', $response->getContent());
}
public function testConstructorWithAssocArrayCreatesJsonObject()
{
$response = new JsonResponse(array('foo' => 'bar'));
$this->assertSame('{"foo":"bar"}', $response->getContent());
}
public function testConstructorWithSimpleTypes()
{
$response = new JsonResponse('foo');
$this->assertSame('"foo"', $response->getContent());
$response = new JsonResponse(0);
$this->assertSame('0', $response->getContent());
$response = new JsonResponse(0.1);
$this->assertSame('0.1', $response->getContent());
$response = new JsonResponse(true);
$this->assertSame('true', $response->getContent());
}
public function testConstructorWithCustomStatus()
{
$response = new JsonResponse(array(), 202);
$this->assertSame(202, $response->getStatusCode());
}
public function testConstructorAddsContentTypeHeader()
{
$response = new JsonResponse();
$this->assertSame('application/json', $response->headers->get('Content-Type'));
}
public function testConstructorWithCustomHeaders()
{
$response = new JsonResponse(array(), 200, array('ETag' => 'foo'));
$this->assertSame('application/json', $response->headers->get('Content-Type'));
$this->assertSame('foo', $response->headers->get('ETag'));
}
public function testConstructorWithCustomContentType()
{
$headers = array('Content-Type' => 'application/vnd.acme.blog-v1+json');
$response = new JsonResponse(array(), 200, $headers);
$this->assertSame('application/vnd.acme.blog-v1+json', $response->headers->get('Content-Type'));
}
public function testCreate()
{
$response = JsonResponse::create(array('foo' => 'bar'), 204);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertEquals('{"foo":"bar"}', $response->getContent());
$this->assertEquals(204, $response->getStatusCode());
}
public function testStaticCreateEmptyJsonObject()
{
$response = JsonResponse::create();
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('{}', $response->getContent());
}
public function testStaticCreateJsonArray()
{
$response = JsonResponse::create(array(0, 1, 2, 3));
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('[0,1,2,3]', $response->getContent());
}
public function testStaticCreateJsonObject()
{
$response = JsonResponse::create(array('foo' => 'bar'));
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('{"foo":"bar"}', $response->getContent());
}
public function testStaticCreateWithSimpleTypes()
{
$response = JsonResponse::create('foo');
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('"foo"', $response->getContent());
$response = JsonResponse::create(0);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('0', $response->getContent());
$response = JsonResponse::create(0.1);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('0.1', $response->getContent());
$response = JsonResponse::create(true);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response);
$this->assertSame('true', $response->getContent());
}
public function testStaticCreateWithCustomStatus()
{
$response = JsonResponse::create(array(), 202);
$this->assertSame(202, $response->getStatusCode());
}
public function testStaticCreateAddsContentTypeHeader()
{
$response = JsonResponse::create();
$this->assertSame('application/json', $response->headers->get('Content-Type'));
}
public function testStaticCreateWithCustomHeaders()
{
$response = JsonResponse::create(array(), 200, array('ETag' => 'foo'));
$this->assertSame('application/json', $response->headers->get('Content-Type'));
$this->assertSame('foo', $response->headers->get('ETag'));
}
public function testStaticCreateWithCustomContentType()
{
$headers = array('Content-Type' => 'application/vnd.acme.blog-v1+json');
$response = JsonResponse::create(array(), 200, $headers);
$this->assertSame('application/vnd.acme.blog-v1+json', $response->headers->get('Content-Type'));
}
public function testSetCallback()
{
$response = JsonResponse::create(array('foo' => 'bar'))->setCallback('callback');
$this->assertEquals('callback({"foo":"bar"});', $response->getContent());
$this->assertEquals('text/javascript', $response->headers->get('Content-Type'));
}
public function testSetCallbackInvalidIdentifier()
{
$response = new JsonResponse('foo');
$this->setExpectedException('InvalidArgumentException');
$response->setCallback('+invalid');
}
public function testJsonEncodeFlags()
{
$response = new JsonResponse('<>\'&"');
$this->assertEquals('"\u003C\u003E\u0027\u0026\u0022"', $response->getContent());
}
}

View File

@@ -0,0 +1,232 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\ParameterBag;
class ParameterBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::__construct
*/
public function testConstructor()
{
$this->testAll();
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::all
*/
public function testAll()
{
$bag = new ParameterBag(array('foo' => 'bar'));
$this->assertEquals(array('foo' => 'bar'), $bag->all(), '->all() gets all the input');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::replace
*/
public function testReplace()
{
$bag = new ParameterBag(array('foo' => 'bar'));
$bag->replace(array('FOO' => 'BAR'));
$this->assertEquals(array('FOO' => 'BAR'), $bag->all(), '->replace() replaces the input with the argument');
$this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::get
*/
public function testGet()
{
$bag = new ParameterBag(array('foo' => 'bar', 'null' => null));
$this->assertEquals('bar', $bag->get('foo'), '->get() gets the value of a parameter');
$this->assertEquals('default', $bag->get('unknown', 'default'), '->get() returns second argument as default if a parameter is not defined');
$this->assertNull($bag->get('null', 'default'), '->get() returns null if null is set');
}
public function testGetDoesNotUseDeepByDefault()
{
$bag = new ParameterBag(array('foo' => array('bar' => 'moo')));
$this->assertNull($bag->get('foo[bar]'));
}
/**
* @dataProvider getInvalidPaths
* @expectedException \InvalidArgumentException
*/
public function testGetDeepWithInvalidPaths($path)
{
$bag = new ParameterBag(array('foo' => array('bar' => 'moo')));
$bag->get($path, null, true);
}
public function getInvalidPaths()
{
return array(
array('foo[['),
array('foo[d'),
array('foo[bar]]'),
array('foo[bar]d'),
);
}
public function testGetDeep()
{
$bag = new ParameterBag(array('foo' => array('bar' => array('moo' => 'boo'))));
$this->assertEquals(array('moo' => 'boo'), $bag->get('foo[bar]', null, true));
$this->assertEquals('boo', $bag->get('foo[bar][moo]', null, true));
$this->assertEquals('default', $bag->get('foo[bar][foo]', 'default', true));
$this->assertEquals('default', $bag->get('bar[moo][foo]', 'default', true));
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::set
*/
public function testSet()
{
$bag = new ParameterBag(array());
$bag->set('foo', 'bar');
$this->assertEquals('bar', $bag->get('foo'), '->set() sets the value of parameter');
$bag->set('foo', 'baz');
$this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::has
*/
public function testHas()
{
$bag = new ParameterBag(array('foo' => 'bar'));
$this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined');
$this->assertFalse($bag->has('unknown'), '->has() return false if a parameter is not defined');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getAlpha
*/
public function testGetAlpha()
{
$bag = new ParameterBag(array('word' => 'foo_BAR_012'));
$this->assertEquals('fooBAR', $bag->getAlpha('word'), '->getAlpha() gets only alphabetic characters');
$this->assertEquals('', $bag->getAlpha('unknown'), '->getAlpha() returns empty string if a parameter is not defined');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getAlnum
*/
public function testGetAlnum()
{
$bag = new ParameterBag(array('word' => 'foo_BAR_012'));
$this->assertEquals('fooBAR012', $bag->getAlnum('word'), '->getAlnum() gets only alphanumeric characters');
$this->assertEquals('', $bag->getAlnum('unknown'), '->getAlnum() returns empty string if a parameter is not defined');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getDigits
*/
public function testGetDigits()
{
$bag = new ParameterBag(array('word' => 'foo_BAR_012'));
$this->assertEquals('012', $bag->getDigits('word'), '->getDigits() gets only digits as string');
$this->assertEquals('', $bag->getDigits('unknown'), '->getDigits() returns empty string if a parameter is not defined');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getInt
*/
public function testGetInt()
{
$bag = new ParameterBag(array('digits' => '0123'));
$this->assertEquals(123, $bag->getInt('digits'), '->getInt() gets a value of parameter as integer');
$this->assertEquals(0, $bag->getInt('unknown'), '->getInt() returns zero if a parameter is not defined');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::filter
*/
public function testFilter()
{
$bag = new ParameterBag(array(
'digits' => '0123ab',
'email' => 'example@example.com',
'url' => 'http://example.com/foo',
'dec' => '256',
'hex' => '0x100',
'array' => array('bang'),
));
$this->assertEmpty($bag->filter('nokey'), '->filter() should return empty by default if no key is found');
$this->assertEquals('0123', $bag->filter('digits', '', false, FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters');
$this->assertEquals('example@example.com', $bag->filter('email', '', false, FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email');
$this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as url with a path');
// This test is repeated for code-coverage
$this->assertEquals('http://example.com/foo', $bag->filter('url', '', false, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as url with a path');
$this->assertFalse($bag->filter('dec', '', false, FILTER_VALIDATE_INT, array(
'flags' => FILTER_FLAG_ALLOW_HEX,
'options' => array('min_range' => 1, 'max_range' => 0xff))
), '->filter() gets a value of parameter as integer between boundaries');
$this->assertFalse($bag->filter('hex', '', false, FILTER_VALIDATE_INT, array(
'flags' => FILTER_FLAG_ALLOW_HEX,
'options' => array('min_range' => 1, 'max_range' => 0xff))
), '->filter() gets a value of parameter as integer between boundaries');
$this->assertEquals(array('bang'), $bag->filter('array', '', false), '->filter() gets a value of parameter as an array');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getIterator
*/
public function testGetIterator()
{
$parameters = array('foo' => 'bar', 'hello' => 'world');
$bag = new ParameterBag($parameters);
$i = 0;
foreach ($bag as $key => $val) {
$i++;
$this->assertEquals($parameters[$key], $val);
}
$this->assertEquals(count($parameters), $i);
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::count
*/
public function testCount()
{
$parameters = array('foo' => 'bar', 'hello' => 'world');
$bag = new ParameterBag($parameters);
$this->assertEquals(count($parameters), count($bag));
}
}

View File

@@ -0,0 +1,83 @@
<?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\Tests;
use \Symfony\Component\HttpFoundation\RedirectResponse;
class RedirectResponseTest extends \PHPUnit_Framework_TestCase
{
public function testGenerateMetaRedirect()
{
$response = new RedirectResponse('foo.bar');
$this->assertEquals(1, preg_match(
'#<meta http-equiv="refresh" content="\d+;url=foo\.bar" />#',
preg_replace(array('/\s+/', '/\'/'), array(' ', '"'), $response->getContent())
));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRedirectResponseConstructorNullUrl()
{
$response = new RedirectResponse(null);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRedirectResponseConstructorWrongStatusCode()
{
$response = new RedirectResponse('foo.bar', 404);
}
public function testGenerateLocationHeader()
{
$response = new RedirectResponse('foo.bar');
$this->assertTrue($response->headers->has('Location'));
$this->assertEquals('foo.bar', $response->headers->get('Location'));
}
public function testGetTargetUrl()
{
$response = new RedirectResponse('foo.bar');
$this->assertEquals('foo.bar', $response->getTargetUrl());
}
public function testSetTargetUrl()
{
$response = new RedirectResponse('foo.bar');
$response->setTargetUrl('baz.beep');
$this->assertEquals('baz.beep', $response->getTargetUrl());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testSetTargetUrlNull()
{
$response = new RedirectResponse('foo.bar');
$response->setTargetUrl(null);
}
public function testCreate()
{
$response = RedirectResponse::create('foo', 301);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
$this->assertEquals(301, $response->getStatusCode());
}
}

View File

@@ -0,0 +1,181 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\RequestMatcher;
use Symfony\Component\HttpFoundation\Request;
class RequestMatcherTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider testIpv4Provider
*/
public function testIpv4($matches, $remoteAddr, $cidr)
{
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
$matcher = new RequestMatcher();
$matcher->matchIp($cidr);
$this->assertEquals($matches, $matcher->matches($request));
}
public function testIpv4Provider()
{
return array(
array(true, '192.168.1.1', '192.168.1.1'),
array(true, '192.168.1.1', '192.168.1.1/1'),
array(true, '192.168.1.1', '192.168.1.0/24'),
array(false, '192.168.1.1', '1.2.3.4/1'),
array(false, '192.168.1.1', '192.168.1/33'),
);
}
/**
* @dataProvider testIpv6Provider
*/
public function testIpv6($matches, $remoteAddr, $cidr)
{
if (!defined('AF_INET6')) {
$this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".');
}
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
$matcher = new RequestMatcher();
$matcher->matchIp($cidr);
$this->assertEquals($matches, $matcher->matches($request));
}
public function testIpv6Provider()
{
return array(
array(true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
array(false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
array(false, '2a01:198:603:0:396e:4789:8e99:890f', '::1'),
array(true, '0:0:0:0:0:0:0:1', '::1'),
array(false, '0:0:603:0:396e:4789:8e99:0001', '::1'),
);
}
public function testAnIpv6WithOptionDisabledIpv6()
{
if (defined('AF_INET6')) {
$this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".');
}
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => '2a01:198:603:0:396e:4789:8e99:890f'));
$matcher = new RequestMatcher();
$matcher->matchIp('2a01:198:603:0::/65');
try {
$matcher->matches($request);
$this->fail('An expected RuntimeException has not been raised.');
} catch (\Exception $e) {
$this->assertInstanceOf('\RuntimeException', $e);
}
}
public function testMethod()
{
$matcher = new RequestMatcher();
$matcher->matchMethod('get');
$request = Request::create('', 'get');
$this->assertTrue($matcher->matches($request));
$matcher->matchMethod('post');
$this->assertFalse($matcher->matches($request));
$matcher->matchMethod(array('get', 'post'));
$this->assertTrue($matcher->matches($request));
}
public function testHost()
{
$matcher = new RequestMatcher();
$request = Request::create('', 'get', array(), array(), array(), array('HTTP_HOST' => 'foo.example.com'));
$matcher->matchHost('.*\.example\.com');
$this->assertTrue($matcher->matches($request));
$matcher->matchHost('\.example\.com$');
$this->assertTrue($matcher->matches($request));
$matcher->matchHost('^.*\.example\.com$');
$this->assertTrue($matcher->matches($request));
$matcher->matchMethod('.*\.sensio\.com');
$this->assertFalse($matcher->matches($request));
}
public function testPath()
{
$matcher = new RequestMatcher();
$request = Request::create('/admin/foo');
$matcher->matchPath('/admin/.*');
$this->assertTrue($matcher->matches($request));
$matcher->matchPath('/admin');
$this->assertTrue($matcher->matches($request));
$matcher->matchPath('^/admin/.*$');
$this->assertTrue($matcher->matches($request));
$matcher->matchMethod('/blog/.*');
$this->assertFalse($matcher->matches($request));
}
public function testPathWithLocaleIsNotSupported()
{
$matcher = new RequestMatcher();
$request = Request::create('/en/login');
$request->setLocale('en');
$matcher->matchPath('^/{_locale}/login$');
$this->assertFalse($matcher->matches($request));
}
public function testPathWithEncodedCharacters()
{
$matcher = new RequestMatcher();
$request = Request::create('/admin/fo%20o');
$matcher->matchPath('^/admin/fo o*$');
$this->assertTrue($matcher->matches($request));
}
public function testAttributes()
{
$matcher = new RequestMatcher();
$request = Request::create('/admin/foo');
$request->attributes->set('foo', 'foo_bar');
$matcher->matchAttribute('foo', 'foo_.*');
$this->assertTrue($matcher->matches($request));
$matcher->matchAttribute('foo', 'foo');
$this->assertTrue($matcher->matches($request));
$matcher->matchAttribute('foo', '^foo_bar$');
$this->assertTrue($matcher->matches($request));
$matcher->matchAttribute('foo', 'babar');
$this->assertFalse($matcher->matches($request));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,227 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Cookie;
class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
{
public function testCacheControlHeader()
{
$bag = new ResponseHeaderBag(array());
$this->assertEquals('no-cache', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('no-cache'));
$bag = new ResponseHeaderBag(array('Cache-Control' => 'public'));
$this->assertEquals('public', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('public'));
$bag = new ResponseHeaderBag(array('ETag' => 'abcde'));
$this->assertEquals('private, must-revalidate', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('private'));
$this->assertTrue($bag->hasCacheControlDirective('must-revalidate'));
$this->assertFalse($bag->hasCacheControlDirective('max-age'));
$bag = new ResponseHeaderBag(array('Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT'));
$this->assertEquals('private, must-revalidate', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array(
'Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT',
'Cache-Control' => 'max-age=3600'
));
$this->assertEquals('max-age=3600, private', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('Last-Modified' => 'abcde'));
$this->assertEquals('private, must-revalidate', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('Etag' => 'abcde', 'Last-Modified' => 'abcde'));
$this->assertEquals('private, must-revalidate', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('cache-control' => 'max-age=100'));
$this->assertEquals('max-age=100, private', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('cache-control' => 's-maxage=100'));
$this->assertEquals('s-maxage=100', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('cache-control' => 'private, max-age=100'));
$this->assertEquals('max-age=100, private', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag(array('cache-control' => 'public, max-age=100'));
$this->assertEquals('max-age=100, public', $bag->get('Cache-Control'));
$bag = new ResponseHeaderBag();
$bag->set('Last-Modified', 'abcde');
$this->assertEquals('private, must-revalidate', $bag->get('Cache-Control'));
}
public function testToStringIncludesCookieHeaders()
{
$bag = new ResponseHeaderBag(array());
$bag->setCookie(new Cookie('foo', 'bar'));
$this->assertContains("Set-Cookie: foo=bar; httponly", explode("\r\n", $bag->__toString()));
$bag->clearCookie('foo');
$this->assertContains("Set-Cookie: foo=deleted; expires=".gmdate("D, d-M-Y H:i:s T", time() - 31536001)."; httponly", explode("\r\n", $bag->__toString()));
}
public function testReplace()
{
$bag = new ResponseHeaderBag(array());
$this->assertEquals('no-cache', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('no-cache'));
$bag->replace(array('Cache-Control' => 'public'));
$this->assertEquals('public', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('public'));
}
public function testReplaceWithRemove()
{
$bag = new ResponseHeaderBag(array());
$this->assertEquals('no-cache', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('no-cache'));
$bag->remove('Cache-Control');
$bag->replace(array());
$this->assertEquals('no-cache', $bag->get('Cache-Control'));
$this->assertTrue($bag->hasCacheControlDirective('no-cache'));
}
public function testCookiesWithSameNames()
{
$bag = new ResponseHeaderBag();
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar'));
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'foo.bar'));
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'bar.foo'));
$bag->setCookie(new Cookie('foo', 'bar'));
$this->assertCount(4, $bag->getCookies());
$headers = explode("\r\n", $bag->__toString());
$this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; path=/path/bar; domain=bar.foo; httponly", $headers);
$this->assertContains("Set-Cookie: foo=bar; httponly", $headers);
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['foo.bar']['/path/foo']['foo']));
$this->assertTrue(isset($cookies['foo.bar']['/path/bar']['foo']));
$this->assertTrue(isset($cookies['bar.foo']['/path/bar']['foo']));
$this->assertTrue(isset($cookies['']['/']['foo']));
}
public function testRemoveCookie()
{
$bag = new ResponseHeaderBag();
$bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar'));
$bag->setCookie(new Cookie('bar', 'foo', 0, '/path/bar', 'foo.bar'));
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['foo.bar']['/path/foo']));
$bag->removeCookie('foo', '/path/foo', 'foo.bar');
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['foo.bar']['/path/foo']));
$bag->removeCookie('bar', '/path/bar', 'foo.bar');
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['foo.bar']));
}
public function testRemoveCookieWithNullRemove()
{
$bag = new ResponseHeaderBag();
$bag->setCookie(new Cookie('foo', 'bar', 0));
$bag->setCookie(new Cookie('bar', 'foo', 0));
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['']['/']));
$bag->removeCookie('foo', null);
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['']['/']['foo']));
$bag->removeCookie('bar', null);
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertFalse(isset($cookies['']['/']['bar']));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testGetCookiesWithInvalidArgument()
{
$bag = new ResponseHeaderBag();
$cookies = $bag->getCookies('invalid_argument');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testMakeDispositionInvalidDisposition()
{
$headers = new ResponseHeaderBag();
$headers->makeDisposition('invalid', 'foo.html');
}
/**
* @dataProvider provideMakeDisposition
*/
public function testMakeDisposition($disposition, $filename, $filenameFallback, $expected)
{
$headers = new ResponseHeaderBag();
$this->assertEquals($expected, $headers->makeDisposition($disposition, $filename, $filenameFallback));
}
public function provideMakeDisposition()
{
return array(
array('attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'),
array('attachment', 'foo.html', '', 'attachment; filename="foo.html"'),
array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'),
array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'),
array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'),
array('attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
);
}
/**
* @dataProvider provideMakeDispositionFail
* @expectedException \InvalidArgumentException
*/
public function testMakeDispositionFail($disposition, $filename)
{
$headers = new ResponseHeaderBag();
$headers->makeDisposition($disposition, $filename);
}
public function provideMakeDispositionFail()
{
return array(
array('attachment', 'foo%20bar.html'),
array('attachment', 'foo/bar.html'),
array('attachment', '/foo.html'),
array('attachment', 'foo\bar.html'),
array('attachment', '\foo.html'),
array('attachment', 'föö.html'),
);
}
}

View File

@@ -0,0 +1,676 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ResponseTest extends \PHPUnit_Framework_TestCase
{
public function testCreate()
{
$response = Response::create('foo', 301, array('Foo' => 'bar'));
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
$this->assertEquals(301, $response->getStatusCode());
$this->assertEquals('bar', $response->headers->get('foo'));
}
public function testToString()
{
$response = new Response();
$response = explode("\r\n", $response);
$this->assertEquals("HTTP/1.0 200 OK", $response[0]);
$this->assertEquals("Cache-Control: no-cache", $response[1]);
}
public function testClone()
{
$response = new Response();
$responseClone = clone $response;
$this->assertEquals($response, $responseClone);
}
public function testSendHeaders()
{
$response = new Response();
$headers = $response->sendHeaders();
$this->assertObjectHasAttribute('headers', $headers);
$this->assertObjectHasAttribute('content', $headers);
$this->assertObjectHasAttribute('version', $headers);
$this->assertObjectHasAttribute('statusCode', $headers);
$this->assertObjectHasAttribute('statusText', $headers);
$this->assertObjectHasAttribute('charset', $headers);
}
public function testSend()
{
$response = new Response();
$responseSend = $response->send();
$this->assertObjectHasAttribute('headers', $responseSend);
$this->assertObjectHasAttribute('content', $responseSend);
$this->assertObjectHasAttribute('version', $responseSend);
$this->assertObjectHasAttribute('statusCode', $responseSend);
$this->assertObjectHasAttribute('statusText', $responseSend);
$this->assertObjectHasAttribute('charset', $responseSend);
}
public function testGetCharset()
{
$response = new Response();
$charsetOrigin = 'UTF-8';
$response->setCharset($charsetOrigin);
$charset = $response->getCharset();
$this->assertEquals($charsetOrigin, $charset);
}
public function testIsCacheable()
{
$response = new Response();
$this->assertFalse($response->isCacheable());
}
public function testIsCacheableWithSetTtl()
{
$response = new Response();
$response->setTtl(10);
$this->assertTrue($response->isCacheable());
}
public function testMustRevalidate()
{
$response = new Response();
$this->assertFalse($response->mustRevalidate());
}
public function testSetNotModified()
{
$response = new Response();
$modified = $response->setNotModified();
$this->assertObjectHasAttribute('headers', $modified);
$this->assertObjectHasAttribute('content', $modified);
$this->assertObjectHasAttribute('version', $modified);
$this->assertObjectHasAttribute('statusCode', $modified);
$this->assertObjectHasAttribute('statusText', $modified);
$this->assertObjectHasAttribute('charset', $modified);
$this->assertEquals(304, $modified->getStatusCode());
}
public function testIsSuccessful()
{
$response = new Response();
$this->assertTrue($response->isSuccessful());
}
public function testIsNotModified()
{
$response = new Response();
$modified = $response->isNotModified(new Request());
$this->assertFalse($modified);
}
public function testIsValidateable()
{
$response = new Response('', 200, array('Last-Modified' => $this->createDateTimeOneHourAgo()->format(DATE_RFC2822)));
$this->assertTrue($response->isValidateable(), '->isValidateable() returns true if Last-Modified is present');
$response = new Response('', 200, array('ETag' => '"12345"'));
$this->assertTrue($response->isValidateable(), '->isValidateable() returns true if ETag is present');
$response = new Response();
$this->assertFalse($response->isValidateable(), '->isValidateable() returns false when no validator is present');
}
public function testGetDate()
{
$response = new Response('', 200, array('Date' => $this->createDateTimeOneHourAgo()->format(DATE_RFC2822)));
$this->assertEquals(0, $this->createDateTimeOneHourAgo()->diff($response->getDate())->format('%s'), '->getDate() returns the Date header if present');
$response = new Response();
$date = $response->getDate();
$this->assertLessThan(1, $date->diff(new \DateTime(), true)->format('%s'), '->getDate() returns the current Date if no Date header present');
$response = new Response('', 200, array('Date' => $this->createDateTimeOneHourAgo()->format(DATE_RFC2822)));
$now = $this->createDateTimeNow();
$response->headers->set('Date', $now->format(DATE_RFC2822));
$this->assertEquals(0, $now->diff($response->getDate())->format('%s'), '->getDate() returns the date when the header has been modified');
}
public function testGetMaxAge()
{
$response = new Response();
$response->headers->set('Cache-Control', 's-maxage=600, max-age=0');
$this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() uses s-maxage cache control directive when present');
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=600');
$this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() falls back to max-age when no s-maxage directive present');
$response = new Response();
$response->headers->set('Cache-Control', 'must-revalidate');
$response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
$this->assertEquals(3600, $response->getMaxAge(), '->getMaxAge() falls back to Expires when no max-age or s-maxage directive present');
$response = new Response();
$this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available');
}
public function testSetSharedMaxAge()
{
$response = new Response();
$response->setSharedMaxAge(20);
$cacheControl = $response->headers->get('Cache-Control');
$this->assertEquals('public, s-maxage=20', $cacheControl);
}
public function testIsPrivate()
{
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=100');
$response->setPrivate();
$this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true');
$this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true');
$response = new Response();
$response->headers->set('Cache-Control', 'public, max-age=100');
$response->setPrivate();
$this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true');
$this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true');
$this->assertFalse($response->headers->hasCacheControlDirective('public'), '->isPrivate() removes the public Cache-Control directive');
}
public function testExpire()
{
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=100');
$response->expire();
$this->assertEquals(100, $response->headers->get('Age'), '->expire() sets the Age to max-age when present');
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=100, s-maxage=500');
$response->expire();
$this->assertEquals(500, $response->headers->get('Age'), '->expire() sets the Age to s-maxage when both max-age and s-maxage are present');
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=5, s-maxage=500');
$response->headers->set('Age', '1000');
$response->expire();
$this->assertEquals(1000, $response->headers->get('Age'), '->expire() does nothing when the response is already stale/expired');
$response = new Response();
$response->expire();
$this->assertFalse($response->headers->has('Age'), '->expire() does nothing when the response does not include freshness information');
}
public function testGetTtl()
{
$response = new Response();
$this->assertNull($response->getTtl(), '->getTtl() returns null when no Expires or Cache-Control headers are present');
$response = new Response();
$response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
$this->assertLessThan(1, 3600 - $response->getTtl(), '->getTtl() uses the Expires header when no max-age is present');
$response = new Response();
$response->headers->set('Expires', $this->createDateTimeOneHourAgo()->format(DATE_RFC2822));
$this->assertLessThan(0, $response->getTtl(), '->getTtl() returns negative values when Expires is in part');
$response = new Response();
$response->headers->set('Cache-Control', 'max-age=60');
$this->assertLessThan(1, 60 - $response->getTtl(), '->getTtl() uses Cache-Control max-age when present');
}
public function testSetClientTtl()
{
$response = new Response();
$response->setClientTtl(10);
$this->assertEquals($response->getMaxAge(), $response->getAge() + 10);
}
public function testGetSetProtocolVersion()
{
$response = new Response();
$this->assertEquals('1.0', $response->getProtocolVersion());
$response->setProtocolVersion('1.1');
$this->assertEquals('1.1', $response->getProtocolVersion());
}
public function testGetVary()
{
$response = new Response();
$this->assertEquals(array(), $response->getVary(), '->getVary() returns an empty array if no Vary header is present');
$response = new Response();
$response->headers->set('Vary', 'Accept-Language');
$this->assertEquals(array('Accept-Language'), $response->getVary(), '->getVary() parses a single header name value');
$response = new Response();
$response->headers->set('Vary', 'Accept-Language User-Agent X-Foo');
$this->assertEquals(array('Accept-Language', 'User-Agent', 'X-Foo'), $response->getVary(), '->getVary() parses multiple header name values separated by spaces');
$response = new Response();
$response->headers->set('Vary', 'Accept-Language,User-Agent, X-Foo');
$this->assertEquals(array('Accept-Language', 'User-Agent', 'X-Foo'), $response->getVary(), '->getVary() parses multiple header name values separated by commas');
}
public function testSetVary()
{
$response = new Response();
$response->setVary('Accept-Language');
$this->assertEquals(array('Accept-Language'), $response->getVary());
$response->setVary('Accept-Language, User-Agent');
$this->assertEquals(array('Accept-Language', 'User-Agent'), $response->getVary(), '->setVary() replace the vary header by default');
$response->setVary('X-Foo', false);
$this->assertEquals(array('Accept-Language', 'User-Agent'), $response->getVary(), '->setVary() doesn\'t change the Vary header if replace is set to false');
}
public function testDefaultContentType()
{
$headerMock = $this->getMock('Symfony\Component\HttpFoundation\ResponseHeaderBag', array('set'));
$headerMock->expects($this->at(0))
->method('set')
->with('Content-Type', 'text/html');
$headerMock->expects($this->at(1))
->method('set')
->with('Content-Type', 'text/html; charset=UTF-8');
$response = new Response('foo');
$response->headers = $headerMock;
$response->prepare(new Request());
}
public function testContentTypeCharset()
{
$response = new Response();
$response->headers->set('Content-Type', 'text/css');
// force fixContentType() to be called
$response->prepare(new Request());
$this->assertEquals('text/css; charset=UTF-8', $response->headers->get('Content-Type'));
}
public function testPrepareDoesNothingIfContentTypeIsSet()
{
$response = new Response('foo');
$response->headers->set('Content-Type', 'text/plain');
$response->prepare(new Request());
$this->assertEquals('text/plain; charset=UTF-8', $response->headers->get('content-type'));
}
public function testPrepareDoesNothingIfRequestFormatIsNotDefined()
{
$response = new Response('foo');
$response->prepare(new Request());
$this->assertEquals('text/html; charset=UTF-8', $response->headers->get('content-type'));
}
public function testPrepareSetContentType()
{
$response = new Response('foo');
$request = Request::create('/');
$request->setRequestFormat('json');
$response->prepare($request);
$this->assertEquals('application/json', $response->headers->get('content-type'));
}
public function testPrepareRemovesContentForHeadRequests()
{
$response = new Response('foo');
$request = Request::create('/', 'HEAD');
$response->prepare($request);
$this->assertEquals('', $response->getContent());
}
public function testSetCache()
{
$response = new Response();
//array('etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public')
try {
$response->setCache(array("wrong option" => "value"));
$this->fail('->setCache() throws an InvalidArgumentException if an option is not supported');
} catch (\Exception $e) {
$this->assertInstanceOf('InvalidArgumentException', $e, '->setCache() throws an InvalidArgumentException if an option is not supported');
$this->assertContains('"wrong option"', $e->getMessage());
}
$options = array('etag' => '"whatever"');
$response->setCache($options);
$this->assertEquals($response->getEtag(), '"whatever"');
$now = new \DateTime();
$options = array('last_modified' => $now);
$response->setCache($options);
$this->assertEquals($response->getLastModified()->getTimestamp(), $now->getTimestamp());
$options = array('max_age' => 100);
$response->setCache($options);
$this->assertEquals($response->getMaxAge(), 100);
$options = array('s_maxage' => 200);
$response->setCache($options);
$this->assertEquals($response->getMaxAge(), 200);
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
$response->setCache(array('public' => true));
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
$response->setCache(array('public' => false));
$this->assertFalse($response->headers->hasCacheControlDirective('public'));
$this->assertTrue($response->headers->hasCacheControlDirective('private'));
$response->setCache(array('private' => true));
$this->assertFalse($response->headers->hasCacheControlDirective('public'));
$this->assertTrue($response->headers->hasCacheControlDirective('private'));
$response->setCache(array('private' => false));
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
}
public function testSendContent()
{
$response = new Response('test response rendering', 200);
ob_start();
$response->sendContent();
$string = ob_get_clean();
$this->assertContains('test response rendering', $string);
}
public function testSetPublic()
{
$response = new Response();
$response->setPublic();
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
}
public function testSetExpires()
{
$response = new Response();
$response->setExpires(null);
$this->assertNull($response->getExpires(), '->setExpires() remove the header when passed null');
$now = new \DateTime();
$response->setExpires($now);
$this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
}
public function testSetLastModified()
{
$response = new Response();
$response->setLastModified(new \DateTime());
$this->assertNotNull($response->getLastModified());
$response->setLastModified(null);
$this->assertNull($response->getLastModified());
}
public function testIsInvalid()
{
$response = new Response();
try {
$response->setStatusCode(99);
$this->fail();
} catch (\InvalidArgumentException $e) {
$this->assertTrue($response->isInvalid());
}
try {
$response->setStatusCode(650);
$this->fail();
} catch (\InvalidArgumentException $e) {
$this->assertTrue($response->isInvalid());
}
$response = new Response('', 200);
$this->assertFalse($response->isInvalid());
}
/**
* @dataProvider getStatusCodeFixtures
*/
public function testSetStatusCode($code, $text, $expectedText)
{
$response = new Response();
$response->setStatusCode($code, $text);
$statusText = new \ReflectionProperty($response, 'statusText');
$statusText->setAccessible(true);
$this->assertEquals($expectedText, $statusText->getValue($response));
}
public function getStatusCodeFixtures()
{
return array(
array('200', null, 'OK'),
array('200', false, ''),
array('200', 'foo', 'foo'),
array('199', null, ''),
array('199', false, ''),
array('199', 'foo', 'foo')
);
}
public function testIsInformational()
{
$response = new Response('', 100);
$this->assertTrue($response->isInformational());
$response = new Response('', 200);
$this->assertFalse($response->isInformational());
}
public function testIsRedirectRedirection()
{
foreach (array(301, 302, 303, 307) as $code) {
$response = new Response('', $code);
$this->assertTrue($response->isRedirection());
$this->assertTrue($response->isRedirect());
}
$response = new Response('', 304);
$this->assertTrue($response->isRedirection());
$this->assertFalse($response->isRedirect());
$response = new Response('', 200);
$this->assertFalse($response->isRedirection());
$this->assertFalse($response->isRedirect());
$response = new Response('', 404);
$this->assertFalse($response->isRedirection());
$this->assertFalse($response->isRedirect());
$response = new Response('', 301, array('Location' => '/good-uri'));
$this->assertFalse($response->isRedirect('/bad-uri'));
$this->assertTrue($response->isRedirect('/good-uri'));
}
public function testIsNotFound()
{
$response = new Response('', 404);
$this->assertTrue($response->isNotFound());
$response = new Response('', 200);
$this->assertFalse($response->isNotFound());
}
public function testIsEmpty()
{
foreach (array(201, 204, 304) as $code) {
$response = new Response('', $code);
$this->assertTrue($response->isEmpty());
}
$response = new Response('', 200);
$this->assertFalse($response->isEmpty());
}
public function testIsForbidden()
{
$response = new Response('', 403);
$this->assertTrue($response->isForbidden());
$response = new Response('', 200);
$this->assertFalse($response->isForbidden());
}
public function testIsOk()
{
$response = new Response('', 200);
$this->assertTrue($response->isOk());
$response = new Response('', 404);
$this->assertFalse($response->isOk());
}
public function testIsServerOrClientError()
{
$response = new Response('', 404);
$this->assertTrue($response->isClientError());
$this->assertFalse($response->isServerError());
$response = new Response('', 500);
$this->assertFalse($response->isClientError());
$this->assertTrue($response->isServerError());
}
public function testHasVary()
{
$response = new Response();
$this->assertFalse($response->hasVary());
$response->setVary('User-Agent');
$this->assertTrue($response->hasVary());
}
public function testSetEtag()
{
$response = new Response('', 200, array('ETag' => '"12345"'));
$response->setEtag();
$this->assertNull($response->headers->get('Etag'), '->setEtag() removes Etags when call with null');
}
/**
* @dataProvider validContentProvider
*/
public function testSetContent($content)
{
$response = new Response();
$response->setContent($content);
$this->assertEquals((string) $content, $response->getContent());
}
/**
* @expectedException UnexpectedValueException
* @dataProvider invalidContentProvider
*/
public function testSetContentInvalid($content)
{
$response = new Response();
$response->setContent($content);
}
public function testSettersAreChainable()
{
$response = new Response();
$setters = array(
'setProtocolVersion' => '1.0',
'setCharset' => 'UTF-8',
'setPublic' => null,
'setPrivate' => null,
'setDate' => new \DateTime,
'expire' => null,
'setMaxAge' => 1,
'setSharedMaxAge' => 1,
'setTtl' => 1,
'setClientTtl' => 1,
);
foreach ($setters as $setter => $arg) {
$this->assertEquals($response, $response->{$setter}($arg));
}
}
public function validContentProvider()
{
return array(
'obj' => array(new StringableObject),
'string' => array('Foo'),
'int' => array(2),
);
}
public function invalidContentProvider()
{
return array(
'obj' => array(new \stdClass),
'array' => array(array()),
'bool' => array(true, '1'),
);
}
protected function createDateTimeOneHourAgo()
{
$date = new \DateTime();
return $date->sub(new \DateInterval('PT1H'));
}
protected function createDateTimeOneHourLater()
{
$date = new \DateTime();
return $date->add(new \DateInterval('PT1H'));
}
protected function createDateTimeNow()
{
return new \DateTime();
}
}
class StringableObject
{
public function __toString()
{
return 'Foo';
}
}

View File

@@ -0,0 +1,101 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\ServerBag;
/**
* ServerBagTest
*
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
*/
class ServerBagTest extends \PHPUnit_Framework_TestCase
{
public function testShouldExtractHeadersFromServerArray()
{
$server = array(
'SOME_SERVER_VARIABLE' => 'value',
'SOME_SERVER_VARIABLE2' => 'value',
'ROOT' => 'value',
'HTTP_CONTENT_TYPE' => 'text/html',
'HTTP_CONTENT_LENGTH' => '0',
'HTTP_ETAG' => 'asdf',
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => 'bar',
);
$bag = new ServerBag($server);
$this->assertEquals(array(
'CONTENT_TYPE' => 'text/html',
'CONTENT_LENGTH' => '0',
'ETAG' => 'asdf',
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => 'bar',
), $bag->getHeaders());
}
public function testHttpPasswordIsOptional()
{
$bag = new ServerBag(array('PHP_AUTH_USER' => 'foo'));
$this->assertEquals(array(
'AUTHORIZATION' => 'Basic '.base64_encode('foo:'),
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => ''
), $bag->getHeaders());
}
public function testHttpBasicAuthWithPhpCgi()
{
$bag = new ServerBag(array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')));
$this->assertEquals(array(
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => 'bar'
), $bag->getHeaders());
}
public function testHttpBasicAuthWithPhpCgiRedirect()
{
$bag = new ServerBag(array('REDIRECT_HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')));
$this->assertEquals(array(
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => 'bar'
), $bag->getHeaders());
}
public function testHttpBasicAuthWithPhpCgiEmptyPassword()
{
$bag = new ServerBag(array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:')));
$this->assertEquals(array(
'AUTHORIZATION' => 'Basic '.base64_encode('foo:'),
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => ''
), $bag->getHeaders());
}
public function testOAuthBearerAuth()
{
$headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo';
$bag = new ServerBag(array('HTTP_AUTHORIZATION' => $headerContent));
$this->assertEquals(array(
'AUTHORIZATION' => $headerContent,
), $bag->getHeaders());
}
}

View File

@@ -0,0 +1,193 @@
<?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\Tests\Session\Attribute;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
/**
* Tests AttributeBag
*
* @author Drak <drak@zikula.org>
*/
class AttributeBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @var array
*/
private $array;
/**
* @var AttributeBag
*/
private $bag;
protected function setUp()
{
$this->array = array(
'hello' => 'world',
'always' => 'be happy',
'user.login' => 'drak',
'csrf.token' => array(
'a' => '1234',
'b' => '4321',
),
'category' => array(
'fishing' => array(
'first' => 'cod',
'second' => 'sole')
),
);
$this->bag = new AttributeBag('_sf2');
$this->bag->initialize($this->array);
}
protected function tearDown()
{
$this->bag = null;
$this->array = array();
}
public function testInitialize()
{
$bag = new AttributeBag();
$bag->initialize($this->array);
$this->assertEquals($this->array, $bag->all());
$array = array('should' => 'change');
$bag->initialize($array);
$this->assertEquals($array, $bag->all());
}
public function testGetStorageKey()
{
$this->assertEquals('_sf2', $this->bag->getStorageKey());
$attributeBag = new AttributeBag('test');
$this->assertEquals('test', $attributeBag->getStorageKey());
}
public function testGetSetName()
{
$this->assertEquals('attributes', $this->bag->getName());
$this->bag->setName('foo');
$this->assertEquals('foo', $this->bag->getName());
}
/**
* @dataProvider attributesProvider
*/
public function testHas($key, $value, $exists)
{
$this->assertEquals($exists, $this->bag->has($key));
}
/**
* @dataProvider attributesProvider
*/
public function testGet($key, $value, $expected)
{
$this->assertEquals($value, $this->bag->get($key));
}
public function testGetDefaults()
{
$this->assertNull($this->bag->get('user2.login'));
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
}
/**
* @dataProvider attributesProvider
*/
public function testSet($key, $value, $expected)
{
$this->bag->set($key, $value);
$this->assertEquals($value, $this->bag->get($key));
}
public function testAll()
{
$this->assertEquals($this->array, $this->bag->all());
$this->bag->set('hello', 'fabien');
$array = $this->array;
$array['hello'] = 'fabien';
$this->assertEquals($array, $this->bag->all());
}
public function testReplace()
{
$array = array();
$array['name'] = 'jack';
$array['foo.bar'] = 'beep';
$this->bag->replace($array);
$this->assertEquals($array, $this->bag->all());
$this->assertNull($this->bag->get('hello'));
$this->assertNull($this->bag->get('always'));
$this->assertNull($this->bag->get('user.login'));
}
public function testRemove()
{
$this->assertEquals('world', $this->bag->get('hello'));
$this->bag->remove('hello');
$this->assertNull($this->bag->get('hello'));
$this->assertEquals('be happy', $this->bag->get('always'));
$this->bag->remove('always');
$this->assertNull($this->bag->get('always'));
$this->assertEquals('drak', $this->bag->get('user.login'));
$this->bag->remove('user.login');
$this->assertNull($this->bag->get('user.login'));
}
public function testClear()
{
$this->bag->clear();
$this->assertEquals(array(), $this->bag->all());
}
public function attributesProvider()
{
return array(
array('hello', 'world', true),
array('always', 'be happy', true),
array('user.login', 'drak', true),
array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
array('user2.login', null, false),
array('never', null, false),
array('bye', null, false),
array('bye/for/now', null, false),
);
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag::getIterator
*/
public function testGetIterator()
{
$i = 0;
foreach ($this->bag as $key => $val) {
$this->assertEquals($this->array[$key], $val);
$i++;
}
$this->assertEquals(count($this->array), $i);
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag::count
*/
public function testCount()
{
$this->assertEquals(count($this->array), count($this->bag));
}
}

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\Tests;
use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag;
/**
* Tests NamespacedAttributeBag
*
* @author Drak <drak@zikula.org>
*/
class NamespacedAttributeBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @var array
*/
private $array;
/**
* @var NamespacedAttributeBag
*/
private $bag;
protected function setUp()
{
$this->array = array(
'hello' => 'world',
'always' => 'be happy',
'user.login' => 'drak',
'csrf.token' => array(
'a' => '1234',
'b' => '4321',
),
'category' => array(
'fishing' => array(
'first' => 'cod',
'second' => 'sole')
),
);
$this->bag = new NamespacedAttributeBag('_sf2', '/');
$this->bag->initialize($this->array);
}
protected function tearDown()
{
$this->bag = null;
$this->array = array();
}
public function testInitialize()
{
$bag = new NamespacedAttributeBag();
$bag->initialize($this->array);
$this->assertEquals($this->array, $this->bag->all());
$array = array('should' => 'not stick');
$bag->initialize($array);
// should have remained the same
$this->assertEquals($this->array, $this->bag->all());
}
public function testGetStorageKey()
{
$this->assertEquals('_sf2', $this->bag->getStorageKey());
$attributeBag = new NamespacedAttributeBag('test');
$this->assertEquals('test', $attributeBag->getStorageKey());
}
/**
* @dataProvider attributesProvider
*/
public function testHas($key, $value, $exists)
{
$this->assertEquals($exists, $this->bag->has($key));
}
/**
* @dataProvider attributesProvider
*/
public function testGet($key, $value, $expected)
{
$this->assertEquals($value, $this->bag->get($key));
}
public function testGetDefaults()
{
$this->assertNull($this->bag->get('user2.login'));
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
}
/**
* @dataProvider attributesProvider
*/
public function testSet($key, $value, $expected)
{
$this->bag->set($key, $value);
$this->assertEquals($value, $this->bag->get($key));
}
public function testAll()
{
$this->assertEquals($this->array, $this->bag->all());
$this->bag->set('hello', 'fabien');
$array = $this->array;
$array['hello'] = 'fabien';
$this->assertEquals($array, $this->bag->all());
}
public function testReplace()
{
$array = array();
$array['name'] = 'jack';
$array['foo.bar'] = 'beep';
$this->bag->replace($array);
$this->assertEquals($array, $this->bag->all());
$this->assertNull($this->bag->get('hello'));
$this->assertNull($this->bag->get('always'));
$this->assertNull($this->bag->get('user.login'));
}
public function testRemove()
{
$this->assertEquals('world', $this->bag->get('hello'));
$this->bag->remove('hello');
$this->assertNull($this->bag->get('hello'));
$this->assertEquals('be happy', $this->bag->get('always'));
$this->bag->remove('always');
$this->assertNull($this->bag->get('always'));
$this->assertEquals('drak', $this->bag->get('user.login'));
$this->bag->remove('user.login');
$this->assertNull($this->bag->get('user.login'));
}
public function testClear()
{
$this->bag->clear();
$this->assertEquals(array(), $this->bag->all());
}
public function attributesProvider()
{
return array(
array('hello', 'world', true),
array('always', 'be happy', true),
array('user.login', 'drak', true),
array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
array('csrf.token/a', '1234', true),
array('csrf.token/b', '4321', true),
array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
array('category/fishing', array('first' => 'cod', 'second' => 'sole'), true),
array('category/fishing/first', 'cod', true),
array('category/fishing/second', 'sole', true),
array('user2.login', null, false),
array('never', null, false),
array('bye', null, false),
array('bye/for/now', null, false),
);
}
}

View File

@@ -0,0 +1,155 @@
<?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\Tests\Session\Flash;
use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag as FlashBag;
/**
* AutoExpireFlashBagTest
*
* @author Drak <drak@zikula.org>
*/
class AutoExpireFlashBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag
*/
private $bag;
/**
* @var array
*/
protected $array = array();
protected function setUp()
{
parent::setUp();
$this->bag = new FlashBag();
$this->array = array('new' => array('notice' => array('A previous flash message')));
$this->bag->initialize($this->array);
}
public function tearDown()
{
$this->bag = null;
parent::tearDown();
}
public function testInitialize()
{
$bag = new FlashBag();
$array = array('new' => array('notice' => array('A previous flash message')));
$bag->initialize($array);
$this->assertEquals(array('A previous flash message'), $bag->peek('notice'));
$array = array('new' => array(
'notice' => array('Something else'),
'error' => array('a'),
));
$bag->initialize($array);
$this->assertEquals(array('Something else'), $bag->peek('notice'));
$this->assertEquals(array('a'), $bag->peek('error'));
}
public function testGetStorageKey()
{
$this->assertEquals('_sf2_flashes', $this->bag->getStorageKey());
$attributeBag = new FlashBag('test');
$this->assertEquals('test', $attributeBag->getStorageKey());
}
public function testGetSetName()
{
$this->assertEquals('flashes', $this->bag->getName());
$this->bag->setName('foo');
$this->assertEquals('foo', $this->bag->getName());
}
public function testPeek()
{
$this->assertEquals(array(), $this->bag->peek('non_existing'));
$this->assertEquals(array('default'), $this->bag->peek('non_existing', array('default')));
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testSet()
{
$this->bag->set('notice', 'Foo');
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testHas()
{
$this->assertFalse($this->bag->has('nothing'));
$this->assertTrue($this->bag->has('notice'));
}
public function testKeys()
{
$this->assertEquals(array('notice'), $this->bag->keys());
}
public function testPeekAll()
{
$array = array(
'new' => array(
'notice' => 'Foo',
'error' => 'Bar',
),
);
$this->bag->initialize($array);
$this->assertEquals(array(
'notice' => 'Foo',
'error' => 'Bar',
), $this->bag->peekAll()
);
$this->assertEquals(array(
'notice' => 'Foo',
'error' => 'Bar',
), $this->bag->peekAll()
);
}
public function testGet()
{
$this->assertEquals(array(), $this->bag->get('non_existing'));
$this->assertEquals(array('default'), $this->bag->get('non_existing', array('default')));
$this->assertEquals(array('A previous flash message'), $this->bag->get('notice'));
$this->assertEquals(array(), $this->bag->get('notice'));
}
public function testSetAll()
{
$this->bag->setAll(array('a' => 'first', 'b' => 'second'));
$this->assertFalse($this->bag->has('a'));
$this->assertFalse($this->bag->has('b'));
}
public function testAll()
{
$this->bag->set('notice', 'Foo');
$this->bag->set('error', 'Bar');
$this->assertEquals(array(
'notice' => array('A previous flash message'),
), $this->bag->all()
);
$this->assertEquals(array(), $this->bag->all());
}
public function testClear()
{
$this->assertEquals(array('notice' => array('A previous flash message')), $this->bag->clear());
}
}

View File

@@ -0,0 +1,168 @@
<?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\Tests\Session\Flash;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
/**
* FlashBagTest
*
* @author Drak <drak@zikula.org>
*/
class FlashBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Symfony\Component\HttpFoundation\SessionFlash\FlashBagInterface
*/
private $bag;
/**
* @var array
*/
protected $array = array();
protected function setUp()
{
parent::setUp();
$this->bag = new FlashBag();
$this->array = array('notice' => array('A previous flash message'));
$this->bag->initialize($this->array);
}
public function tearDown()
{
$this->bag = null;
parent::tearDown();
}
public function testInitialize()
{
$bag = new FlashBag();
$bag->initialize($this->array);
$this->assertEquals($this->array, $bag->peekAll());
$array = array('should' => array('change'));
$bag->initialize($array);
$this->assertEquals($array, $bag->peekAll());
}
public function testGetStorageKey()
{
$this->assertEquals('_sf2_flashes', $this->bag->getStorageKey());
$attributeBag = new FlashBag('test');
$this->assertEquals('test', $attributeBag->getStorageKey());
}
public function testGetSetName()
{
$this->assertEquals('flashes', $this->bag->getName());
$this->bag->setName('foo');
$this->assertEquals('foo', $this->bag->getName());
}
public function testPeek()
{
$this->assertEquals(array(), $this->bag->peek('non_existing'));
$this->assertEquals(array('default'), $this->bag->peek('not_existing', array('default')));
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testGet()
{
$this->assertEquals(array(), $this->bag->get('non_existing'));
$this->assertEquals(array('default'), $this->bag->get('not_existing', array('default')));
$this->assertEquals(array('A previous flash message'), $this->bag->get('notice'));
$this->assertEquals(array(), $this->bag->get('notice'));
}
public function testAll()
{
$this->bag->set('notice', 'Foo');
$this->bag->set('error', 'Bar');
$this->assertEquals(array(
'notice' => array('Foo'),
'error' => array('Bar')), $this->bag->all()
);
$this->assertEquals(array(), $this->bag->all());
}
public function testSet()
{
$this->bag->set('notice', 'Foo');
$this->bag->set('notice', 'Bar');
$this->assertEquals(array('Bar'), $this->bag->peek('notice'));
}
public function testHas()
{
$this->assertFalse($this->bag->has('nothing'));
$this->assertTrue($this->bag->has('notice'));
}
public function testKeys()
{
$this->assertEquals(array('notice'), $this->bag->keys());
}
public function testPeekAll()
{
$this->bag->set('notice', 'Foo');
$this->bag->set('error', 'Bar');
$this->assertEquals(array(
'notice' => array('Foo'),
'error' => array('Bar'),
), $this->bag->peekAll()
);
$this->assertTrue($this->bag->has('notice'));
$this->assertTrue($this->bag->has('error'));
$this->assertEquals(array(
'notice' => array('Foo'),
'error' => array('Bar'),
), $this->bag->peekAll()
);
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Flash\FlashBag::count
*/
public function testCount()
{
$flashes = array('hello' => 'world', 'beep' => 'boop', 'notice' => 'nope');
foreach ($flashes as $key => $val) {
$this->bag->set($key, $val);
}
$this->assertEquals(count($flashes), count($this->bag));
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Flash\FlashBag::getIterator
*/
public function testGetIterator()
{
$flashes = array('hello' => 'world', 'beep' => 'boop', 'notice' => 'nope');
foreach ($flashes as $key => $val) {
$this->bag->set($key, $val);
}
$i = 0;
foreach ($this->bag as $key => $val) {
$this->assertEquals(array($flashes[$key]), $val);
$i++;
}
$this->assertEquals(count($flashes), $i);
$this->assertEquals(0, count($this->bag));
}
}

View File

@@ -0,0 +1,276 @@
<?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\Tests\Session;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
/**
* SessionTest
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Robert Schönthal <seroscho@googlemail.com>
* @author Drak <drak@zikula.org>
*/
class SessionTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface
*/
protected $storage;
/**
* @var \Symfony\Component\HttpFoundation\Session\SessionInterface
*/
protected $session;
protected function setUp()
{
$this->storage = new MockArraySessionStorage();
$this->session = new Session($this->storage, new AttributeBag(), new FlashBag());
}
protected function tearDown()
{
$this->storage = null;
$this->session = null;
}
public function testStart()
{
$this->assertEquals('', $this->session->getId());
$this->assertTrue($this->session->start());
$this->assertNotEquals('', $this->session->getId());
}
public function testGet()
{
// tests defaults
$this->assertNull($this->session->get('foo'));
$this->assertEquals(1, $this->session->get('foo', 1));
}
/**
* @dataProvider setProvider
*/
public function testSet($key, $value)
{
$this->session->set($key, $value);
$this->assertEquals($value, $this->session->get($key));
}
/**
* @dataProvider setProvider
*/
public function testHas($key, $value)
{
$this->session->set($key, $value);
$this->assertTrue($this->session->has($key));
$this->assertFalse($this->session->has($key.'non_value'));
}
public function testReplace()
{
$this->session->replace(array('happiness' => 'be good', 'symfony' => 'awesome'));
$this->assertEquals(array('happiness' => 'be good', 'symfony' => 'awesome'), $this->session->all());
$this->session->replace(array());
$this->assertEquals(array(), $this->session->all());
}
/**
* @dataProvider setProvider
*/
public function testAll($key, $value, $result)
{
$this->session->set($key, $value);
$this->assertEquals($result, $this->session->all());
}
/**
* @dataProvider setProvider
*/
public function testClear($key, $value)
{
$this->session->set('hi', 'fabien');
$this->session->set($key, $value);
$this->session->clear();
$this->assertEquals(array(), $this->session->all());
}
public function setProvider()
{
return array(
array('foo', 'bar', array('foo' => 'bar')),
array('foo.bar', 'too much beer', array('foo.bar' => 'too much beer')),
array('great', 'symfony2 is great', array('great' => 'symfony2 is great')),
);
}
/**
* @dataProvider setProvider
*/
public function testRemove($key, $value)
{
$this->session->set('hi.world', 'have a nice day');
$this->session->set($key, $value);
$this->session->remove($key);
$this->assertEquals(array('hi.world' => 'have a nice day'), $this->session->all());
}
public function testInvalidate()
{
$this->session->set('invalidate', 123);
$this->session->invalidate();
$this->assertEquals(array(), $this->session->all());
}
public function testMigrate()
{
$this->session->set('migrate', 321);
$this->session->migrate();
$this->assertEquals(321, $this->session->get('migrate'));
}
public function testMigrateDestroy()
{
$this->session->set('migrate', 333);
$this->session->migrate(true);
$this->assertEquals(333, $this->session->get('migrate'));
}
public function testSave()
{
$this->session->save();
}
public function testGetId()
{
$this->assertEquals('', $this->session->getId());
$this->session->start();
$this->assertNotEquals('', $this->session->getId());
}
public function testGetFlashBag()
{
$this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface', $this->session->getFlashBag());
}
// deprecated since 2.1, will be removed from 2.3
public function testGetSetFlashes()
{
$array = array('notice' => 'hello', 'error' => 'none');
$this->assertEquals(array(), $this->session->getFlashes());
$this->session->setFlashes($array);
$this->assertEquals($array, $this->session->getFlashes());
$this->assertEquals(array(), $this->session->getFlashes());
$this->session->getFlashBag()->add('notice', 'foo');
// test that BC works by only retrieving the first added.
$this->session->getFlashBag()->add('notice', 'foo2');
$this->assertEquals(array('notice' => 'foo'), $this->session->getFlashes());
}
public function testGetFlashesWithArray()
{
$array = array('notice' => 'hello', 'error' => 'none');
$this->assertEquals(array(), $this->session->getFlashes());
$this->session->setFlash('foo', $array);
$this->assertEquals(array('foo' => $array), $this->session->getFlashes());
$this->assertEquals(array(), $this->session->getFlashes());
$array = array('hello', 'foo');
$this->assertEquals(array(), $this->session->getFlashes());
$this->session->setFlash('foo', $array);
$this->assertEquals(array('foo' => 'hello'), $this->session->getFlashes());
$this->assertEquals(array(), $this->session->getFlashes());
}
public function testGetSetFlash()
{
$this->assertNull($this->session->getFlash('notice'));
$this->assertEquals('default', $this->session->getFlash('notice', 'default'));
$this->session->getFlashBag()->add('notice', 'foo');
$this->session->getFlashBag()->add('notice', 'foo2');
// test that BC works by only retrieving the first added.
$this->assertEquals('foo', $this->session->getFlash('notice'));
$this->assertNull($this->session->getFlash('notice'));
}
public function testHasFlash()
{
$this->assertFalse($this->session->hasFlash('notice'));
$this->session->setFlash('notice', 'foo');
$this->assertTrue($this->session->hasFlash('notice'));
}
public function testRemoveFlash()
{
$this->session->setFlash('notice', 'foo');
$this->session->setFlash('error', 'bar');
$this->assertTrue($this->session->hasFlash('notice'));
$this->session->removeFlash('error');
$this->assertTrue($this->session->hasFlash('notice'));
$this->assertFalse($this->session->hasFlash('error'));
}
public function testClearFlashes()
{
$this->assertFalse($this->session->hasFlash('notice'));
$this->assertFalse($this->session->hasFlash('error'));
$this->session->setFlash('notice', 'foo');
$this->session->setFlash('error', 'bar');
$this->assertTrue($this->session->hasFlash('notice'));
$this->assertTrue($this->session->hasFlash('error'));
$this->session->clearFlashes();
$this->assertFalse($this->session->hasFlash('notice'));
$this->assertFalse($this->session->hasFlash('error'));
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Session::getIterator
*/
public function testGetIterator()
{
$attributes = array('hello' => 'world', 'symfony2' => 'rocks');
foreach ($attributes as $key => $val) {
$this->session->set($key, $val);
}
$i = 0;
foreach ($this->session as $key => $val) {
$this->assertEquals($attributes[$key], $val);
$i++;
}
$this->assertEquals(count($attributes), $i);
}
/**
* @covers \Symfony\Component\HttpFoundation\Session\Session::count
*/
public function testGetCount()
{
$this->session->set('hello', 'world');
$this->session->set('symfony2', 'rocks');
$this->assertEquals(2, count($this->session));
}
public function testGetMeta()
{
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\MetadataBag', $this->session->getMetadataBag());
}
}

View File

@@ -0,0 +1,124 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler;
class MemcacheSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
const PREFIX = 'prefix_';
const TTL = 1000;
/**
* @var MemcacheSessionHandler
*/
protected $storage;
protected $memcache;
protected function setUp()
{
if (!class_exists('Memcache')) {
$this->markTestSkipped('Skipped tests Memcache class is not present');
}
$this->memcache = $this->getMock('Memcache');
$this->storage = new MemcacheSessionHandler(
$this->memcache,
array('prefix' => self::PREFIX, 'expiretime' => self::TTL)
);
}
protected function tearDown()
{
$this->memcache = null;
$this->storage = null;
}
public function testOpenSession()
{
$this->assertTrue($this->storage->open('', ''));
}
public function testCloseSession()
{
$this->memcache
->expects($this->once())
->method('close')
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->close());
}
public function testReadSession()
{
$this->memcache
->expects($this->once())
->method('get')
->with(self::PREFIX.'id')
;
$this->assertEquals('', $this->storage->read('id'));
}
public function testWriteSession()
{
$this->memcache
->expects($this->once())
->method('set')
->with(self::PREFIX.'id', 'data', 0, $this->equalTo(time() + self::TTL, 2))
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->write('id', 'data'));
}
public function testDestroySession()
{
$this->memcache
->expects($this->once())
->method('delete')
->with(self::PREFIX.'id')
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->destroy('id'));
}
public function testGcSession()
{
$this->assertTrue($this->storage->gc(123));
}
/**
* @dataProvider getOptionFixtures
*/
public function testSupportedOptions($options, $supported)
{
try {
new MemcacheSessionHandler($this->memcache, $options);
$this->assertTrue($supported);
} catch (\InvalidArgumentException $e) {
$this->assertFalse($supported);
}
}
public function getOptionFixtures()
{
return array(
array(array('prefix' => 'session'), true),
array(array('expiretime' => 100), true),
array(array('prefix' => 'session', 'expiretime' => 200), true),
array(array('expiretime' => 100, 'foo' => 'bar'), false),
);
}
}

View File

@@ -0,0 +1,119 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler;
class MemcacheddSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
const PREFIX = 'prefix_';
const TTL = 1000;
/**
* @var MemcachedSessionHandler
*/
protected $storage;
protected $memcached;
protected function setUp()
{
if (!class_exists('Memcached')) {
$this->markTestSkipped('Skipped tests Memcache class is not present');
}
$this->memcached = $this->getMock('Memcached');
$this->storage = new MemcachedSessionHandler(
$this->memcached,
array('prefix' => self::PREFIX, 'expiretime' => self::TTL)
);
}
protected function tearDown()
{
$this->memcached = null;
$this->storage = null;
}
public function testOpenSession()
{
$this->assertTrue($this->storage->open('', ''));
}
public function testCloseSession()
{
$this->assertTrue($this->storage->close());
}
public function testReadSession()
{
$this->memcached
->expects($this->once())
->method('get')
->with(self::PREFIX.'id')
;
$this->assertEquals('', $this->storage->read('id'));
}
public function testWriteSession()
{
$this->memcached
->expects($this->once())
->method('set')
->with(self::PREFIX.'id', 'data', $this->equalTo(time() + self::TTL, 2))
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->write('id', 'data'));
}
public function testDestroySession()
{
$this->memcached
->expects($this->once())
->method('delete')
->with(self::PREFIX.'id')
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->destroy('id'));
}
public function testGcSession()
{
$this->assertTrue($this->storage->gc(123));
}
/**
* @dataProvider getOptionFixtures
*/
public function testSupportedOptions($options, $supported)
{
try {
new MemcachedSessionHandler($this->memcached, $options);
$this->assertTrue($supported);
} catch (\InvalidArgumentException $e) {
$this->assertFalse($supported);
}
}
public function getOptionFixtures()
{
return array(
array(array('prefix' => 'session'), true),
array(array('expiretime' => 100), true),
array(array('prefix' => 'session', 'expiretime' => 200), true),
array(array('expiretime' => 100, 'foo' => 'bar'), false),
);
}
}

View File

@@ -0,0 +1,193 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler;
/**
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $mongo;
private $storage;
public $options;
protected function setUp()
{
if (!class_exists('\Mongo')) {
$this->markTestSkipped('MongoDbSessionHandler requires the php "mongo" extension');
}
$this->mongo = $this->getMockBuilder('Mongo')
->disableOriginalConstructor()
->getMock();
$this->options = array(
'id_field' => 'sess_id',
'data_field' => 'sess_data',
'time_field' => 'sess_time',
'database' => 'sf2-test',
'collection' => 'session-test'
);
$this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
}
public function testOpenMethodAlwaysReturnTrue()
{
$this->assertTrue($this->storage->open('test', 'test'), 'The "open" method should always return true');
}
public function testCloseMethodAlwaysReturnTrue()
{
$this->assertTrue($this->storage->close(), 'The "close" method should always return true');
}
public function testWrite()
{
$database = $this->getMockBuilder('MongoDB')
->disableOriginalConstructor()
->getMock();
$collection = $this->getMockBuilder('MongoCollection')
->disableOriginalConstructor()
->getMock();
$this->mongo->expects($this->once())
->method('selectDB')
->with($this->options['database'])
->will($this->returnValue($database));
$database->expects($this->once())
->method('selectCollection')
->with($this->options['collection'])
->will($this->returnValue($collection));
$that = $this;
$data = array();
$collection->expects($this->once())
->method('update')
->will($this->returnCallback(function($citeria, $updateData, $options) use ($that, &$data) {
$that->assertEquals(array($that->options['id_field'] => 'foo'), $citeria);
$that->assertEquals(array('upsert' => true), $options);
$data = $updateData['$set'];
}));
$this->assertTrue($this->storage->write('foo', 'bar'));
$this->assertEquals('foo', $data[$this->options['id_field']]);
$this->assertEquals('bar', $data[$this->options['data_field']]->bin);
}
public function testReplaceSessionData()
{
$database = $this->getMockBuilder('MongoDB')
->disableOriginalConstructor()
->getMock();
$collection = $this->getMockBuilder('MongoCollection')
->disableOriginalConstructor()
->getMock();
$this->mongo->expects($this->once())
->method('selectDB')
->with($this->options['database'])
->will($this->returnValue($database));
$database->expects($this->once())
->method('selectCollection')
->with($this->options['collection'])
->will($this->returnValue($collection));
$data = array();
$collection->expects($this->exactly(2))
->method('update')
->will($this->returnCallback(function($citeria, $updateData, $options) use (&$data) {
$data = $updateData;
}));
$this->storage->write('foo', 'bar');
$this->storage->write('foo', 'foobar');
$this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin);
}
public function testDestroy()
{
$database = $this->getMockBuilder('MongoDB')
->disableOriginalConstructor()
->getMock();
$collection = $this->getMockBuilder('MongoCollection')
->disableOriginalConstructor()
->getMock();
$this->mongo->expects($this->once())
->method('selectDB')
->with($this->options['database'])
->will($this->returnValue($database));
$database->expects($this->once())
->method('selectCollection')
->with($this->options['collection'])
->will($this->returnValue($collection));
$collection->expects($this->once())
->method('remove')
->with(
array($this->options['id_field'] => 'foo'),
array('justOne' => true)
);
$this->storage->destroy('foo');
}
public function testGc()
{
$database = $this->getMockBuilder('MongoDB')
->disableOriginalConstructor()
->getMock();
$collection = $this->getMockBuilder('MongoCollection')
->disableOriginalConstructor()
->getMock();
$this->mongo->expects($this->once())
->method('selectDB')
->with($this->options['database'])
->will($this->returnValue($database));
$database->expects($this->once())
->method('selectCollection')
->with($this->options['collection'])
->will($this->returnValue($collection));
$that = $this;
$collection->expects($this->once())
->method('remove')
->will($this->returnCallback(function($citeria) use($that) {
$that->assertInstanceOf('MongoTimestamp', $citeria[$that->options['time_field']]['$lt']);
$that->assertGreaterThanOrEqual(time() - -1, $citeria[$that->options['time_field']]['$lt']->sec);
}));
$this->storage->gc(-1);
}
}

View File

@@ -0,0 +1,79 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
/**
* Test class for NativeFileSessionHandler.
*
* @author Drak <drak@zikula.org>
*
* @runTestsInSeparateProcesses
*/
class NativeFileSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
public function test__Construct()
{
$storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir()));
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName());
$this->assertEquals('files', ini_get('session.save_handler'));
} else {
$this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName());
$this->assertEquals('user', ini_get('session.save_handler'));
}
$this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path'));
$this->assertEquals('TESTING', ini_get('session.name'));
}
/**
* @dataProvider savePathDataProvider
*/
public function test__ConstructSavePath($savePath, $expectedSavePath, $path)
{
$handler = new NativeFileSessionHandler($savePath);
$this->assertEquals($expectedSavePath, ini_get('session.save_path'));
$this->assertTrue(is_dir(realpath($path)));
rmdir($path);
}
public function savePathDataProvider()
{
$base = sys_get_temp_dir();
return array(
array("$base/foo", "$base/foo", "$base/foo"),
array("5;$base/foo", "5;$base/foo", "$base/foo"),
array("5;0600;$base/foo", "5;0600;$base/foo", "$base/foo"),
);
}
/**
* @expectedException \InvalidArgumentException
*/
public function test__ConstructException()
{
$handler = new NativeFileSessionHandler('something;invalid;with;too-many-args');
}
public function testConstructDefault()
{
$path = ini_get('session.save_path');
$storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler());
$this->assertEquals($path, ini_get('session.save_path'));
}
}

View File

@@ -0,0 +1,39 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
/**
* Test class for NativeSessionHandler.
*
* @author Drak <drak@zikula.org>
*
* @runTestsInSeparateProcesses
*/
class NativeSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
public function testConstruct()
{
$handler = new NativeSessionHandler();
// note for PHPUnit optimisers - the use of assertTrue/False
// here is deliberate since the tests do not require the classes to exist - drak
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->assertFalse($handler instanceof \SessionHandler);
$this->assertTrue($handler instanceof NativeSessionHandler);
} else {
$this->assertTrue($handler instanceof \SessionHandler);
$this->assertTrue($handler instanceof NativeSessionHandler);
}
}
}

View File

@@ -0,0 +1,57 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* Test class for NullSessionHandler.
*
* @author Drak <drak@zikula.org>
*
* @runTestsInSeparateProcesses
*/
class NullSessionStorageTest extends \PHPUnit_Framework_TestCase
{
public function testSaveHandlers()
{
$storage = $this->getStorage();
$this->assertEquals('user', ini_get('session.save_handler'));
}
public function testSession()
{
session_id('nullsessionstorage');
$storage = $this->getStorage();
$session = new Session($storage);
$this->assertNull($session->get('something'));
$session->set('something', 'unique');
$this->assertEquals('unique', $session->get('something'));
}
public function testNothingIsPersisted()
{
session_id('nullsessionstorage');
$storage = $this->getStorage();
$session = new Session($storage);
$session->start();
$this->assertEquals('nullsessionstorage', $session->getId());
$this->assertNull($session->get('something'));
}
public function getStorage()
{
return new NativeSessionStorage(array(), new NullSessionHandler());
}
}

View File

@@ -0,0 +1,63 @@
<?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\Tests\Session\Storage\Handler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
class PdoSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
private $pdo;
protected function setUp()
{
if (!class_exists('PDO') || !in_array('sqlite', \PDO::getAvailableDrivers())) {
$this->markTestSkipped('This test requires SQLite support in your environment');
}
$this->pdo = new \PDO("sqlite::memory:");
$sql = "CREATE TABLE sessions (sess_id VARCHAR(255) PRIMARY KEY, sess_data TEXT, sess_time INTEGER)";
$this->pdo->exec($sql);
}
public function testMultipleInstances()
{
$storage1 = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array());
$storage1->write('foo', 'bar');
$storage2 = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array());
$this->assertEquals('bar', $storage2->read('foo'), 'values persist between instances');
}
public function testSessionDestroy()
{
$storage = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array());
$storage->write('foo', 'bar');
$this->assertEquals(1, count($this->pdo->query('SELECT * FROM sessions')->fetchAll()));
$storage->destroy('foo');
$this->assertEquals(0, count($this->pdo->query('SELECT * FROM sessions')->fetchAll()));
}
public function testSessionGC()
{
$storage = new PdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array());
$storage->write('foo', 'bar');
$storage->write('baz', 'bar');
$this->assertEquals(2, count($this->pdo->query('SELECT * FROM sessions')->fetchAll()));
$storage->gc(-1);
$this->assertEquals(0, count($this->pdo->query('SELECT * FROM sessions')->fetchAll()));
}
}

View File

@@ -0,0 +1,99 @@
<?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\Tests\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
/**
* Test class for MetadataBag.
*/
class MetadataBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @var MetadataBag
*/
protected $bag;
/**
* @var array
*/
protected $array = array();
protected function setUp()
{
$this->bag = new MetadataBag();
$this->array = array(MetadataBag::CREATED => 1234567, MetadataBag::UPDATED => 12345678, MetadataBag::LIFETIME => 0);
$this->bag->initialize($this->array);
}
protected function tearDown()
{
$this->array = array();
$this->bag = null;
}
public function testInitialize()
{
$p = new \ReflectionProperty('Symfony\Component\HttpFoundation\Session\Storage\MetadataBag', 'meta');
$p->setAccessible(true);
$bag1 = new MetadataBag();
$array = array();
$bag1->initialize($array);
$this->assertGreaterThanOrEqual(time(), $bag1->getCreated());
$this->assertEquals($bag1->getCreated(), $bag1->getLastUsed());
sleep(1);
$bag2 = new MetadataBag();
$array2 = $p->getValue($bag1);
$bag2->initialize($array2);
$this->assertEquals($bag1->getCreated(), $bag2->getCreated());
$this->assertEquals($bag1->getLastUsed(), $bag2->getLastUsed());
$this->assertEquals($bag2->getCreated(), $bag2->getLastUsed());
sleep(1);
$bag3 = new MetadataBag();
$array3 = $p->getValue($bag2);
$bag3->initialize($array3);
$this->assertEquals($bag1->getCreated(), $bag3->getCreated());
$this->assertGreaterThan($bag2->getLastUsed(), $bag3->getLastUsed());
$this->assertNotEquals($bag3->getCreated(), $bag3->getLastUsed());
}
public function testGetSetName()
{
$this->assertEquals('__metadata', $this->bag->getName());
$this->bag->setName('foo');
$this->assertEquals('foo', $this->bag->getName());
}
public function testGetStorageKey()
{
$this->assertEquals('_sf2_meta', $this->bag->getStorageKey());
}
public function testGetCreated()
{
$this->assertEquals(1234567, $this->bag->getCreated());
}
public function testGetLastUsed()
{
$this->assertLessThanOrEqual(time(), $this->bag->getLastUsed());
}
public function testClear()
{
$this->bag->clear();
}
}

View File

@@ -0,0 +1,98 @@
<?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\Tests\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
/**
* Test class for MockArraySessionStorage.
*
* @author Drak <drak@zikula.org>
*/
class MockArraySessionStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @var MockArraySessionStorage
*/
private $storage;
/**
* @var AttributeBag
*/
private $attributes;
/**
* @var FlashBag
*/
private $flashes;
private $data;
protected function setUp()
{
$this->attributes = new AttributeBag();
$this->flashes = new FlashBag();
$this->data = array(
$this->attributes->getStorageKey() => array('foo' => 'bar'),
$this->flashes->getStorageKey() => array('notice' => 'hello'),
);
$this->storage = new MockArraySessionStorage();
$this->storage->registerBag($this->flashes);
$this->storage->registerBag($this->attributes);
$this->storage->setSessionData($this->data);
}
protected function tearDown()
{
$this->data = null;
$this->flashes = null;
$this->attributes = null;
$this->storage = null;
}
public function testStart()
{
$this->assertEquals('', $this->storage->getId());
$this->storage->start();
$id = $this->storage->getId();
$this->assertNotEquals('', $id);
$this->storage->start();
$this->assertEquals($id, $this->storage->getId());
}
public function testRegenerate()
{
$this->storage->start();
$id = $this->storage->getId();
$this->storage->regenerate();
$this->assertNotEquals($id, $this->storage->getId());
$this->assertEquals(array('foo' => 'bar'), $this->storage->getBag('attributes')->all());
$this->assertEquals(array('notice' => 'hello'), $this->storage->getBag('flashes')->peekAll());
$id = $this->storage->getId();
$this->storage->regenerate(true);
$this->assertNotEquals($id, $this->storage->getId());
$this->assertEquals(array('foo' => 'bar'), $this->storage->getBag('attributes')->all());
$this->assertEquals(array('notice' => 'hello'), $this->storage->getBag('flashes')->peekAll());
}
public function testGetId()
{
$this->assertEquals('', $this->storage->getId());
$this->storage->start();
$this->assertNotEquals('', $this->storage->getId());
}
}

View File

@@ -0,0 +1,117 @@
<?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\Tests\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
/**
* Test class for MockFileSessionStorage.
*
* @author Drak <drak@zikula.org>
*/
class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string
*/
private $sessionDir;
/**
* @var FileMockSessionStorage
*/
protected $storage;
protected function setUp()
{
$this->sessionDir = sys_get_temp_dir().'/sf2test';
$this->storage = $this->getStorage();
}
protected function tearDown()
{
$this->sessionDir = null;
$this->storage = null;
array_map('unlink', glob($this->sessionDir.'/*.session'));
if (is_dir($this->sessionDir)) {
rmdir($this->sessionDir);
}
}
public function testStart()
{
$this->assertEquals('', $this->storage->getId());
$this->assertTrue($this->storage->start());
$id = $this->storage->getId();
$this->assertNotEquals('', $this->storage->getId());
$this->assertTrue($this->storage->start());
$this->assertEquals($id, $this->storage->getId());
}
public function testRegenerate()
{
$this->storage->start();
$this->storage->getBag('attributes')->set('regenerate', 1234);
$this->storage->regenerate();
$this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate'));
$this->storage->regenerate(true);
$this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate'));
}
public function testGetId()
{
$this->assertEquals('', $this->storage->getId());
$this->storage->start();
$this->assertNotEquals('', $this->storage->getId());
}
public function testSave()
{
$this->storage->start();
$id = $this->storage->getId();
$this->assertNotEquals('108', $this->storage->getBag('attributes')->get('new'));
$this->assertFalse($this->storage->getBag('flashes')->has('newkey'));
$this->storage->getBag('attributes')->set('new', '108');
$this->storage->getBag('flashes')->set('newkey', 'test');
$this->storage->save();
$storage = $this->getStorage();
$storage->setId($id);
$storage->start();
$this->assertEquals('108', $storage->getBag('attributes')->get('new'));
$this->assertTrue($storage->getBag('flashes')->has('newkey'));
$this->assertEquals(array('test'), $storage->getBag('flashes')->peek('newkey'));
}
public function testMultipleInstances()
{
$storage1 = $this->getStorage();
$storage1->start();
$storage1->getBag('attributes')->set('foo', 'bar');
$storage1->save();
$storage2 = $this->getStorage();
$storage2->setId($storage1->getId());
$storage2->start();
$this->assertEquals('bar', $storage2->getBag('attributes')->get('foo'), 'values persist between instances');
}
private function getStorage()
{
$storage = new MockFileSessionStorage($this->sessionDir);
$storage->registerBag(new FlashBag());
$storage->registerBag(new AttributeBag());
return $storage;
}
}

View File

@@ -0,0 +1,155 @@
<?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\Tests\Session\Storage;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
/**
* Test class for NativeSessionStorage.
*
* @author Drak <drak@zikula.org>
*
* These tests require separate processes.
*
* @runTestsInSeparateProcesses
*/
class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @return NativeSessionStorage
*/
protected function getStorage(array $options = array())
{
$storage = new NativeSessionStorage($options);
$storage->registerBag(new AttributeBag);
return $storage;
}
public function testBag()
{
$storage = $this->getStorage();
$bag = new FlashBag();
$storage->registerBag($bag);
$this->assertSame($bag, $storage->getBag($bag->getName()));
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRegisterBagException()
{
$storage = $this->getStorage();
$storage->getBag('non_existing');
}
public function testGetId()
{
$storage = $this->getStorage();
$this->assertEquals('', $storage->getId());
$storage->start();
$this->assertNotEquals('', $storage->getId());
}
public function testRegenerate()
{
$storage = $this->getStorage();
$storage->start();
$id = $storage->getId();
$storage->getBag('attributes')->set('lucky', 7);
$storage->regenerate();
$this->assertNotEquals($id, $storage->getId());
$this->assertEquals(7, $storage->getBag('attributes')->get('lucky'));
}
public function testRegenerateDestroy()
{
$storage = $this->getStorage();
$storage->start();
$id = $storage->getId();
$storage->getBag('attributes')->set('legs', 11);
$storage->regenerate(true);
$this->assertNotEquals($id, $storage->getId());
$this->assertEquals(11, $storage->getBag('attributes')->get('legs'));
}
public function testDefaultSessionCacheLimiter()
{
ini_set('session.cache_limiter', 'nocache');
$storage = new NativeSessionStorage();
$this->assertEquals('', ini_get('session.cache_limiter'));
}
public function testExplicitSessionCacheLimiter()
{
ini_set('session.cache_limiter', 'nocache');
$storage = new NativeSessionStorage(array('cache_limiter' => 'public'));
$this->assertEquals('public', ini_get('session.cache_limiter'));
}
public function testCookieOptions()
{
$options = array(
'cookie_lifetime' => 123456,
'cookie_path' => '/my/cookie/path',
'cookie_domain' => 'symfony2.example.com',
'cookie_secure' => true,
'cookie_httponly' => false,
);
$this->getStorage($options);
$temp = session_get_cookie_params();
$gco = array();
foreach ($temp as $key => $value) {
$gco['cookie_'.$key] = $value;
}
$this->assertEquals($options, $gco);
}
public function testSetSaveHandler()
{
$storage = $this->getStorage();
$storage->setSaveHandler(new \StdClass());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
}
public function testSetSaveHandlerPHP53()
{
if (version_compare(phpversion(), '5.4.0', '>=')) {
$this->markTestSkipped('Test skipped, for PHP 5.3 only.');
}
$storage = $this->getStorage();
$storage->setSaveHandler(new NativeFileSessionHandler());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
}
public function testSetSaveHandlerPHP54()
{
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->markTestSkipped('Test skipped, for PHP 5.4+ only.');
}
$storage = $this->getStorage();
$storage->setSaveHandler(new NullSessionHandler());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
}
}

View File

@@ -0,0 +1,141 @@
<?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\Tests\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
// Note until PHPUnit_Mock_Objects 1.2 is released you cannot mock abstracts due to
// https://github.com/sebastianbergmann/phpunit-mock-objects/issues/73
class ConcreteProxy extends AbstractProxy
{
}
class ConcreteSessionHandlerInterfaceProxy extends AbstractProxy implements \SessionHandlerInterface
{
public function open($savePath, $sessionName)
{
}
public function close()
{
}
public function read($id)
{
}
public function write($id, $data)
{
}
public function destroy($id)
{
}
public function gc($maxlifetime)
{
}
}
/**
* Test class for AbstractProxy.
*
* @author Drak <drak@zikula.org>
*/
class AbstractProxyTest extends \PHPUnit_Framework_TestCase
{
/**
* @var AbstractProxy
*/
protected $proxy;
protected function setUp()
{
$this->proxy = new ConcreteProxy();
}
protected function tearDown()
{
$this->proxy = null;
}
public function testGetSaveHandlerName()
{
$this->assertNull($this->proxy->getSaveHandlerName());
}
public function testIsSessionHandlerInterface()
{
$this->assertFalse($this->proxy->isSessionHandlerInterface());
$sh = new ConcreteSessionHandlerInterfaceProxy();
$this->assertTrue($sh->isSessionHandlerInterface());
}
public function testIsWrapper()
{
$this->assertFalse($this->proxy->isWrapper());
}
public function testIsActive()
{
$this->assertFalse($this->proxy->isActive());
}
public function testSetActive()
{
$this->proxy->setActive(true);
$this->assertTrue($this->proxy->isActive());
$this->proxy->setActive(false);
$this->assertFalse($this->proxy->isActive());
}
/**
* @runInSeparateProcess
*/
public function testName()
{
$this->assertEquals(session_name(), $this->proxy->getName());
$this->proxy->setName('foo');
$this->assertEquals('foo', $this->proxy->getName());
$this->assertEquals(session_name(), $this->proxy->getName());
}
/**
* @expectedException \LogicException
*/
public function testNameException()
{
$this->proxy->setActive(true);
$this->proxy->setName('foo');
}
/**
* @runInSeparateProcess
*/
public function testId()
{
$this->assertEquals(session_id(), $this->proxy->getId());
$this->proxy->setId('foo');
$this->assertEquals('foo', $this->proxy->getId());
$this->assertEquals(session_id(), $this->proxy->getId());
}
/**
* @expectedException \LogicException
*/
public function testIdException()
{
$this->proxy->setActive(true);
$this->proxy->setId('foo');
}
}

View File

@@ -0,0 +1,35 @@
<?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\Tests\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
/**
* Test class for NativeProxy.
*
* @author Drak <drak@zikula.org>
*/
class NativeProxyTest extends \PHPUnit_Framework_TestCase
{
public function testIsWrapper()
{
$proxy = new NativeProxy();
$this->assertFalse($proxy->isWrapper());
}
public function testGetSaveHandlerName()
{
$name = ini_get('session.save_handler');
$proxy = new NativeProxy();
$this->assertEquals($name, $proxy->getSaveHandlerName());
}
}

View File

@@ -0,0 +1,122 @@
<?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\Tests\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
/**
* Tests for SessionHandlerProxy class.
*
* @author Drak <drak@zikula.org>
*
* @runTestsInSeparateProcesses
*/
class SessionHandlerProxyTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PHPUnit_Framework_MockObject_Matcher
*/
private $mock;
/**
* @var SessionHandlerProxy
*/
private $proxy;
protected function setUp()
{
$this->mock = $this->getMock('SessionHandlerInterface');
$this->proxy = new SessionHandlerProxy($this->mock);
}
protected function tearDown()
{
$this->mock = null;
$this->proxy = null;
}
public function testOpen()
{
$this->mock->expects($this->once())
->method('open')
->will($this->returnValue(true));
$this->assertFalse($this->proxy->isActive());
$this->proxy->open('name', 'id');
$this->assertTrue($this->proxy->isActive());
}
public function testOpenFalse()
{
$this->mock->expects($this->once())
->method('open')
->will($this->returnValue(false));
$this->assertFalse($this->proxy->isActive());
$this->proxy->open('name', 'id');
$this->assertFalse($this->proxy->isActive());
}
public function testClose()
{
$this->mock->expects($this->once())
->method('close')
->will($this->returnValue(true));
$this->assertFalse($this->proxy->isActive());
$this->proxy->close();
$this->assertFalse($this->proxy->isActive());
}
public function testCloseFalse()
{
$this->mock->expects($this->once())
->method('close')
->will($this->returnValue(false));
$this->assertFalse($this->proxy->isActive());
$this->proxy->close();
$this->assertFalse($this->proxy->isActive());
}
public function testRead()
{
$this->mock->expects($this->once())
->method('read');
$this->proxy->read('id');
}
public function testWrite()
{
$this->mock->expects($this->once())
->method('write');
$this->proxy->write('id', 'data');
}
public function testDestroy()
{
$this->mock->expects($this->once())
->method('destroy');
$this->proxy->destroy('id');
}
public function testGc()
{
$this->mock->expects($this->once())
->method('gc');
$this->proxy->gc(86400);
}
}

View File

@@ -0,0 +1,114 @@
<?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\Tests;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;
class StreamedResponseTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$response = new StreamedResponse(function () { echo 'foo'; }, 404, array('Content-Type' => 'text/plain'));
$this->assertEquals(404, $response->getStatusCode());
$this->assertEquals('text/plain', $response->headers->get('Content-Type'));
}
public function testPrepareWith11Protocol()
{
$response = new StreamedResponse(function () { echo 'foo'; });
$request = Request::create('/');
$request->server->set('SERVER_PROTOCOL', 'HTTP/1.1');
$response->prepare($request);
$this->assertEquals('1.1', $response->getProtocolVersion());
$this->assertNotEquals('chunked', $response->headers->get('Transfer-Encoding'), 'Apache assumes responses with a Transfer-Encoding header set to chunked to already be encoded.');
$this->assertEquals('no-cache, private', $response->headers->get('Cache-Control'));
}
public function testPrepareWith10Protocol()
{
$response = new StreamedResponse(function () { echo 'foo'; });
$request = Request::create('/');
$request->server->set('SERVER_PROTOCOL', 'HTTP/1.0');
$response->prepare($request);
$this->assertEquals('1.0', $response->getProtocolVersion());
$this->assertNull($response->headers->get('Transfer-Encoding'));
$this->assertEquals('no-cache, private', $response->headers->get('Cache-Control'));
}
public function testPrepareWithHeadRequest()
{
$response = new StreamedResponse(function () { echo 'foo'; });
$request = Request::create('/', 'HEAD');
$response->prepare($request);
}
public function testSendContent()
{
$called = 0;
$response = new StreamedResponse(function () use (&$called) { ++$called; });
$response->sendContent();
$this->assertEquals(1, $called);
$response->sendContent();
$this->assertEquals(1, $called);
}
/**
* @expectedException \LogicException
*/
public function testSendContentWithNonCallable()
{
$response = new StreamedResponse(null);
$response->sendContent();
}
/**
* @expectedException \LogicException
*/
public function testSetCallbackNonCallable()
{
$response = new StreamedResponse(null);
$response->setCallback(null);
}
/**
* @expectedException \LogicException
*/
public function testSetContent()
{
$response = new StreamedResponse(function () { echo 'foo'; });
$response->setContent('foo');
}
public function testGetContent()
{
$response = new StreamedResponse(function () { echo 'foo'; });
$this->assertFalse($response->getContent());
}
public function testCreate()
{
$response = StreamedResponse::create(function () {}, 204);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response);
$this->assertEquals(204, $response->getStatusCode());
}
}

View File

@@ -0,0 +1,22 @@
<?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.
*/
spl_autoload_register(function ($class) {
if (ltrim('SessionHandlerInterface', '/') === $class) {
require_once __DIR__.'/../Resources/stubs/SessionHandlerInterface.php';
}
if (0 !== strpos(ltrim($class, '/'), 'Symfony\Component\HttpFoundation')) {
return;
}
require_once __DIR__.'/../'.substr(str_replace('\\', '/', $class), strlen('Symfony\Component\HttpFoundation')).'.php';
});

View File

@@ -0,0 +1,34 @@
{
"name": "symfony/http-foundation",
"type": "library",
"description": "Symfony HttpFoundation Component",
"keywords": [],
"homepage": "http://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.3"
},
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpFoundation": "",
"SessionHandlerInterface": "Symfony/Component/HttpFoundation/Resources/stubs"
}
},
"target-dir": "Symfony/Component/HttpFoundation",
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="Tests/bootstrap.php"
>
<testsuites>
<testsuite name="Symfony HttpFoundation Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>