update v 1.0.7.5

This commit is contained in:
Sujit Prasad
2016-06-13 20:41:55 +05:30
parent aa9786d829
commit 283d97e3ea
5078 changed files with 339851 additions and 175995 deletions

View File

@@ -27,6 +27,9 @@ class BinaryFileResponse extends Response
{
protected static $trustXSendfileTypeHeader = false;
/**
* @var File
*/
protected $file;
protected $offset;
protected $maxlen;
@@ -158,6 +161,20 @@ class BinaryFileResponse extends Response
$filename = $this->file->getFilename();
}
if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) {
$encoding = mb_detect_encoding($filename, null, true);
for ($i = 0; $i < mb_strlen($filename, $encoding); ++$i) {
$char = mb_substr($filename, $i, 1, $encoding);
if ('%' === $char || ord($char) < 32 || ord($char) > 126) {
$filenameFallback .= '_';
} else {
$filenameFallback .= $char;
}
}
}
$dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
$this->headers->set('Content-Disposition', $dispositionHeader);
@@ -180,7 +197,7 @@ class BinaryFileResponse extends Response
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}
if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) {
if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
$this->setProtocolVersion('1.1');
}
@@ -193,17 +210,21 @@ class BinaryFileResponse extends Response
// Use X-Sendfile, do not send any content.
$type = $request->headers->get('X-Sendfile-Type');
$path = $this->file->getRealPath();
if (strtolower($type) == 'x-accel-redirect') {
// Fall back to scheme://path for stream wrapped locations.
if (false === $path) {
$path = $this->file->getPathname();
}
if (strtolower($type) === 'x-accel-redirect') {
// Do X-Accel-Mapping substitutions.
// @link http://wiki.nginx.org/X-accel#X-Accel-Redirect
foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
$mapping = explode('=', $mapping, 2);
if (2 == count($mapping)) {
if (2 === count($mapping)) {
$pathPrefix = trim($mapping[0]);
$location = trim($mapping[1]);
if (substr($path, 0, strlen($pathPrefix)) == $pathPrefix) {
if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) {
$path = $location.substr($path, strlen($pathPrefix));
break;
}
@@ -214,7 +235,7 @@ class BinaryFileResponse extends Response
$this->maxlen = 0;
} elseif ($request->headers->has('Range')) {
// Process the range headers.
if (!$request->headers->has('If-Range') || $this->getEtag() == $request->headers->get('If-Range')) {
if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
$range = $request->headers->get('Range');
$fileSize = $this->file->getSize();
@@ -232,6 +253,7 @@ class BinaryFileResponse extends Response
if ($start <= $end) {
if ($start < 0 || $end > $fileSize - 1) {
$this->setStatusCode(416);
$this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize));
} elseif ($start !== 0 || $end !== $fileSize - 1) {
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
$this->offset = $start;
@@ -247,19 +269,32 @@ class BinaryFileResponse extends Response
return $this;
}
private function hasValidIfRangeHeader($header)
{
if ($this->getEtag() === $header) {
return true;
}
if (null === $lastModified = $this->getLastModified()) {
return false;
}
return $lastModified->format('D, d M Y H:i:s').' GMT' === $header;
}
/**
* Sends the file.
*
* {@inheritdoc}
*/
public function sendContent()
{
if (!$this->isSuccessful()) {
parent::sendContent();
return;
return parent::sendContent();
}
if (0 === $this->maxlen) {
return;
return $this;
}
$out = fopen('php://output', 'wb');
@@ -273,6 +308,8 @@ class BinaryFileResponse extends Response
if ($this->deleteFileAfterSend) {
unlink($this->file->getPathname());
}
return $this;
}
/**
@@ -308,6 +345,7 @@ class BinaryFileResponse extends Response
/**
* If this is set to true, the file will be unlinked after the request is send
* Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used.
*
* @param bool $shouldDelete
*
* @return BinaryFileResponse

View File

@@ -1,6 +1,17 @@
CHANGELOG
=========
3.0.0
-----
* The precedence of parameters returned from `Request::get()` changed from "GET, PATH, BODY" to "PATH, GET, BODY"
2.8.0
-----
* Finding deep items in `ParameterBag::get()` is deprecated since version 2.8 and
will be removed in 3.0.
2.6.0
-----

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* Represents a cookie.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @api
*/
class Cookie
{
@@ -31,17 +29,15 @@ class Cookie
/**
* Constructor.
*
* @param string $name The name of the cookie
* @param string $value The value of the cookie
* @param int|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 bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
* @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
* @param string $name The name of the cookie
* @param string $value The value of the cookie
* @param int|string|\DateTime|\DateTimeInterface $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 bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
* @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
*
* @throws \InvalidArgumentException
*
* @api
*/
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)
{
@@ -55,7 +51,7 @@ class Cookie
}
// convert expiration time to a Unix timestamp
if ($expire instanceof \DateTime) {
if ($expire instanceof \DateTimeInterface) {
$expire = $expire->format('U');
} elseif (!is_numeric($expire)) {
$expire = strtotime($expire);
@@ -116,8 +112,6 @@ class Cookie
* Gets the name of the cookie.
*
* @return string
*
* @api
*/
public function getName()
{
@@ -128,8 +122,6 @@ class Cookie
* Gets the value of the cookie.
*
* @return string
*
* @api
*/
public function getValue()
{
@@ -140,8 +132,6 @@ class Cookie
* Gets the domain that the cookie is available to.
*
* @return string
*
* @api
*/
public function getDomain()
{
@@ -152,8 +142,6 @@ class Cookie
* Gets the time the cookie expires.
*
* @return int
*
* @api
*/
public function getExpiresTime()
{
@@ -164,8 +152,6 @@ class Cookie
* Gets the path on the server in which the cookie will be available on.
*
* @return string
*
* @api
*/
public function getPath()
{
@@ -176,8 +162,6 @@ class Cookie
* Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client.
*
* @return bool
*
* @api
*/
public function isSecure()
{
@@ -188,8 +172,6 @@ class Cookie
* Checks whether the cookie will be made accessible only through the HTTP protocol.
*
* @return bool
*
* @api
*/
public function isHttpOnly()
{
@@ -200,8 +182,6 @@ class Cookie
* Whether this cookie is about to be cleared.
*
* @return bool
*
* @api
*/
public function isCleared()
{

View File

@@ -20,8 +20,6 @@ use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
* A file in the file system.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
class File extends \SplFileInfo
{
@@ -32,8 +30,6 @@ class File extends \SplFileInfo
* @param bool $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)
{
@@ -54,8 +50,6 @@ class File extends \SplFileInfo
*
* @return string|null The guessed extension or null if it cannot be guessed
*
* @api
*
* @see ExtensionGuesser
* @see getMimeType()
*/
@@ -77,8 +71,6 @@ class File extends \SplFileInfo
* @return string|null The guessed mime type (i.e. "application/pdf")
*
* @see MimeTypeGuesser
*
* @api
*/
public function getMimeType()
{
@@ -87,20 +79,6 @@ class File extends \SplFileInfo
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.
*
@@ -110,8 +88,6 @@ class File extends \SplFileInfo
* @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)
{

View File

@@ -21,8 +21,6 @@ use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Florian Eckerstorfer <florian@eckerstorfer.org>
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class UploadedFile extends File
{
@@ -52,7 +50,7 @@ class UploadedFile extends File
/**
* The file size provided by the uploader.
*
* @var string
* @var int|null
*/
private $size;
@@ -77,17 +75,15 @@ class UploadedFile extends File
*
* 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 int $size The file size
* @param int $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants)
* @param bool $test Whether the test mode is active
* @param string $path The full temporary path to the file
* @param string $originalName The original file name
* @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream
* @param int|null $size The file size
* @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
* @param bool $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)
{
@@ -107,8 +103,6 @@ class UploadedFile extends File
* Then it should not be considered as a safe value.
*
* @return string|null The original name
*
* @api
*/
public function getClientOriginalName()
{
@@ -140,8 +134,6 @@ class UploadedFile extends File
* @return string|null The mime type
*
* @see getMimeType()
*
* @api
*/
public function getClientMimeType()
{
@@ -180,8 +172,6 @@ class UploadedFile extends File
* Then it should not be considered as a safe value.
*
* @return int|null The file size
*
* @api
*/
public function getClientSize()
{
@@ -195,8 +185,6 @@ class UploadedFile extends File
* Otherwise one of the other UPLOAD_ERR_XXX constants is returned.
*
* @return int The upload error
*
* @api
*/
public function getError()
{
@@ -207,8 +195,6 @@ class UploadedFile extends File
* Returns whether the file was uploaded successfully.
*
* @return bool True if the file has been uploaded with HTTP and no error occurred.
*
* @api
*/
public function isValid()
{
@@ -226,8 +212,6 @@ class UploadedFile extends File
* @return File A File object representing the new file
*
* @throws FileException if, for any reason, the file could not have been moved
*
* @api
*/
public function move($directory, $name = null)
{

View File

@@ -18,8 +18,6 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
*
* @api
*/
class FileBag extends ParameterBag
{
@@ -29,8 +27,6 @@ class FileBag extends ParameterBag
* Constructor.
*
* @param array $parameters An array of HTTP files
*
* @api
*/
public function __construct(array $parameters = array())
{
@@ -39,8 +35,6 @@ class FileBag extends ParameterBag
/**
* {@inheritdoc}
*
* @api
*/
public function replace(array $files = array())
{
@@ -50,8 +44,6 @@ class FileBag extends ParameterBag
/**
* {@inheritdoc}
*
* @api
*/
public function set($key, $value)
{
@@ -64,8 +56,6 @@ class FileBag extends ParameterBag
/**
* {@inheritdoc}
*
* @api
*/
public function add(array $files = array())
{

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* HeaderBag is a container for HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class HeaderBag implements \IteratorAggregate, \Countable
{
@@ -27,8 +25,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Constructor.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function __construct(array $headers = array())
{
@@ -65,8 +61,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Returns the headers.
*
* @return array An array of headers
*
* @api
*/
public function all()
{
@@ -77,8 +71,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Returns the parameter keys.
*
* @return array An array of parameter keys
*
* @api
*/
public function keys()
{
@@ -89,8 +81,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Replaces the current HTTP headers by a new set.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function replace(array $headers = array())
{
@@ -102,8 +92,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Adds new headers the current HTTP headers set.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function add(array $headers)
{
@@ -120,12 +108,10 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @param bool $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), '_', '-');
$key = str_replace('_', '-', strtolower($key));
if (!array_key_exists($key, $this->headers)) {
if (null === $default) {
@@ -148,12 +134,10 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @param string $key The key
* @param string|array $values The value or an array of values
* @param bool $replace Whether to replace the actual value or not (true by default)
*
* @api
*/
public function set($key, $values, $replace = true)
{
$key = strtr(strtolower($key), '_', '-');
$key = str_replace('_', '-', strtolower($key));
$values = array_values((array) $values);
@@ -174,12 +158,10 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @param string $key The HTTP header
*
* @return bool true if the parameter exists, false otherwise
*
* @api
*/
public function has($key)
{
return array_key_exists(strtr(strtolower($key), '_', '-'), $this->headers);
return array_key_exists(str_replace('_', '-', strtolower($key)), $this->headers);
}
/**
@@ -189,8 +171,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @param string $value The HTTP value
*
* @return bool true if the value is contained in the header, false otherwise
*
* @api
*/
public function contains($key, $value)
{
@@ -201,12 +181,10 @@ class HeaderBag implements \IteratorAggregate, \Countable
* Removes a header.
*
* @param string $key The HTTP header name
*
* @api
*/
public function remove($key)
{
$key = strtr(strtolower($key), '_', '-');
$key = str_replace('_', '-', strtolower($key));
unset($this->headers[$key]);
@@ -224,8 +202,6 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @return null|\DateTime The parsed DateTime or the default value if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*
* @api
*/
public function getDate($key, \DateTime $default = null)
{

View File

@@ -57,18 +57,19 @@ class IpUtils
* @param string $requestIp IPv4 address to check
* @param string $ip IPv4 address or subnet in CIDR notation
*
* @return bool Whether the IP is valid
* @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet.
*/
public static function checkIp4($requestIp, $ip)
{
if (false !== strpos($ip, '/')) {
if ('0.0.0.0/0' === $ip) {
return true;
}
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 32) {
if ($netmask === '0') {
// Ensure IP is valid - using ip2long below implicitly validates, but we need to do it manually here
return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
}
if ($netmask < 0 || $netmask > 32) {
return false;
}
} else {
@@ -111,8 +112,12 @@ class IpUtils
$netmask = 128;
}
$bytesAddr = unpack('n*', inet_pton($address));
$bytesTest = unpack('n*', inet_pton($requestIp));
$bytesAddr = unpack('n*', @inet_pton($address));
$bytesTest = unpack('n*', @inet_pton($requestIp));
if (!$bytesAddr || !$bytesTest) {
return false;
}
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
$left = $netmask - 16 * ($i - 1);

View File

@@ -102,39 +102,12 @@ class JsonResponse extends Response
$data = json_encode($data, $this->encodingOptions);
} else {
try {
if (PHP_VERSION_ID < 50400) {
// PHP 5.3 triggers annoying warnings for some
// types that can't be serialized as JSON (INF, resources, etc.)
// but doesn't provide the JsonSerializable interface.
set_error_handler('var_dump', 0);
$data = @json_encode($data, $this->encodingOptions);
} else {
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
// objects in a new exception that needs to be removed.
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
if (PHP_VERSION_ID < 50500) {
// Clear json_last_error()
json_encode(null);
$errorHandler = set_error_handler('var_dump');
restore_error_handler();
set_error_handler(function () use ($errorHandler) {
if (JSON_ERROR_NONE === json_last_error()) {
return $errorHandler && false !== call_user_func_array($errorHandler, func_get_args());
}
});
}
$data = json_encode($data, $this->encodingOptions);
}
if (PHP_VERSION_ID < 50500) {
restore_error_handler();
}
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
// objects in a new exception that needs to be removed.
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
$data = json_encode($data, $this->encodingOptions);
} catch (\Exception $e) {
if (PHP_VERSION_ID < 50500) {
restore_error_handler();
}
if (PHP_VERSION_ID >= 50400 && 'Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
if ('Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
throw $e->getPrevious() ?: $e;
}
throw $e;
@@ -142,7 +115,7 @@ class JsonResponse extends Response
}
if (JSON_ERROR_NONE !== json_last_error()) {
throw new \InvalidArgumentException($this->transformJsonError());
throw new \InvalidArgumentException(json_last_error_msg());
}
$this->data = $data;
@@ -196,31 +169,4 @@ class JsonResponse extends Response
return $this->setContent($this->data);
}
private function transformJsonError()
{
if (function_exists('json_last_error_msg')) {
return json_last_error_msg();
}
switch (json_last_error()) {
case JSON_ERROR_DEPTH:
return 'Maximum stack depth exceeded.';
case JSON_ERROR_STATE_MISMATCH:
return 'Underflow or the modes mismatch.';
case JSON_ERROR_CTRL_CHAR:
return 'Unexpected control character found.';
case JSON_ERROR_SYNTAX:
return 'Syntax error, malformed JSON.';
case JSON_ERROR_UTF8:
return 'Malformed UTF-8 characters, possibly incorrectly encoded.';
default:
return 'Unknown error.';
}
}
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 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

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* ParameterBag is a container for key/value pairs.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ParameterBag implements \IteratorAggregate, \Countable
{
@@ -31,8 +29,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Constructor.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function __construct(array $parameters = array())
{
@@ -43,8 +39,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Returns the parameters.
*
* @return array An array of parameters
*
* @api
*/
public function all()
{
@@ -55,8 +49,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Returns the parameter keys.
*
* @return array An array of parameter keys
*
* @api
*/
public function keys()
{
@@ -67,8 +59,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Replaces the current parameters by a new set.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function replace(array $parameters = array())
{
@@ -79,8 +69,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Adds parameters.
*
* @param array $parameters An array of parameters
*
* @api
*/
public function add(array $parameters = array())
{
@@ -90,63 +78,14 @@ class ParameterBag implements \IteratorAggregate, \Countable
/**
* Returns a parameter by name.
*
* @param string $path The key
* @param string $key The key
* @param mixed $default The default value if the parameter key does not exist
* @param bool $deep If true, a path like foo[bar] will find deeper items
*
* @return mixed
*
* @throws \InvalidArgumentException
*
* @api
*/
public function get($path, $default = null, $deep = false)
public function get($key, $default = null)
{
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;
return array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
}
/**
@@ -154,8 +93,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
*
* @param string $key The key
* @param mixed $value The value
*
* @api
*/
public function set($key, $value)
{
@@ -168,8 +105,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* @param string $key The key
*
* @return bool true if the parameter exists, false otherwise
*
* @api
*/
public function has($key)
{
@@ -180,8 +115,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
* Removes a parameter.
*
* @param string $key The key
*
* @api
*/
public function remove($key)
{
@@ -192,65 +125,53 @@ class ParameterBag implements \IteratorAggregate, \Countable
* 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 bool $deep If true, a path like foo[bar] will find deeper items
* @param string $default The default value if the parameter key does not exist
*
* @return string The filtered value
*
* @api
*/
public function getAlpha($key, $default = '', $deep = false)
public function getAlpha($key, $default = '')
{
return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default, $deep));
return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default));
}
/**
* 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 bool $deep If true, a path like foo[bar] will find deeper items
* @param string $default The default value if the parameter key does not exist
*
* @return string The filtered value
*
* @api
*/
public function getAlnum($key, $default = '', $deep = false)
public function getAlnum($key, $default = '')
{
return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default, $deep));
return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default));
}
/**
* 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 bool $deep If true, a path like foo[bar] will find deeper items
* @param string $default The default value if the parameter key does not exist
*
* @return string The filtered value
*
* @api
*/
public function getDigits($key, $default = '', $deep = false)
public function getDigits($key, $default = '')
{
// 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));
return str_replace(array('-', '+'), '', $this->filter($key, $default, 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 bool $deep If true, a path like foo[bar] will find deeper items
* @param int $default The default value if the parameter key does not exist
*
* @return int The filtered value
*
* @api
*/
public function getInt($key, $default = 0, $deep = false)
public function getInt($key, $default = 0)
{
return (int) $this->get($key, $default, $deep);
return (int) $this->get($key, $default);
}
/**
@@ -258,13 +179,12 @@ class ParameterBag implements \IteratorAggregate, \Countable
*
* @param string $key The parameter key
* @param mixed $default The default value if the parameter key does not exist
* @param bool $deep If true, a path like foo[bar] will find deeper items
*
* @return bool The filtered value
*/
public function getBoolean($key, $default = false, $deep = false)
public function getBoolean($key, $default = false)
{
return $this->filter($key, $default, $deep, FILTER_VALIDATE_BOOLEAN);
return $this->filter($key, $default, FILTER_VALIDATE_BOOLEAN);
}
/**
@@ -272,7 +192,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
*
* @param string $key Key.
* @param mixed $default Default = null.
* @param bool $deep Default = false.
* @param int $filter FILTER_* constant.
* @param mixed $options Filter options.
*
@@ -280,9 +199,9 @@ class ParameterBag implements \IteratorAggregate, \Countable
*
* @return mixed
*/
public function filter($key, $default = null, $deep = false, $filter = FILTER_DEFAULT, $options = array())
public function filter($key, $default = null, $filter = FILTER_DEFAULT, $options = array())
{
$value = $this->get($key, $default, $deep);
$value = $this->get($key, $default);
// Always turn $options into an array - this allows filter_var option shortcuts.
if (!is_array($options) && $options) {

View File

@@ -0,0 +1,14 @@
HttpFoundation Component
========================
The HttpFoundation component defines an object-oriented layer for the HTTP
specification.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/http_foundation/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* RedirectResponse represents an HTTP response doing a redirect.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class RedirectResponse extends Response
{
@@ -25,22 +23,17 @@ class RedirectResponse extends Response
/**
* 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 string $url The URL to redirect to. The URL should be a full URL, with schema etc.,
* but practically every browser redirects on paths only as well
* @param int $status The status code (302 by default)
* @param array $headers The headers (Location is always set to the given URL)
*
* @throws \InvalidArgumentException
*
* @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);

View File

@@ -25,11 +25,10 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
* * getUriForPath
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Request
{
const HEADER_FORWARDED = 'forwarded';
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_PROTO = 'client_proto';
@@ -46,6 +45,9 @@ class Request
const METHOD_TRACE = 'TRACE';
const METHOD_CONNECT = 'CONNECT';
/**
* @var string[]
*/
protected static $trustedProxies = array();
/**
@@ -62,10 +64,13 @@ class Request
* Names for headers that can be trusted when
* using trusted proxies.
*
* The default names are non-standard, but widely used
* The FORWARDED header is the standard as of rfc7239.
*
* The other headers are non-standard, but widely used
* by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
*/
protected static $trustedHeaders = array(
self::HEADER_FORWARDED => 'FORWARDED',
self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
@@ -78,8 +83,6 @@ class Request
* Custom parameters.
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
* @api
*/
public $attributes;
@@ -87,8 +90,6 @@ class Request
* Request body parameters ($_POST).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
* @api
*/
public $request;
@@ -96,8 +97,6 @@ class Request
* Query string parameters ($_GET).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
* @api
*/
public $query;
@@ -105,8 +104,6 @@ class Request
* Server and execution environment parameters ($_SERVER).
*
* @var \Symfony\Component\HttpFoundation\ServerBag
*
* @api
*/
public $server;
@@ -114,8 +111,6 @@ class Request
* Uploaded files ($_FILES).
*
* @var \Symfony\Component\HttpFoundation\FileBag
*
* @api
*/
public $files;
@@ -123,8 +118,6 @@ class Request
* Cookies ($_COOKIE).
*
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
* @api
*/
public $cookies;
@@ -132,8 +125,6 @@ class Request
* Headers (taken from the $_SERVER).
*
* @var \Symfony\Component\HttpFoundation\HeaderBag
*
* @api
*/
public $headers;
@@ -224,8 +215,6 @@ class Request
* @param array $files The FILES parameters
* @param array $server The SERVER parameters
* @param string|resource $content The raw body data
*
* @api
*/
public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
@@ -244,8 +233,6 @@ class Request
* @param array $files The FILES parameters
* @param array $server The SERVER parameters
* @param string|resource $content The raw body data
*
* @api
*/
public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
@@ -274,8 +261,6 @@ class Request
* Creates a new request with values from PHP's super globals.
*
* @return Request A new request
*
* @api
*/
public static function createFromGlobals()
{
@@ -283,7 +268,7 @@ class Request
// stores the Content-Type and Content-Length header values in
// HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields.
$server = $_SERVER;
if ('cli-server' === php_sapi_name()) {
if ('cli-server' === PHP_SAPI) {
if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
$server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
}
@@ -319,8 +304,6 @@ class Request
* @param string $content The raw body data
*
* @return Request A Request instance
*
* @api
*/
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
{
@@ -328,7 +311,7 @@ class Request
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'HTTP_HOST' => 'localhost',
'HTTP_USER_AGENT' => 'Symfony/2.X',
'HTTP_USER_AGENT' => 'Symfony/3.X',
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5',
'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
@@ -439,8 +422,6 @@ class Request
* @param array $server The SERVER parameters
*
* @return Request The duplicated request
*
* @api
*/
public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
{
@@ -527,8 +508,6 @@ class Request
*
* It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE.
* $_FILES is never overridden, see rfc1867
*
* @api
*/
public function overrideGlobals()
{
@@ -565,8 +544,6 @@ class Request
* You should only list the reverse proxies that you manage directly.
*
* @param array $proxies A list of trusted proxies
*
* @api
*/
public static function setTrustedProxies(array $proxies)
{
@@ -723,37 +700,30 @@ class Request
}
/**
* Gets a "parameter" value.
* Gets a "parameter" value from any bag.
*
* This method is mainly useful for libraries that want to provide some flexibility.
* This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
* flexibility in controllers, it is better to explicitly get request parameters from the appropriate
* public property instead (attributes, query, request).
*
* Order of precedence: GET, PATH, POST
*
* Avoid using this method in controllers:
*
* * slow
* * prefer to get from a "named" source
*
* It is better to explicitly get request parameters from the appropriate
* public property instead (query, attributes, request).
* Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY
*
* @param string $key the key
* @param mixed $default the default value
* @param bool $deep is parameter deep in multidimensional array
* @param mixed $default the default value if the parameter key does not exist
*
* @return mixed
*/
public function get($key, $default = null, $deep = false)
public function get($key, $default = null)
{
if ($this !== $result = $this->query->get($key, $this, $deep)) {
if ($this !== $result = $this->attributes->get($key, $this)) {
return $result;
}
if ($this !== $result = $this->attributes->get($key, $this, $deep)) {
if ($this !== $result = $this->query->get($key, $this)) {
return $result;
}
if ($this !== $result = $this->request->get($key, $this, $deep)) {
if ($this !== $result = $this->request->get($key, $this)) {
return $result;
}
@@ -764,8 +734,6 @@ class Request
* Gets the Session.
*
* @return SessionInterface|null The session
*
* @api
*/
public function getSession()
{
@@ -777,8 +745,6 @@ class Request
* previous requests.
*
* @return bool
*
* @api
*/
public function hasPreviousSession()
{
@@ -794,8 +760,6 @@ class Request
* is associated with a Session instance.
*
* @return bool true when the Request contains a Session object, false otherwise
*
* @api
*/
public function hasSession()
{
@@ -806,8 +770,6 @@ class Request
* Sets the Session.
*
* @param SessionInterface $session The Session
*
* @api
*/
public function setSession(SessionInterface $session)
{
@@ -829,35 +791,48 @@ class Request
*/
public function getClientIps()
{
$clientIps = array();
$ip = $this->server->get('REMOTE_ADDR');
if (!$this->isFromTrustedProxy()) {
return array($ip);
}
if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
return array($ip);
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
$forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
$clientIps = $matches[3];
} elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
}
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
$firstTrustedIp = null;
$ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies
// Eliminate all IPs from the forwarded IP chain which are trusted proxies
foreach ($clientIps as $key => $clientIp) {
// Remove port on IPv4 address (unfortunately, it does happen)
// Remove port (unfortunately, it does happen)
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
$clientIps[$key] = $clientIp = $match[1];
}
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
unset($clientIps[$key]);
continue;
}
if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
unset($clientIps[$key]);
// Fallback to this when the client IP falls into the range of trusted proxies
if (null === $firstTrustedIp) {
$firstTrustedIp = $clientIp;
}
}
}
// Now the IP chain contains only untrusted proxies and the client IP
return $clientIps ? array_reverse($clientIps) : array($ip);
return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
}
/**
@@ -877,8 +852,6 @@ class Request
*
* @see getClientIps()
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
*
* @api
*/
public function getClientIp()
{
@@ -891,8 +864,6 @@ class Request
* Returns current script name.
*
* @return string
*
* @api
*/
public function getScriptName()
{
@@ -912,8 +883,6 @@ class Request
* * http://localhost/mysite/about?var=1 returns '/about'
*
* @return string The raw path (i.e. not urldecoded)
*
* @api
*/
public function getPathInfo()
{
@@ -935,8 +904,6 @@ class Request
* * http://localhost/we%20b/index.php returns '/we%20b'
*
* @return string The raw path (i.e. not urldecoded)
*
* @api
*/
public function getBasePath()
{
@@ -956,8 +923,6 @@ class Request
* script filename (e.g. index.php) if one exists.
*
* @return string The raw URL (i.e. not urldecoded)
*
* @api
*/
public function getBaseUrl()
{
@@ -972,8 +937,6 @@ class Request
* Gets the request's scheme.
*
* @return string
*
* @api
*/
public function getScheme()
{
@@ -992,8 +955,6 @@ class Request
* configure it via "setTrustedHeaderName()" with the "client-port" key.
*
* @return string
*
* @api
*/
public function getPort()
{
@@ -1067,8 +1028,6 @@ class Request
* The port name will be appended to the host if it's non-standard.
*
* @return string
*
* @api
*/
public function getHttpHost()
{
@@ -1086,8 +1045,6 @@ class Request
* Returns the requested URI (path and query string).
*
* @return string The raw URI (i.e. not URI decoded)
*
* @api
*/
public function getRequestUri()
{
@@ -1117,8 +1074,6 @@ class Request
* @return string A normalized URI (URL) for the Request
*
* @see getQueryString()
*
* @api
*/
public function getUri()
{
@@ -1135,14 +1090,67 @@ class Request
* @param string $path A path to use instead of the current one
*
* @return string The normalized URI for the path
*
* @api
*/
public function getUriForPath($path)
{
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
}
/**
* Returns the path as relative reference from the current Request path.
*
* Only the URIs path component (no schema, host etc.) is relevant and must be given.
* Both paths must be absolute and not contain relative parts.
* Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
* Furthermore, they can be used to reduce the link size in documents.
*
* Example target paths, given a base path of "/a/b/c/d":
* - "/a/b/c/d" -> ""
* - "/a/b/c/" -> "./"
* - "/a/b/" -> "../"
* - "/a/b/c/other" -> "other"
* - "/a/x/y" -> "../../x/y"
*
* @param string $path The target path
*
* @return string The relative target path
*/
public function getRelativeUriForPath($path)
{
// be sure that we are dealing with an absolute path
if (!isset($path[0]) || '/' !== $path[0]) {
return $path;
}
if ($path === $basePath = $this->getPathInfo()) {
return '';
}
$sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
$targetDirs = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
array_pop($sourceDirs);
$targetFile = array_pop($targetDirs);
foreach ($sourceDirs as $i => $dir) {
if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
unset($sourceDirs[$i], $targetDirs[$i]);
} else {
break;
}
}
$targetDirs[] = $targetFile;
$path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
// A reference to the same base directory or an empty subdirectory must be prefixed with "./".
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
// as the first segment of a relative-path reference, as it would be mistaken for a scheme name
// (see http://tools.ietf.org/html/rfc3986#section-4.2).
return !isset($path[0]) || '/' === $path[0]
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
? "./$path" : $path;
}
/**
* Generates the normalized query string for the Request.
*
@@ -1150,8 +1158,6 @@ class Request
* and have consistent escaping.
*
* @return string|null A normalized query string for the Request
*
* @api
*/
public function getQueryString()
{
@@ -1163,7 +1169,7 @@ class Request
/**
* Checks whether the request is secure or not.
*
* This method can read the client port from the "X-Forwarded-Proto" header
* This method can read the client protocol from the "X-Forwarded-Proto" header
* when trusted proxies were set via "setTrustedProxies()".
*
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
@@ -1173,8 +1179,6 @@ class Request
* the "client-proto" key.
*
* @return bool
*
* @api
*/
public function isSecure()
{
@@ -1190,7 +1194,7 @@ class Request
/**
* Returns the host name.
*
* This method can read the client port from the "X-Forwarded-Host" header
* This method can read the client host name from the "X-Forwarded-Host" header
* when trusted proxies were set via "setTrustedProxies()".
*
* The "X-Forwarded-Host" header must contain the client host name.
@@ -1201,8 +1205,6 @@ class Request
* @return string
*
* @throws \UnexpectedValueException when the host name is invalid
*
* @api
*/
public function getHost()
{
@@ -1252,8 +1254,6 @@ class Request
* Sets the request method.
*
* @param string $method
*
* @api
*/
public function setMethod($method)
{
@@ -1274,8 +1274,6 @@ class Request
*
* @return string The request method
*
* @api
*
* @see getRealMethod()
*/
public function getMethod()
@@ -1313,8 +1311,6 @@ class Request
* @param string $format The format
*
* @return string The associated mime type (null if not found)
*
* @api
*/
public function getMimeType($format)
{
@@ -1331,13 +1327,12 @@ class Request
* @param string $mimeType The associated mime type
*
* @return string|null The format (null if not found)
*
* @api
*/
public function getFormat($mimeType)
{
$canonicalMimeType = null;
if (false !== $pos = strpos($mimeType, ';')) {
$mimeType = substr($mimeType, 0, $pos);
$canonicalMimeType = substr($mimeType, 0, $pos);
}
if (null === static::$formats) {
@@ -1348,6 +1343,9 @@ class Request
if (in_array($mimeType, (array) $mimeTypes)) {
return $format;
}
if (null !== $canonicalMimeType && in_array($canonicalMimeType, (array) $mimeTypes)) {
return $format;
}
}
}
@@ -1356,8 +1354,6 @@ class Request
*
* @param string $format The format
* @param string|array $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type)
*
* @api
*/
public function setFormat($format, $mimeTypes)
{
@@ -1374,19 +1370,17 @@ class Request
* Here is the process to determine the format:
*
* * format defined by the user (with setRequestFormat())
* * _format request parameter
* * _format request attribute
* * $default
*
* @param string $default The default format
*
* @return string The request format
*
* @api
*/
public function getRequestFormat($default = 'html')
{
if (null === $this->format) {
$this->format = $this->get('_format', $default);
$this->format = $this->attributes->get('_format', $default);
}
return $this->format;
@@ -1396,8 +1390,6 @@ class Request
* Sets the request format.
*
* @param string $format The request format.
*
* @api
*/
public function setRequestFormat($format)
{
@@ -1408,8 +1400,6 @@ class Request
* Gets the format associated with the request.
*
* @return string|null The format (null if no content type is present)
*
* @api
*/
public function getContentType()
{
@@ -1420,8 +1410,6 @@ class Request
* Sets the default locale.
*
* @param string $locale
*
* @api
*/
public function setDefaultLocale($locale)
{
@@ -1446,8 +1434,6 @@ class Request
* Sets the locale.
*
* @param string $locale
*
* @api
*/
public function setLocale($locale)
{
@@ -1480,8 +1466,6 @@ class Request
* Checks whether the method is safe or not.
*
* @return bool
*
* @api
*/
public function isMethodSafe()
{
@@ -1513,7 +1497,7 @@ class Request
// Content passed in parameter (test)
if (is_string($this->content)) {
$resource = fopen('php://temp','r+');
$resource = fopen('php://temp', 'r+');
fwrite($resource, $this->content);
rewind($resource);
@@ -1562,8 +1546,6 @@ class Request
* @param array $locales An array of ordered available locales
*
* @return string|null The preferred locale
*
* @api
*/
public function getPreferredLanguage(array $locales = null)
{
@@ -1597,8 +1579,6 @@ class Request
* Gets a list of languages acceptable by the client browser.
*
* @return array Languages ordered in the user browser preferences
*
* @api
*/
public function getLanguages()
{
@@ -1639,8 +1619,6 @@ class Request
* Gets a list of charsets acceptable by the client browser.
*
* @return array List of charsets in preferable order
*
* @api
*/
public function getCharsets()
{
@@ -1669,8 +1647,6 @@ class Request
* Gets a list of content types acceptable by the client browser.
*
* @return array List of content types in preferable order
*
* @api
*/
public function getAcceptableContentTypes()
{
@@ -1690,8 +1666,6 @@ class Request
* @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
*
* @return bool true if the request is an XMLHttpRequest, false otherwise
*
* @api
*/
public function isXmlHttpRequest()
{
@@ -1788,9 +1762,9 @@ class Request
return $prefix;
}
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/').'/')) {
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/'.DIRECTORY_SEPARATOR).'/')) {
// directory portion of $baseUrl matches
return rtrim($prefix, '/');
return rtrim($prefix, '/'.DIRECTORY_SEPARATOR);
}
$truncatedRequestUri = $requestUri;
@@ -1811,7 +1785,7 @@ class Request
$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
}
return rtrim($baseUrl, '/');
return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR);
}
/**
@@ -1853,8 +1827,6 @@ class Request
return '/';
}
$pathInfo = '/';
// Remove the query string from REQUEST_URI
if ($pos = strpos($requestUri, '?')) {
$requestUri = substr($requestUri, 0, $pos);
@@ -1937,7 +1909,7 @@ class Request
if (self::$requestFactory) {
$request = call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
if (!$request instanceof Request) {
if (!$request instanceof self) {
throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
}

View File

@@ -15,8 +15,6 @@ 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
{
@@ -144,8 +142,6 @@ class RequestMatcher implements RequestMatcherInterface
/**
* {@inheritdoc}
*
* @api
*/
public function matches(Request $request)
{

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* RequestMatcherInterface is an interface for strategies to match a Request.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
interface RequestMatcherInterface
{
@@ -26,8 +24,6 @@ interface RequestMatcherInterface
* @param Request $request The request to check for a match
*
* @return bool true if the request matches, false otherwise
*
* @api
*/
public function matches(Request $request);
}

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* Response represents an HTTP response.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class Response
{
@@ -61,6 +59,7 @@ class Response
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;
const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
const HTTP_LOCKED = 423; // RFC4918
const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
@@ -69,6 +68,7 @@ class Response
const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
const HTTP_INTERNAL_SERVER_ERROR = 500;
const HTTP_NOT_IMPLEMENTED = 501;
const HTTP_BAD_GATEWAY = 502;
@@ -116,7 +116,7 @@ class Response
*
* The list of codes is complete according to the
* {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}
* (last updated 2012-02-13).
* (last updated 2016-03-01).
*
* Unless otherwise noted, the status code is defined in RFC2616.
*
@@ -142,7 +142,6 @@ class Response
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
306 => 'Reserved',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect', // RFC7238
400 => 'Bad Request',
@@ -158,12 +157,13 @@ class Response
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
413 => 'Payload Too Large',
414 => 'URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot', // RFC2324
421 => 'Misdirected Request', // RFC7540
422 => 'Unprocessable Entity', // RFC4918
423 => 'Locked', // RFC4918
424 => 'Failed Dependency', // RFC4918
@@ -172,6 +172,7 @@ class Response
428 => 'Precondition Required', // RFC6585
429 => 'Too Many Requests', // RFC6585
431 => 'Request Header Fields Too Large', // RFC6585
451 => 'Unavailable For Legal Reasons', // RFC7725
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
@@ -193,8 +194,6 @@ class Response
* @param array $headers An array of response headers
*
* @throws \InvalidArgumentException When the HTTP status code is not valid
*
* @api
*/
public function __construct($content = '', $status = 200, $headers = array())
{
@@ -202,9 +201,6 @@ class Response
$this->setContent($content);
$this->setStatusCode($status);
$this->setProtocolVersion('1.0');
if (!$this->headers->has('Date')) {
$this->setDate(new \DateTime(null, new \DateTimeZone('UTC')));
}
}
/**
@@ -333,8 +329,9 @@ class Response
return $this;
}
// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
if (!$this->headers->has('Date')) {
$this->setDate(\DateTime::createFromFormat('U', time()));
}
// headers
foreach ($this->headers->allPreserveCase() as $name => $values) {
@@ -343,6 +340,9 @@ class Response
}
}
// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
// cookies
foreach ($this->headers->getCookies() as $cookie) {
setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
@@ -367,8 +367,6 @@ class Response
* Sends HTTP headers and content.
*
* @return Response
*
* @api
*/
public function send()
{
@@ -394,8 +392,6 @@ class Response
* @return Response
*
* @throws \UnexpectedValueException
*
* @api
*/
public function setContent($content)
{
@@ -412,8 +408,6 @@ class Response
* Gets the current response content.
*
* @return string Content
*
* @api
*/
public function getContent()
{
@@ -426,8 +420,6 @@ class Response
* @param string $version The HTTP protocol version
*
* @return Response
*
* @api
*/
public function setProtocolVersion($version)
{
@@ -440,8 +432,6 @@ class Response
* Gets the HTTP protocol version.
*
* @return string The HTTP protocol version
*
* @api
*/
public function getProtocolVersion()
{
@@ -460,8 +450,6 @@ class Response
* @return Response
*
* @throws \InvalidArgumentException When the HTTP status code is not valid
*
* @api
*/
public function setStatusCode($code, $text = null)
{
@@ -471,7 +459,7 @@ class Response
}
if (null === $text) {
$this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : '';
$this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status';
return $this;
}
@@ -491,8 +479,6 @@ class Response
* Retrieves the status code for the current web response.
*
* @return int Status code
*
* @api
*/
public function getStatusCode()
{
@@ -505,8 +491,6 @@ class Response
* @param string $charset Character set
*
* @return Response
*
* @api
*/
public function setCharset($charset)
{
@@ -519,8 +503,6 @@ class Response
* Retrieves the response charset.
*
* @return string Character set
*
* @api
*/
public function getCharset()
{
@@ -537,8 +519,6 @@ class Response
* validator (Last-Modified, ETag) are considered uncacheable.
*
* @return bool true if the response is worth caching, false otherwise
*
* @api
*/
public function isCacheable()
{
@@ -561,8 +541,6 @@ class Response
* indicator or Expires header and the calculated age is less than the freshness lifetime.
*
* @return bool true if the response is fresh, false otherwise
*
* @api
*/
public function isFresh()
{
@@ -574,8 +552,6 @@ class Response
* the response with the origin server using a conditional GET request.
*
* @return bool true if the response is validateable, false otherwise
*
* @api
*/
public function isValidateable()
{
@@ -588,8 +564,6 @@ class Response
* It makes the response ineligible for serving other clients.
*
* @return Response
*
* @api
*/
public function setPrivate()
{
@@ -605,8 +579,6 @@ class Response
* It makes the response eligible for serving other clients.
*
* @return Response
*
* @api
*/
public function setPublic()
{
@@ -625,12 +597,10 @@ class Response
* greater than the value provided by the origin.
*
* @return bool true if the response must be revalidated by a cache, false otherwise
*
* @api
*/
public function mustRevalidate()
{
return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->has('proxy-revalidate');
return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate');
}
/**
@@ -639,12 +609,14 @@ class Response
* @return \DateTime A \DateTime instance
*
* @throws \RuntimeException When the header is not parseable
*
* @api
*/
public function getDate()
{
return $this->headers->getDate('Date', new \DateTime());
if (!$this->headers->has('Date')) {
$this->setDate(\DateTime::createFromFormat('U', time()));
}
return $this->headers->getDate('Date');
}
/**
@@ -653,8 +625,6 @@ class Response
* @param \DateTime $date A \DateTime instance
*
* @return Response
*
* @api
*/
public function setDate(\DateTime $date)
{
@@ -682,8 +652,6 @@ class Response
* Marks the response stale by setting the Age header to be equal to the maximum age of the response.
*
* @return Response
*
* @api
*/
public function expire()
{
@@ -698,8 +666,6 @@ class Response
* Returns the value of the Expires header as a DateTime instance.
*
* @return \DateTime|null A DateTime instance or null if the header does not exist
*
* @api
*/
public function getExpires()
{
@@ -719,8 +685,6 @@ class Response
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return Response
*
* @api
*/
public function setExpires(\DateTime $date = null)
{
@@ -743,8 +707,6 @@ class Response
* back on an expires header. It returns null when no maximum age can be established.
*
* @return int|null Number of seconds
*
* @api
*/
public function getMaxAge()
{
@@ -769,8 +731,6 @@ class Response
* @param int $value Number of seconds
*
* @return Response
*
* @api
*/
public function setMaxAge($value)
{
@@ -787,8 +747,6 @@ class Response
* @param int $value Number of seconds
*
* @return Response
*
* @api
*/
public function setSharedMaxAge($value)
{
@@ -807,8 +765,6 @@ class Response
* revalidating with the origin.
*
* @return int|null The TTL in seconds
*
* @api
*/
public function getTtl()
{
@@ -825,8 +781,6 @@ class Response
* @param int $seconds Number of seconds
*
* @return Response
*
* @api
*/
public function setTtl($seconds)
{
@@ -843,8 +797,6 @@ class Response
* @param int $seconds Number of seconds
*
* @return Response
*
* @api
*/
public function setClientTtl($seconds)
{
@@ -859,8 +811,6 @@ class Response
* @return \DateTime|null A DateTime instance or null if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*
* @api
*/
public function getLastModified()
{
@@ -875,8 +825,6 @@ class Response
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return Response
*
* @api
*/
public function setLastModified(\DateTime $date = null)
{
@@ -895,8 +843,6 @@ class Response
* Returns the literal value of the ETag HTTP header.
*
* @return string|null The ETag HTTP header or null if it does not exist
*
* @api
*/
public function getEtag()
{
@@ -910,8 +856,6 @@ class Response
* @param bool $weak Whether you want a weak ETag or not
*
* @return Response
*
* @api
*/
public function setEtag($etag = null, $weak = false)
{
@@ -938,8 +882,6 @@ class Response
* @return Response
*
* @throws \InvalidArgumentException
*
* @api
*/
public function setCache(array $options)
{
@@ -991,8 +933,6 @@ class Response
* @return Response
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3.5
*
* @api
*/
public function setNotModified()
{
@@ -1011,8 +951,6 @@ class Response
* Returns true if the response includes a Vary header.
*
* @return bool true if the response includes a Vary header, false otherwise
*
* @api
*/
public function hasVary()
{
@@ -1023,8 +961,6 @@ class Response
* Returns an array of header names given in the Vary header.
*
* @return array An array of Vary names
*
* @api
*/
public function getVary()
{
@@ -1044,11 +980,9 @@ class Response
* Sets the Vary header.
*
* @param string|array $headers
* @param bool $replace Whether to replace the actual value of not (true by default)
* @param bool $replace Whether to replace the actual value or not (true by default)
*
* @return Response
*
* @api
*/
public function setVary($headers, $replace = true)
{
@@ -1067,8 +1001,6 @@ class Response
* @param Request $request A Request instance
*
* @return bool true if the Response validators match the Request, false otherwise
*
* @api
*/
public function isNotModified(Request $request)
{
@@ -1095,13 +1027,12 @@ class Response
return $notModified;
}
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
/**
* Is response invalid?
*
* @return bool
*
* @api
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*/
public function isInvalid()
{
@@ -1112,8 +1043,6 @@ class Response
* Is response informative?
*
* @return bool
*
* @api
*/
public function isInformational()
{
@@ -1124,8 +1053,6 @@ class Response
* Is response successful?
*
* @return bool
*
* @api
*/
public function isSuccessful()
{
@@ -1136,8 +1063,6 @@ class Response
* Is the response a redirect?
*
* @return bool
*
* @api
*/
public function isRedirection()
{
@@ -1148,8 +1073,6 @@ class Response
* Is there a client error?
*
* @return bool
*
* @api
*/
public function isClientError()
{
@@ -1160,8 +1083,6 @@ class Response
* Was there a server side error?
*
* @return bool
*
* @api
*/
public function isServerError()
{
@@ -1172,8 +1093,6 @@ class Response
* Is the response OK?
*
* @return bool
*
* @api
*/
public function isOk()
{
@@ -1184,8 +1103,6 @@ class Response
* Is the response forbidden?
*
* @return bool
*
* @api
*/
public function isForbidden()
{
@@ -1196,8 +1113,6 @@ class Response
* Is the response a not found error?
*
* @return bool
*
* @api
*/
public function isNotFound()
{
@@ -1210,8 +1125,6 @@ class Response
* @param string $location
*
* @return bool
*
* @api
*/
public function isRedirect($location = null)
{
@@ -1222,8 +1135,6 @@ class Response
* Is the response empty?
*
* @return bool
*
* @api
*/
public function isEmpty()
{
@@ -1242,6 +1153,7 @@ class Response
{
$status = ob_get_status(true);
$level = count($status);
// PHP_OUTPUT_HANDLER_* are not defined on HHVM 3.3
$flags = defined('PHP_OUTPUT_HANDLER_REMOVABLE') ? PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE) : -1;
while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || $flags === ($s['flags'] & $flags) : $s['del'])) {

View File

@@ -15,8 +15,6 @@ namespace Symfony\Component\HttpFoundation;
* ResponseHeaderBag is a container for Response HTTP headers.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class ResponseHeaderBag extends HeaderBag
{
@@ -45,8 +43,6 @@ class ResponseHeaderBag extends HeaderBag
* Constructor.
*
* @param array $headers An array of HTTP headers
*
* @api
*/
public function __construct(array $headers = array())
{
@@ -84,8 +80,6 @@ class ResponseHeaderBag extends HeaderBag
/**
* {@inheritdoc}
*
* @api
*/
public function replace(array $headers = array())
{
@@ -100,14 +94,12 @@ class ResponseHeaderBag extends HeaderBag
/**
* {@inheritdoc}
*
* @api
*/
public function set($key, $values, $replace = true)
{
parent::set($key, $values, $replace);
$uniqueKey = strtr(strtolower($key), '_', '-');
$uniqueKey = str_replace('_', '-', strtolower($key));
$this->headerNames[$uniqueKey] = $key;
// ensure the cache-control header has sensible defaults
@@ -121,14 +113,12 @@ class ResponseHeaderBag extends HeaderBag
/**
* {@inheritdoc}
*
* @api
*/
public function remove($key)
{
parent::remove($key);
$uniqueKey = strtr(strtolower($key), '_', '-');
$uniqueKey = str_replace('_', '-', strtolower($key));
unset($this->headerNames[$uniqueKey]);
if ('cache-control' === $uniqueKey) {
@@ -156,8 +146,6 @@ class ResponseHeaderBag extends HeaderBag
* Sets a cookie.
*
* @param Cookie $cookie
*
* @api
*/
public function setCookie(Cookie $cookie)
{
@@ -170,8 +158,6 @@ class ResponseHeaderBag extends HeaderBag
* @param string $name
* @param string $path
* @param string $domain
*
* @api
*/
public function removeCookie($name, $path = '/', $domain = null)
{
@@ -195,11 +181,9 @@ class ResponseHeaderBag extends HeaderBag
*
* @param string $format
*
* @throws \InvalidArgumentException When the $format is invalid
*
* @return array
*
* @api
* @throws \InvalidArgumentException When the $format is invalid
*/
public function getCookies($format = self::COOKIES_FLAT)
{
@@ -231,8 +215,6 @@ class ResponseHeaderBag extends HeaderBag
* @param string $domain
* @param bool $secure
* @param bool $httpOnly
*
* @api
*/
public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true)
{

View File

@@ -86,6 +86,10 @@ class ServerBag extends ParameterBag
}
}
if (isset($headers['AUTHORIZATION'])) {
return $headers;
}
// 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']);

View File

@@ -14,11 +14,9 @@ namespace Symfony\Component\HttpFoundation\Session\Flash;
/**
* FlashBag flash message container.
*
* \IteratorAggregate implementation is deprecated and will be removed in 3.0.
*
* @author Drak <drak@zikula.org>
*/
class FlashBag implements FlashBagInterface, \IteratorAggregate
class FlashBag implements FlashBagInterface
{
private $name = 'flashes';
@@ -165,16 +163,4 @@ class FlashBag implements FlashBagInterface, \IteratorAggregate
{
return $this->all();
}
/**
* Returns an iterator for flashes.
*
* @deprecated Will be removed in 3.0.
*
* @return \ArrayIterator An \ArrayIterator instance
*/
public function getIterator()
{
return new \ArrayIterator($this->all());
}
}

View File

@@ -23,8 +23,6 @@ use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Drak <drak@zikula.org>
*
* @api
*/
class Session implements SessionInterface, \IteratorAggregate, \Countable
{

View File

@@ -26,8 +26,6 @@ interface SessionInterface
* @return bool True if session started.
*
* @throws \RuntimeException If session fails to start.
*
* @api
*/
public function start();
@@ -35,8 +33,6 @@ interface SessionInterface
* Returns the session ID.
*
* @return string The session ID.
*
* @api
*/
public function getId();
@@ -44,8 +40,6 @@ interface SessionInterface
* Sets the session ID.
*
* @param string $id
*
* @api
*/
public function setId($id);
@@ -53,8 +47,6 @@ interface SessionInterface
* Returns the session name.
*
* @return mixed The session name.
*
* @api
*/
public function getName();
@@ -62,8 +54,6 @@ interface SessionInterface
* Sets the session name.
*
* @param string $name
*
* @api
*/
public function setName($name);
@@ -79,8 +69,6 @@ interface SessionInterface
* not a Unix timestamp.
*
* @return bool True if session invalidated, false if error.
*
* @api
*/
public function invalidate($lifetime = null);
@@ -95,8 +83,6 @@ interface SessionInterface
* not a Unix timestamp.
*
* @return bool True if session migrated, false if error.
*
* @api
*/
public function migrate($destroy = false, $lifetime = null);
@@ -115,8 +101,6 @@ interface SessionInterface
* @param string $name The attribute name
*
* @return bool true if the attribute is defined, false otherwise
*
* @api
*/
public function has($name);
@@ -127,8 +111,6 @@ interface SessionInterface
* @param mixed $default The default value if not found.
*
* @return mixed
*
* @api
*/
public function get($name, $default = null);
@@ -137,8 +119,6 @@ interface SessionInterface
*
* @param string $name
* @param mixed $value
*
* @api
*/
public function set($name, $value);
@@ -146,8 +126,6 @@ interface SessionInterface
* Returns attributes.
*
* @return array Attributes
*
* @api
*/
public function all();
@@ -164,15 +142,11 @@ interface SessionInterface
* @param string $name
*
* @return mixed The removed value or null when it does not exist
*
* @api
*/
public function remove($name);
/**
* Clears all attributes.
*
* @api
*/
public function clear();

View File

@@ -108,7 +108,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface
}
/**
* Return a Memcache instance
* Return a Memcache instance.
*
* @return \Memcache
*/

View File

@@ -114,7 +114,7 @@ class MemcachedSessionHandler implements \SessionHandlerInterface
}
/**
* Return a Memcached instance
* Return a Memcached instance.
*
* @return \Memcached
*/

View File

@@ -177,7 +177,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
}
/**
* Return a Mongo instance
* Return a Mongo instance.
*
* @return \Mongo
*/

View File

@@ -48,8 +48,8 @@ class NativeFileSessionHandler extends NativeSessionHandler
$baseDir = ltrim(strrchr($savePath, ';'), ';');
}
if ($baseDir && !is_dir($baseDir)) {
mkdir($baseDir, 0777, true);
if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) {
throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s"', $baseDir));
}
ini_set('session.save_path', $savePath);

View File

@@ -11,14 +11,11 @@
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
// Adds SessionHandler functionality if available.
// @see http://php.net/sessionhandler
if (PHP_VERSION_ID >= 50400) {
class NativeSessionHandler extends \SessionHandler
{
}
} else {
class NativeSessionHandler
{
}
/**
* Adds SessionHandler functionality if available.
*
* @see http://php.net/sessionhandler
*/
class NativeSessionHandler extends \SessionHandler
{
}

View File

@@ -17,8 +17,6 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
* 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
{

View File

@@ -42,8 +42,8 @@ class MockFileSessionStorage extends MockArraySessionStorage
$savePath = sys_get_temp_dir();
}
if (!is_dir($savePath)) {
mkdir($savePath, 0777, true);
if (!is_dir($savePath) && !@mkdir($savePath, 0777, true) && !is_dir($savePath)) {
throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s"', $savePath));
}
$this->savePath = $savePath;

View File

@@ -13,7 +13,6 @@ namespace Symfony\Component\HttpFoundation\Session\Storage;
use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
@@ -65,7 +64,7 @@ class NativeSessionStorage implements SessionStorageInterface
* ("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).
* cache_limiter, "" (use "0" to prevent headers from being sent entirely).
* cookie_domain, ""
* cookie_httponly, ""
* cookie_lifetime, "0"
@@ -101,11 +100,7 @@ class NativeSessionStorage implements SessionStorageInterface
session_cache_limiter(''); // disable by default because it's managed by HeaderBag (if used)
ini_set('session.use_cookies', 1);
if (PHP_VERSION_ID >= 50400) {
session_register_shutdown();
} else {
register_shutdown_function('session_write_close');
}
session_register_shutdown();
$this->setMetadataBag($metaBag);
$this->setOptions($options);
@@ -131,15 +126,10 @@ class NativeSessionStorage implements SessionStorageInterface
return true;
}
if (PHP_VERSION_ID >= 50400 && \PHP_SESSION_ACTIVE === session_status()) {
if (\PHP_SESSION_ACTIVE === session_status()) {
throw new \RuntimeException('Failed to start the session: already started by PHP.');
}
if (PHP_VERSION_ID < 50400 && !$this->closed && isset($_SESSION) && session_id()) {
// not 100% fool-proof, but is the most reliable way to determine if a session is active in PHP 5.3
throw new \RuntimeException('Failed to start the session: already started by PHP ($_SESSION is set).');
}
if (ini_get('session.use_cookies') && headers_sent($file, $line)) {
throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
}
@@ -150,10 +140,6 @@ class NativeSessionStorage implements SessionStorageInterface
}
$this->loadSession();
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
// This condition matches only PHP 5.3 with internal save handlers
$this->saveHandler->setActive(true);
}
return true;
}
@@ -195,6 +181,11 @@ class NativeSessionStorage implements SessionStorageInterface
*/
public function regenerate($destroy = false, $lifetime = null)
{
// Cannot regenerate the session ID for non-active sessions.
if (\PHP_SESSION_ACTIVE !== session_status()) {
return false;
}
if (null !== $lifetime) {
ini_set('session.cookie_lifetime', $lifetime);
}
@@ -219,11 +210,6 @@ class NativeSessionStorage implements SessionStorageInterface
{
session_write_close();
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
// This condition matches only PHP 5.3 with internal save handlers
$this->saveHandler->setActive(false);
}
$this->closed = true;
$this->started = false;
}
@@ -250,6 +236,10 @@ class NativeSessionStorage implements SessionStorageInterface
*/
public function registerBag(SessionBagInterface $bag)
{
if ($this->started) {
throw new \LogicException('Cannot register a bag when the session is already started.');
}
$this->bags[$bag->getName()] = $bag;
}
@@ -341,7 +331,7 @@ class NativeSessionStorage implements SessionStorageInterface
* session.save_handler and session.save_path e.g.
*
* ini_set('session.save_handler', 'files');
* ini_set('session.save_path', /tmp');
* ini_set('session.save_path', '/tmp');
*
* or pass in a NativeSessionHandler instance which configures session.save_handler in the
* constructor, for a template see NativeFileSessionHandler or use handlers in
@@ -369,24 +359,12 @@ class NativeSessionStorage implements SessionStorageInterface
if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) {
$saveHandler = new SessionHandlerProxy($saveHandler);
} elseif (!$saveHandler instanceof AbstractProxy) {
$saveHandler = PHP_VERSION_ID >= 50400 ?
new SessionHandlerProxy(new \SessionHandler()) : new NativeProxy();
$saveHandler = new SessionHandlerProxy(new \SessionHandler());
}
$this->saveHandler = $saveHandler;
if ($this->saveHandler instanceof \SessionHandlerInterface) {
if (PHP_VERSION_ID >= 50400) {
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')
);
}
session_set_save_handler($this->saveHandler, false);
}
}

View File

@@ -43,10 +43,6 @@ class PhpBridgeSessionStorage extends NativeSessionStorage
}
$this->loadSession();
if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) {
// This condition matches only PHP 5.3 + internal save handlers
$this->saveHandler->setActive(true);
}
return true;
}

View File

@@ -25,11 +25,6 @@ abstract class AbstractProxy
*/
protected $wrapper = false;
/**
* @var bool
*/
protected $active = false;
/**
* @var string
*/
@@ -52,7 +47,7 @@ abstract class AbstractProxy
*/
public function isSessionHandlerInterface()
{
return ($this instanceof \SessionHandlerInterface);
return $this instanceof \SessionHandlerInterface;
}
/**
@@ -72,32 +67,7 @@ abstract class AbstractProxy
*/
public function isActive()
{
if (PHP_VERSION_ID >= 50400) {
return $this->active = \PHP_SESSION_ACTIVE === session_status();
}
return $this->active;
}
/**
* Sets the active flag.
*
* Has no effect under PHP 5.4+ as status is detected
* automatically in isActive()
*
* @internal
*
* @param bool $flag
*
* @throws \LogicException
*/
public function setActive($flag)
{
if (PHP_VERSION_ID >= 50400) {
throw new \LogicException('This method is disabled in PHP 5.4.0+');
}
$this->active = (bool) $flag;
return \PHP_SESSION_ACTIVE === session_status();
}
/**

View File

@@ -42,13 +42,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
*/
public function open($savePath, $sessionName)
{
$return = (bool) $this->handler->open($savePath, $sessionName);
if (true === $return) {
$this->active = true;
}
return $return;
return (bool) $this->handler->open($savePath, $sessionName);
}
/**
@@ -56,8 +50,6 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
*/
public function close()
{
$this->active = false;
return (bool) $this->handler->close();
}

View File

@@ -18,19 +18,15 @@ use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
*
* @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 bool True if started.
*
* @api
* @throws \RuntimeException If something goes wrong starting the session.
*/
public function start();
@@ -45,8 +41,6 @@ interface SessionStorageInterface
* Returns the session ID.
*
* @return string The session ID or empty.
*
* @api
*/
public function getId();
@@ -54,8 +48,6 @@ interface SessionStorageInterface
* Sets the session ID.
*
* @param string $id
*
* @api
*/
public function setId($id);
@@ -63,8 +55,6 @@ interface SessionStorageInterface
* Returns the session name.
*
* @return mixed The session name.
*
* @api
*/
public function getName();
@@ -72,8 +62,6 @@ interface SessionStorageInterface
* Sets the session name.
*
* @param string $name
*
* @api
*/
public function setName($name);
@@ -88,10 +76,10 @@ interface SessionStorageInterface
* Note regenerate+destroy should not clear the session data in memory
* only delete the session data from persistent storage.
*
* Care: When regenerating the session ID no locking is involved in PHPs
* Care: When regenerating the session ID no locking is involved in PHP's
* session design. See https://bugs.php.net/bug.php?id=61470 for a discussion.
* So you must make sure the regenerated session is saved BEFORE sending the
* headers with the new ID. Symfonys HttpKernel offers a listener for this.
* headers with the new ID. Symfony's HttpKernel offers a listener for this.
* See Symfony\Component\HttpKernel\EventListener\SaveSessionListener.
* Otherwise session data could get lost again for concurrent requests with the
* new ID. One result could be that you get logged out after just logging in.
@@ -105,8 +93,6 @@ interface SessionStorageInterface
* @return bool 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);
@@ -115,7 +101,7 @@ interface SessionStorageInterface
*
* 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
* a real PHP session would interfere with testing, in which case
* it should actually persist the session data if required.
*
* @throws \RuntimeException If the session is saved without being started, or if the session

View File

@@ -23,8 +23,6 @@ namespace Symfony\Component\HttpFoundation;
* @see flush()
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @api
*/
class StreamedResponse extends Response
{
@@ -37,10 +35,8 @@ class StreamedResponse extends Response
* @param callable|null $callback A valid PHP callback or null to set it later
* @param int $status The response status code
* @param array $headers An array of response headers
*
* @api
*/
public function __construct($callback = null, $status = 200, $headers = array())
public function __construct(callable $callback = null, $status = 200, $headers = array())
{
parent::__construct(null, $status, $headers);
@@ -51,7 +47,7 @@ class StreamedResponse extends Response
}
/**
* Factory method for chainability
* Factory method for chainability.
*
* @param callable|null $callback A valid PHP callback or null to set it later
* @param int $status The response status code
@@ -68,14 +64,9 @@ class StreamedResponse extends Response
* Sets the PHP callback associated with this Response.
*
* @param callable $callback A valid PHP callback
*
* @throws \LogicException
*/
public function setCallback($callback)
public function setCallback(callable $callback)
{
if (!is_callable($callback)) {
throw new \LogicException('The Response callback must be a valid PHP callable.');
}
$this->callback = $callback;
}

View File

@@ -1,56 +0,0 @@
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:
```php
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:
```php
$request = Request::create('/?foo=bar', 'GET');
echo $request->getPathInfo();
```
And here is how to create and send a Response:
```php
$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 not using Composer but are using PHP 5.3.x, you must add the following to your autoloader:
```php
// 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:
$ cd path/to/Symfony/Component/HttpFoundation/
$ composer install
$ phpunit

View File

@@ -1,102 +0,0 @@
<?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 for PHP < 5.4.
*
* The order in which these methods are invoked by PHP are:
* 1. open [session_start]
* 2. read
* 3. gc [optional depending on probability settings: gc_probability / gc_divisor]
* 4. destroy [optional when session_regenerate_id(true) is used]
* 5. write [session_write_close] or destroy [session_destroy]
* 6. close
*
* 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>
* @author Tobias Schultze <http://tobion.de>
*/
interface SessionHandlerInterface
{
/**
* Re-initializes existing session, or creates a new one.
*
* @see http://php.net/sessionhandlerinterface.open
*
* @param string $savePath Save path
* @param string $sessionName Session name, see http://php.net/function.session-name.php
*
* @return bool true on success, false on failure
*/
public function open($savePath, $sessionName);
/**
* Closes the current session.
*
* @see http://php.net/sessionhandlerinterface.close
*
* @return bool true on success, false on failure
*/
public function close();
/**
* Reads the session data.
*
* @see http://php.net/sessionhandlerinterface.read
*
* @param string $sessionId Session ID, see http://php.net/function.session-id
*
* @return string Same session data as passed in write() or empty string when non-existent or on failure
*/
public function read($sessionId);
/**
* Writes the session data to the storage.
*
* Care, the session ID passed to write() can be different from the one previously
* received in read() when the session ID changed due to session_regenerate_id().
*
* @see http://php.net/sessionhandlerinterface.write
*
* @param string $sessionId Session ID , see http://php.net/function.session-id
* @param string $data Serialized session data to save
*
* @return bool true on success, false on failure
*/
public function write($sessionId, $data);
/**
* Destroys a session.
*
* @see http://php.net/sessionhandlerinterface.destroy
*
* @param string $sessionId Session ID, see http://php.net/function.session-id
*
* @return bool true on success, false on failure
*/
public function destroy($sessionId);
/**
* Cleans up expired sessions (garbage collection).
*
* @see http://php.net/sessionhandlerinterface.gc
*
* @param string|int $maxlifetime Sessions that have not updated for the last maxlifetime seconds will be removed
*
* @return bool true on success, false on failure
*/
public function gc($maxlifetime);
}

View File

@@ -1,268 +0,0 @@
<?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;
/**
* Session handler using a PDO connection to read and write data.
*
* Session data is a binary string that can contain non-printable characters like the null byte.
* For this reason this handler base64 encodes the data to be able to save it in a character column.
*
* This version of the PdoSessionHandler does NOT implement locking. So concurrent requests to the
* same session can result in data loss due to race conditions.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Michael Williams <michael.williams@funsational.com>
* @author Tobias Schultze <http://tobion.de>
*
* @deprecated Deprecated since version 2.6, to be removed in 3.0. Use
* {@link PdoSessionHandler} instead.
*/
class LegacyPdoSessionHandler implements \SessionHandlerInterface
{
/**
* @var \PDO PDO instance
*/
private $pdo;
/**
* @var string Table name
*/
private $table;
/**
* @var string Column for session id
*/
private $idCol;
/**
* @var string Column for session data
*/
private $dataCol;
/**
* @var string Column for timestamp
*/
private $timeCol;
/**
* 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.');
}
if (\PDO::ERRMODE_EXCEPTION !== $pdo->getAttribute(\PDO::ATTR_ERRMODE)) {
throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION))', __CLASS__));
}
$this->pdo = $pdo;
$dbOptions = array_merge(array(
'db_id_col' => 'sess_id',
'db_data_col' => 'sess_data',
'db_time_col' => 'sess_time',
), $dbOptions);
$this->table = $dbOptions['db_table'];
$this->idCol = $dbOptions['db_id_col'];
$this->dataCol = $dbOptions['db_data_col'];
$this->timeCol = $dbOptions['db_time_col'];
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
// delete the record associated with this id
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->execute();
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime)
{
// delete the session records that have expired
$sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT);
$stmt->execute();
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
$sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
try {
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$stmt->execute();
// We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
$sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM);
if ($sessionRows) {
return base64_decode($sessionRows[0][0]);
}
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($sessionId, $data)
{
$encoded = base64_encode($data);
try {
// We use a single MERGE SQL query when supported by the database.
$mergeSql = $this->getMergeSql();
if (null !== $mergeSql) {
$mergeStmt = $this->pdo->prepare($mergeSql);
$mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$mergeStmt->execute();
return true;
}
$updateStmt = $this->pdo->prepare(
"UPDATE $this->table SET $this->dataCol = :data, $this->timeCol = :time WHERE $this->idCol = :id"
);
$updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$updateStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$updateStmt->execute();
// When MERGE is not supported, like in Postgres, we have to use this approach that can result in
// duplicate key errors when the same session is written simultaneously. We can just catch such an
// error and re-execute the update. This is similar to a serializable transaction with retry logic
// on serialization failures but without the overhead and without possible false positives due to
// longer gap locking.
if (!$updateStmt->rowCount()) {
try {
$insertStmt = $this->pdo->prepare(
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
);
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
$insertStmt->execute();
} catch (\PDOException $e) {
// Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
if (0 === strpos($e->getCode(), '23')) {
$updateStmt->execute();
} else {
throw $e;
}
}
}
} catch (\PDOException $e) {
throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
}
return true;
}
/**
* Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database.
*
* @return string|null The SQL string or null when not supported
*/
private function getMergeSql()
{
$driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
switch ($driver) {
case 'mysql':
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)";
case 'oci':
// DUAL is Oracle specific dummy table
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ".
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time";
case 'sqlsrv' === $driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
// MERGE is only available since SQL Server 2008 and must be terminated by semicolon
// It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ".
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ".
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time;";
case 'sqlite':
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)";
}
}
/**
* Return a PDO instance
*
* @return \PDO
*/
protected function getConnection()
{
return $this->pdo;
}
}

View File

@@ -1,24 +0,0 @@
<?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;
function time($asFloat = false)
{
return Tests\time();
}
namespace Symfony\Component\HttpFoundation\Tests;
function time()
{
return $_SERVER['REQUEST_TIME'];
}

View File

@@ -1,116 +0,0 @@
<?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\LegacyPdoSessionHandler;
/**
* @group legacy
*/
class LegacyPdoSessionHandlerTest extends \PHPUnit_Framework_TestCase
{
private $pdo;
protected function setUp()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
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:');
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$sql = 'CREATE TABLE sessions (sess_id VARCHAR(128) PRIMARY KEY, sess_data TEXT, sess_time INTEGER)';
$this->pdo->exec($sql);
}
public function testIncompleteOptions()
{
$this->setExpectedException('InvalidArgumentException');
$storage = new LegacyPdoSessionHandler($this->pdo, array());
}
public function testWrongPdoErrMode()
{
$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
$pdo->exec('CREATE TABLE sessions (sess_id VARCHAR(128) PRIMARY KEY, sess_data TEXT, sess_time INTEGER)');
$this->setExpectedException('InvalidArgumentException');
$storage = new LegacyPdoSessionHandler($pdo, array('db_table' => 'sessions'));
}
public function testWrongTableOptionsWrite()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'bad_name'));
$this->setExpectedException('RuntimeException');
$storage->write('foo', 'bar');
}
public function testWrongTableOptionsRead()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'bad_name'));
$this->setExpectedException('RuntimeException');
$storage->read('foo', 'bar');
}
public function testWriteRead()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'));
$storage->write('foo', 'bar');
$this->assertEquals('bar', $storage->read('foo'), 'written value can be read back correctly');
}
public function testMultipleInstances()
{
$storage1 = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'));
$storage1->write('foo', 'bar');
$storage2 = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'));
$this->assertEquals('bar', $storage2->read('foo'), 'values persist between instances');
}
public function testSessionDestroy()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'));
$storage->write('foo', 'bar');
$this->assertCount(1, $this->pdo->query('SELECT * FROM sessions')->fetchAll());
$storage->destroy('foo');
$this->assertCount(0, $this->pdo->query('SELECT * FROM sessions')->fetchAll());
}
public function testSessionGC()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'));
$storage->write('foo', 'bar');
$storage->write('baz', 'bar');
$this->assertCount(2, $this->pdo->query('SELECT * FROM sessions')->fetchAll());
$storage->gc(-1);
$this->assertCount(0, $this->pdo->query('SELECT * FROM sessions')->fetchAll());
}
public function testGetConnection()
{
$storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'sessions'), array());
$method = new \ReflectionMethod($storage, 'getConnection');
$method->setAccessible(true);
$this->assertInstanceOf('\PDO', $method->invoke($storage));
}
}

View File

@@ -34,6 +34,17 @@ class BinaryFileResponseTest extends ResponseTestCase
$this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition'));
}
public function testConstructWithNonAsciiFilename()
{
touch(sys_get_temp_dir().'/fööö.html');
$response = new BinaryFileResponse(sys_get_temp_dir().'/fööö.html', 200, array(), true, 'attachment');
@unlink(sys_get_temp_dir().'/fööö.html');
$this->assertSame('fööö.html', $response->getFile()->getFilename());
}
/**
* @expectedException \LogicException
*/
@@ -49,12 +60,20 @@ class BinaryFileResponseTest extends ResponseTestCase
$this->assertFalse($response->getContent());
}
public function testSetContentDispositionGeneratesSafeFallbackFilename()
{
$response = new BinaryFileResponse(__FILE__);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html');
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
}
/**
* @dataProvider provideRanges
*/
public function testRequests($requestRange, $offset, $length, $responseRange)
{
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag();
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
// do a request to get the ETag
$request = Request::create('/');
@@ -80,6 +99,37 @@ class BinaryFileResponseTest extends ResponseTestCase
$this->assertEquals($responseRange, $response->headers->get('Content-Range'));
}
/**
* @dataProvider provideRanges
*/
public function testRequestsWithoutEtag($requestRange, $offset, $length, $responseRange)
{
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
// do a request to get the LastModified
$request = Request::create('/');
$response->prepare($request);
$lastModified = $response->headers->get('Last-Modified');
// prepare a request for a range of the testing file
$request = Request::create('/');
$request->headers->set('If-Range', $lastModified);
$request->headers->set('Range', $requestRange);
$file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r');
fseek($file, $offset);
$data = fread($file, $length);
fclose($file);
$this->expectOutputString($data);
$response = clone $response;
$response->prepare($request);
$response->sendContent();
$this->assertEquals(206, $response->getStatusCode());
$this->assertEquals($responseRange, $response->headers->get('Content-Range'));
}
public function provideRanges()
{
return array(
@@ -91,12 +141,31 @@ class BinaryFileResponseTest extends ResponseTestCase
);
}
public function testRangeRequestsWithoutLastModifiedDate()
{
// prevent auto last modified
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'), true, null, false, false);
// prepare a request for a range of the testing file
$request = Request::create('/');
$request->headers->set('If-Range', date('D, d M Y H:i:s').' GMT');
$request->headers->set('Range', 'bytes=1-4');
$this->expectOutputString(file_get_contents(__DIR__.'/File/Fixtures/test.gif'));
$response = clone $response;
$response->prepare($request);
$response->sendContent();
$this->assertEquals(200, $response->getStatusCode());
$this->assertNull($response->headers->get('Content-Range'));
}
/**
* @dataProvider provideFullFileRanges
*/
public function testFullFileRequests($requestRange)
{
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag();
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
// prepare a request for a range of the testing file
$request = Request::create('/');
@@ -131,7 +200,7 @@ class BinaryFileResponseTest extends ResponseTestCase
*/
public function testInvalidRequests($requestRange)
{
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag();
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag();
// prepare a request for a range of the testing file
$request = Request::create('/');
@@ -142,7 +211,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$response->sendContent();
$this->assertEquals(416, $response->getStatusCode());
#$this->assertEquals('', $response->headers->get('Content-Range'));
$this->assertEquals('bytes */35', $response->headers->get('Content-Range'));
}
public function provideInvalidRanges()
@@ -153,13 +222,16 @@ class BinaryFileResponseTest extends ResponseTestCase
);
}
public function testXSendfile()
/**
* @dataProvider provideXSendfileFiles
*/
public function testXSendfile($file)
{
$request = Request::create('/');
$request->headers->set('X-Sendfile-Type', 'X-Sendfile');
BinaryFileResponse::trustXSendfileTypeHeader();
$response = BinaryFileResponse::create(__DIR__.'/../README.md');
$response = BinaryFileResponse::create($file, 200, array('Content-Type' => 'application/octet-stream'));
$response->prepare($request);
$this->expectOutputString('');
@@ -168,6 +240,14 @@ class BinaryFileResponseTest extends ResponseTestCase
$this->assertContains('README.md', $response->headers->get('X-Sendfile'));
}
public function provideXSendfileFiles()
{
return array(
array(__DIR__.'/../README.md'),
array('file://'.__DIR__.'/../README.md'),
);
}
/**
* @dataProvider getSampleXAccelMappings
*/
@@ -180,7 +260,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$file = new FakeFile($realpath, __DIR__.'/File/Fixtures/test');
BinaryFileResponse::trustXSendfileTypeHeader();
$response = new BinaryFileResponse($file);
$response = new BinaryFileResponse($file, 200, array('Content-Type' => 'application/octet-stream'));
$reflection = new \ReflectionObject($response);
$property = $reflection->getProperty('file');
$property->setAccessible(true);
@@ -199,7 +279,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$realPath = realpath($path);
$this->assertFileExists($realPath);
$response = new BinaryFileResponse($realPath);
$response = new BinaryFileResponse($realPath, 200, array('Content-Type' => 'application/octet-stream'));
$response->deleteFileAfterSend(true);
$response->prepare($request);
@@ -211,7 +291,7 @@ class BinaryFileResponseTest extends ResponseTestCase
public function testAcceptRangeOnUnsafeMethods()
{
$request = Request::create('/', 'POST');
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif');
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
$response->prepare($request);
$this->assertEquals('none', $response->headers->get('Accept-Ranges'));
@@ -220,7 +300,7 @@ class BinaryFileResponseTest extends ResponseTestCase
public function testAcceptRangeNotOverriden()
{
$request = Request::create('/', 'POST');
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif');
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'));
$response->headers->set('Accept-Ranges', 'foo');
$response->prepare($request);
@@ -237,7 +317,7 @@ class BinaryFileResponseTest extends ResponseTestCase
protected function provideResponse()
{
return new BinaryFileResponse(__DIR__.'/../README.md');
return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream'));
}
public static function tearDownAfterClass()

View File

@@ -13,13 +13,13 @@ namespace Symfony\Component\HttpFoundation\Tests;
use Symfony\Component\HttpFoundation\Cookie;
require_once __DIR__.'/ClockMock.php';
/**
* CookieTest.
*
* @author John Kary <john@johnkary.net>
* @author Hugo Hamon <hugo.hamon@sensio.com>
*
* @group time-sensitive
*/
class CookieTest extends \PHPUnit_Framework_TestCase
{
@@ -41,7 +41,6 @@ class CookieTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider invalidNames
* @expectedException \InvalidArgumentException
* @covers Symfony\Component\HttpFoundation\Cookie::__construct
*/
public function testInstantiationThrowsExceptionIfCookieNameContainsInvalidCharacters($name)
{
@@ -56,9 +55,6 @@ class CookieTest extends \PHPUnit_Framework_TestCase
$cookie = new Cookie('MyCookie', 'foo', 'bar');
}
/**
* @covers Symfony\Component\HttpFoundation\Cookie::getValue
*/
public function testGetValue()
{
$value = 'MyValue';
@@ -89,13 +85,24 @@ class CookieTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date');
}
/**
* @requires PHP 5.5
*/
public function testConstructorWithDateTimeImmutable()
{
$expire = new \DateTimeImmutable();
$cookie = new Cookie('foo', 'bar', $expire);
$this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date');
}
public function testGetExpiresTimeWithStringValue()
{
$value = '+1 day';
$cookie = new Cookie('foo', 'bar', $value);
$expire = strtotime($value);
$this->assertEquals($expire, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date');
$this->assertEquals($expire, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date', 1);
}
public function testGetDomain()

View File

@@ -45,6 +45,9 @@ class FileTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('gif', $file->guessExtension());
}
/**
* @requires extension fileinfo
*/
public function testGuessExtensionWithReset()
{
$file = new File(__DIR__.'/Fixtures/other-file.example');
@@ -78,8 +81,8 @@ class FileTest extends \PHPUnit_Framework_TestCase
$movedFile = $file->move($targetDir);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile);
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertFileExists($targetPath);
$this->assertFileNotExists($path);
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
@@ -97,8 +100,8 @@ class FileTest extends \PHPUnit_Framework_TestCase
$file = new File($path);
$movedFile = $file->move($targetDir, 'test.newname.gif');
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertFileExists($targetPath);
$this->assertFileNotExists($path);
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
@@ -132,8 +135,8 @@ class FileTest extends \PHPUnit_Framework_TestCase
$movedFile = $file->move($targetDir, $filename);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile);
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertFileExists($targetPath);
$this->assertFileNotExists($path);
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
@@ -161,12 +164,6 @@ class FileTest extends \PHPUnit_Framework_TestCase
@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');

View File

Before

Width:  |  Height:  |  Size: 35 B

After

Width:  |  Height:  |  Size: 35 B

View File

@@ -14,17 +14,16 @@ namespace Symfony\Component\HttpFoundation\Tests\File\MimeType;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
/**
* @requires extension fileinfo
*/
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'));
}
$this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test'));
}
public function testGuessImageWithDirectory()
@@ -38,29 +37,17 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase
{
$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'));
}
$this->assertEquals('image/gif', 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'));
}
$this->assertEquals('image/gif', 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'));
}
$this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension'));
}
public function testGuessWithIncorrectPath()
@@ -75,7 +62,7 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase
$this->markTestSkipped('Can not verify chmod operations on Windows');
}
if ('root' === get_current_user()) {
if (!getenv('USER') || 'root' === getenv('USER')) {
$this->markTestSkipped('This test will fail if run under superuser');
}
@@ -83,7 +70,7 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase
touch($path);
@chmod($path, 0333);
if (get_current_user() != 'root' && substr(sprintf('%o', fileperms($path)), -4) == '0333') {
if (substr(sprintf('%o', fileperms($path)), -4) == '0333') {
$this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException');
MimeTypeGuesser::getInstance()->guess($path);
} else {

View File

@@ -164,8 +164,8 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertFileExists($targetPath);
$this->assertFileNotExists($path);
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);

View File

@@ -15,9 +15,6 @@ 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'));
@@ -67,9 +64,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('#a', $bag->getCacheControlDirective('public'));
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::all
*/
public function testAll()
{
$bag = new HeaderBag(array('foo' => 'bar'));
@@ -79,9 +73,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -91,9 +82,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -119,9 +107,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -186,9 +171,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::getIterator
*/
public function testGetIterator()
{
$headers = array('foo' => 'bar', 'hello' => 'world', 'third' => 'charm');
@@ -203,9 +185,6 @@ class HeaderBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(count($headers), $i);
}
/**
* @covers Symfony\Component\HttpFoundation\HeaderBag::count
*/
public function testCount()
{
$headers = array('foo' => 'bar', 'HELLO' => 'WORLD');

View File

@@ -30,13 +30,13 @@ class IpUtilsTest extends \PHPUnit_Framework_TestCase
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'),
array(false, '192.168.1.1', '192.168.1.1/33'), // invalid subnet
array(true, '192.168.1.1', array('1.2.3.4/1', '192.168.1.0/24')),
array(true, '192.168.1.1', array('192.168.1.0/24', '1.2.3.4/1')),
array(false, '192.168.1.1', array('1.2.3.4/1', '4.3.2.1/1')),
array(true, '1.2.3.4', '0.0.0.0/0'),
array(false, '1.2.3.4', '256.256.256/0'),
array(false, '1.2.3.4', '192.168.1.0/0'),
array(true, '1.2.3.4', '192.168.1.0/0'),
array(false, '1.2.3.4', '256.256.256/0'), // invalid CIDR notation
);
}
@@ -63,18 +63,17 @@ class IpUtilsTest extends \PHPUnit_Framework_TestCase
array(true, '2a01:198:603:0:396e:4789:8e99:890f', array('::1', '2a01:198:603:0::/65')),
array(true, '2a01:198:603:0:396e:4789:8e99:890f', array('2a01:198:603:0::/65', '::1')),
array(false, '2a01:198:603:0:396e:4789:8e99:890f', array('::1', '1a01:198:603:0::/65')),
array(false, '}__test|O:21:&quot;JDatabaseDriverMysqli&quot;:3:{s:2', '::1'),
array(false, '2a01:198:603:0:396e:4789:8e99:890f', 'unknown'),
);
}
/**
* @expectedException \RuntimeException
* @requires extension sockets
*/
public function testAnIpv6WithOptionDisabledIpv6()
{
if (!extension_loaded('sockets')) {
$this->markTestSkipped('Only works when the socket extension is enabled');
}
if (defined('AF_INET6')) {
$this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".');
}

View File

@@ -208,10 +208,6 @@ class JsonResponseTest extends \PHPUnit_Framework_TestCase
*/
public function testSetContentJsonSerializeError()
{
if (!interface_exists('JsonSerializable')) {
$this->markTestSkipped('Interface JsonSerializable is available in PHP 5.4+');
}
$serializable = new JsonSerializableObject();
JsonResponse::create($serializable);

View File

@@ -15,17 +15,11 @@ 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'));
@@ -54,9 +48,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('foo' => 'bar'), $bag->all());
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::replace
*/
public function testReplace()
{
$bag = new ParameterBag(array('foo' => 'bar'));
@@ -66,9 +57,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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));
@@ -85,40 +73,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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());
@@ -130,9 +84,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -141,9 +92,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -152,9 +100,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -163,9 +108,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -174,9 +116,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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'));
@@ -185,9 +124,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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(
@@ -201,31 +137,28 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$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('0123', $bag->filter('digits', '', 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('example@example.com', $bag->filter('email', '', 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->assertEquals('http://example.com/foo', $bag->filter('url', '', 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->assertEquals('http://example.com/foo', $bag->filter('url', '', 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(
$this->assertFalse($bag->filter('dec', '', 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(
$this->assertFalse($bag->filter('hex', '', 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');
$this->assertEquals(array('bang'), $bag->filter('array', ''), '->filter() gets a value of parameter as an array');
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getIterator
*/
public function testGetIterator()
{
$parameters = array('foo' => 'bar', 'hello' => 'world');
@@ -240,9 +173,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(count($parameters), $i);
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::count
*/
public function testCount()
{
$parameters = array('foo' => 'bar', 'hello' => 'world');
@@ -251,9 +181,6 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(count($parameters), count($bag));
}
/**
* @covers Symfony\Component\HttpFoundation\ParameterBag::getBoolean
*/
public function testGetBoolean()
{
$parameters = array('string_true' => 'true', 'string_false' => 'false');

View File

@@ -17,17 +17,6 @@ use Symfony\Component\HttpFoundation\Request;
class RequestTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Symfony\Component\HttpFoundation\Request::__construct
*/
public function testConstructor()
{
$this->testInitialize();
}
/**
* @covers Symfony\Component\HttpFoundation\Request::initialize
*/
public function testInitialize()
{
$request = new Request();
@@ -94,9 +83,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('pl', $locale);
}
/**
* @covers Symfony\Component\HttpFoundation\Request::create
*/
public function testCreate()
{
$request = Request::create('http://test.com/foo?bar=baz');
@@ -224,7 +210,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('/?foo', $request->getRequestUri());
$this->assertEquals(array('foo' => ''), $request->query->all());
## assume rewrite rule: (.*) --> app/app.php ; app/ is a symlink to a symfony web/ directory
// assume rewrite rule: (.*) --> app/app.php; app/ is a symlink to a symfony web/ directory
$request = Request::create('http://test.com/apparthotel-1234', 'GET', array(), array(), array(),
array(
'DOCUMENT_ROOT' => '/var/www/www.test.com',
@@ -240,9 +226,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($request->isSecure());
}
/**
* @covers Symfony\Component\HttpFoundation\Request::create
*/
public function testCreateCheckPrecedence()
{
// server is used by default
@@ -311,8 +294,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getFormat
* @covers Symfony\Component\HttpFoundation\Request::setFormat
* @dataProvider getFormatToMimeTypeMapProvider
*/
public function testGetFormatFromMimeType($format, $mimeTypes)
@@ -327,9 +308,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getFormat
*/
public function testGetFormatFromMimeTypeWithParameters()
{
$request = new Request();
@@ -337,7 +315,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getMimeType
* @dataProvider getFormatToMimeTypeMapProvider
*/
public function testGetMimeTypeFromFormat($format, $mimeTypes)
@@ -348,6 +325,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
}
public function testGetFormatWithCustomMimeType()
{
$request = new Request();
$request->setFormat('custom', 'application/vnd.foo.api;myversion=2.3');
$this->assertEquals('custom', $request->getFormat('application/vnd.foo.api;myversion=2.3'));
}
public function getFormatToMimeTypeMapProvider()
{
return array(
@@ -358,13 +342,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase
array('json', array('application/json', 'application/x-json')),
array('xml', array('text/xml', 'application/xml', 'application/x-xml')),
array('rdf', array('application/rdf+xml')),
array('atom',array('application/atom+xml')),
array('atom', array('application/atom+xml')),
);
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getUri
*/
public function testGetUri()
{
$server = array();
@@ -480,9 +461,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri());
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getUriForPath
*/
public function testGetUriForPath()
{
$request = Request::create('http://test.com/foo?bar=baz');
@@ -591,13 +569,30 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getUserInfo
* @dataProvider getRelativeUriForPathData()
*/
public function testGetRelativeUriForPath($expected, $pathinfo, $path)
{
$this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path));
}
public function getRelativeUriForPathData()
{
return array(
array('me.png', '/foo', '/me.png'),
array('../me.png', '/foo/bar', '/me.png'),
array('me.png', '/foo/bar', '/foo/me.png'),
array('../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'),
array('../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'),
array('baz/me.png', '/foo/bar/b', 'baz/me.png'),
);
}
public function testGetUserInfo()
{
$request = new Request();
$server['PHP_AUTH_USER'] = 'fabien';
$server = array('PHP_AUTH_USER' => 'fabien');
$request->initialize(array(), array(), array(), array(), array(), $server);
$this->assertEquals('fabien', $request->getUserInfo());
@@ -610,9 +605,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('0:0', $request->getUserInfo());
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getSchemeAndHttpHost
*/
public function testGetSchemeAndHttpHost()
{
$request = new Request();
@@ -637,8 +629,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers Symfony\Component\HttpFoundation\Request::getQueryString
* @covers Symfony\Component\HttpFoundation\Request::normalizeQueryString
* @dataProvider getQueryStringNormalizationData
*/
public function testGetQueryString($query, $expectedQuery, $msg)
@@ -774,10 +764,6 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request->getHost();
}
/**
* @covers Symfony\Component\HttpFoundation\Request::setMethod
* @covers Symfony\Component\HttpFoundation\Request::getMethod
*/
public function testGetSetMethod()
{
$request = new Request();
@@ -857,6 +843,31 @@ class RequestTest extends \PHPUnit_Framework_TestCase
Request::setTrustedProxies(array());
}
/**
* @dataProvider testGetClientIpsForwardedProvider
*/
public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies)
{
$request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies);
$this->assertEquals($expected, $request->getClientIps());
Request::setTrustedProxies(array());
}
public function testGetClientIpsForwardedProvider()
{
// $expected $remoteAddr $httpForwarded $trustedProxies
return array(
array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', null),
array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', array('127.0.0.1')),
array(array('88.88.88.88'), '127.0.0.1', 'for="88.88.88.88:80"', array('127.0.0.1')),
array(array('192.0.2.60'), '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', array('::1')),
array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', array('::1')),
array(array('2001:db8:cafe::17'), '::1', 'for="[2001:db8:cafe::17]:4711', array('::1')),
);
}
public function testGetClientIpsProvider()
{
// $expected $remoteAddr $httpForwardedFor $trustedProxies
@@ -905,6 +916,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase
// client IP with port
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', array('127.0.0.1')),
// invalid forwarded IP is ignored
array(array('88.88.88.88'), '127.0.0.1', 'unknown,88.88.88.88', array('127.0.0.1')),
array(array('88.88.88.88'), '127.0.0.1', '}__test|O:21:&quot;JDatabaseDriverMysqli&quot;:3:{s:2,88.88.88.88', array('127.0.0.1')),
);
}
@@ -935,7 +950,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
public function testContentAsResource()
{
$resource = fopen('php://memory','r+');
$resource = fopen('php://memory', 'r+');
fwrite($resource, 'My other content');
rewind($resource);
@@ -961,13 +976,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
* @requires PHP 5.6
*/
public function testGetContentCanBeCalledTwiceWithResources($first, $second)
{
if (PHP_VERSION_ID < 50600) {
$this->markTestSkipped('PHP < 5.6 does not allow to open php://input several times.');
}
$req = new Request();
$a = $req->getContent($first);
$b = $req->getContent($second);
@@ -1176,6 +1188,25 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('/path%20test/info', $request->getPathInfo());
}
public function testGetParameterPrecedence()
{
$request = new Request();
$request->attributes->set('foo', 'attr');
$request->query->set('foo', 'query');
$request->request->set('foo', 'body');
$this->assertSame('attr', $request->get('foo'));
$request->attributes->remove('foo');
$this->assertSame('query', $request->get('foo'));
$request->query->remove('foo');
$this->assertSame('body', $request->get('foo'));
$request->request->remove('foo');
$this->assertNull($request->get('foo'));
}
public function testGetPreferredLanguage()
{
$request = new Request();
@@ -1215,12 +1246,11 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($request->isXmlHttpRequest());
}
/**
* @requires extension intl
*/
public function testIntlLocale()
{
if (!extension_loaded('intl')) {
$this->markTestSkipped('The intl extension is needed to run this test.');
}
$request = new Request();
$request->setDefaultLocale('fr');
@@ -1318,6 +1348,9 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request = new Request();
$this->assertNull($request->setRequestFormat('foo'));
$this->assertEquals('foo', $request->getRequestFormat(null));
$request = new Request(array('_format' => 'foo'));
$this->assertEquals('html', $request->getRequestFormat());
}
public function testHasSession()
@@ -1518,6 +1551,25 @@ class RequestTest extends \PHPUnit_Framework_TestCase
return $request;
}
private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies)
{
$request = new Request();
$server = array('REMOTE_ADDR' => $remoteAddr);
if (null !== $httpForwarded) {
$server['HTTP_FORWARDED'] = $httpForwarded;
}
if ($trustedProxies) {
Request::setTrustedProxies($trustedProxies);
}
$request->initialize(array(), array(), array(), array(), array(), $server);
return $request;
}
public function testTrustedProxies()
{
$request = Request::create('http://example.com/');
@@ -1544,6 +1596,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(80, $request->getPort());
$this->assertFalse($request->isSecure());
// request is forwarded by a non-trusted proxy
Request::setTrustedProxies(array('2.2.2.2'));
$this->assertEquals('3.3.3.3', $request->getClientIp());
$this->assertEquals('example.com', $request->getHost());
$this->assertEquals(80, $request->getPort());
$this->assertFalse($request->isSecure());
// trusted proxy via setTrustedProxies()
Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
$this->assertEquals('1.1.1.1', $request->getClientIp());
@@ -1765,7 +1824,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request = Request::create('/');
$request->headers->set('host', $host);
$this->assertEquals($host, $request->getHost());
$this->assertLessThan(1, microtime(true) - $start);
$this->assertLessThan(5, microtime(true) - $start);
}
/**

View File

@@ -14,12 +14,12 @@ namespace Symfony\Component\HttpFoundation\Tests;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Cookie;
require_once __DIR__.'/ClockMock.php';
/**
* @group time-sensitive
*/
class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Symfony\Component\HttpFoundation\ResponseHeaderBag::allPreserveCase
* @dataProvider provideAllPreserveCase
*/
public function testAllPreserveCase($headers, $expected)

View File

@@ -14,6 +14,9 @@ namespace Symfony\Component\HttpFoundation\Tests;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* @group time-sensitive
*/
class ResponseTest extends ResponseTestCase
{
public function testCreate()
@@ -105,6 +108,22 @@ class ResponseTest extends ResponseTestCase
$this->assertFalse($response->mustRevalidate());
}
public function testMustRevalidateWithMustRevalidateCacheControlHeader()
{
$response = new Response();
$response->headers->set('cache-control', 'must-revalidate');
$this->assertTrue($response->mustRevalidate());
}
public function testMustRevalidateWithProxyRevalidateCacheControlHeader()
{
$response = new Response();
$response->headers->set('cache-control', 'proxy-revalidate');
$this->assertTrue($response->mustRevalidate());
}
public function testSetNotModified()
{
$response = new Response();
@@ -243,16 +262,18 @@ class ResponseTest extends ResponseTestCase
{
$oneHourAgo = $this->createDateTimeOneHourAgo();
$response = new Response('', 200, array('Date' => $oneHourAgo->format(DATE_RFC2822)));
$this->assertEquals(0, $oneHourAgo->diff($response->getDate())->format('%s'), '->getDate() returns the Date header if present');
$date = $response->getDate();
$this->assertEquals($oneHourAgo->getTimestamp(), $date->getTimestamp(), '->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');
$this->assertEquals(time(), $date->getTimestamp(), '->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->assertLessThanOrEqual(1, $now->diff($response->getDate())->format('%s'), '->getDate() returns the date when the header has been modified');
$date = $response->getDate();
$this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the date when the header has been modified');
$response = new Response('', 200);
$response->headers->remove('Date');
@@ -272,7 +293,7 @@ class ResponseTest extends ResponseTestCase
$response = new Response();
$response->headers->set('Cache-Control', 'must-revalidate');
$response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
$this->assertLessThanOrEqual(1, $response->getMaxAge() - 3600, '->getMaxAge() falls back to Expires when no max-age or s-maxage directive present');
$this->assertEquals(3600, $response->getMaxAge(), '->getMaxAge() falls back to Expires when no max-age or s-maxage directive present');
$response = new Response();
$response->headers->set('Cache-Control', 'must-revalidate');
@@ -343,7 +364,7 @@ class ResponseTest extends ResponseTestCase
$response = new Response();
$response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
$this->assertLessThanOrEqual(1, 3600 - $response->getTtl(), '->getTtl() uses the Expires header when no max-age is present');
$this->assertEquals(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));
@@ -356,7 +377,7 @@ class ResponseTest extends ResponseTestCase
$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');
$this->assertEquals(60, $response->getTtl(), '->getTtl() uses Cache-Control max-age when present');
}
public function testSetClientTtl()
@@ -556,7 +577,7 @@ class ResponseTest extends ResponseTestCase
$response->setCache($options);
$this->assertEquals($response->getEtag(), '"whatever"');
$now = new \DateTime();
$now = $this->createDateTimeNow();
$options = array('last_modified' => $now);
$response->setCache($options);
$this->assertEquals($response->getLastModified()->getTimestamp(), $now->getTimestamp());
@@ -615,7 +636,7 @@ class ResponseTest extends ResponseTestCase
$this->assertNull($response->getExpires(), '->setExpires() remove the header when passed null');
$now = new \DateTime();
$now = $this->createDateTimeNow();
$response->setExpires($now);
$this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
@@ -624,7 +645,7 @@ class ResponseTest extends ResponseTestCase
public function testSetLastModified()
{
$response = new Response();
$response->setLastModified(new \DateTime());
$response->setLastModified($this->createDateTimeNow());
$this->assertNotNull($response->getLastModified());
$response->setLastModified(null);
@@ -674,7 +695,7 @@ class ResponseTest extends ResponseTestCase
array('200', null, 'OK'),
array('200', false, ''),
array('200', 'foo', 'foo'),
array('199', null, ''),
array('199', null, 'unknown status'),
array('199', false, ''),
array('199', 'foo', 'foo'),
);
@@ -809,7 +830,7 @@ class ResponseTest extends ResponseTestCase
'setCharset' => 'UTF-8',
'setPublic' => null,
'setPrivate' => null,
'setDate' => new \DateTime(),
'setDate' => $this->createDateTimeNow(),
'expire' => null,
'setMaxAge' => 1,
'setSharedMaxAge' => 1,
@@ -842,21 +863,19 @@ class ResponseTest extends ResponseTestCase
protected function createDateTimeOneHourAgo()
{
$date = new \DateTime();
return $date->sub(new \DateInterval('PT1H'));
return $this->createDateTimeNow()->sub(new \DateInterval('PT1H'));
}
protected function createDateTimeOneHourLater()
{
$date = new \DateTime();
return $date->add(new \DateInterval('PT1H'));
return $this->createDateTimeNow()->add(new \DateInterval('PT1H'));
}
protected function createDateTimeNow()
{
return new \DateTime();
$date = new \DateTime();
return $date->setTimestamp(time());
}
protected function provideResponse()

View File

@@ -151,4 +151,19 @@ class ServerBagTest extends \PHPUnit_Framework_TestCase
'AUTHORIZATION' => $headerContent,
), $bag->getHeaders());
}
/**
* @see https://github.com/symfony/symfony/issues/17345
*/
public function testItDoesNotOverwriteTheAuthorizationHeaderIfItIsAlreadySet()
{
$headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo';
$bag = new ServerBag(array('PHP_AUTH_USER' => 'foo', 'HTTP_AUTHORIZATION' => $headerContent));
$this->assertEquals(array(
'AUTHORIZATION' => $headerContent,
'PHP_AUTH_USER' => 'foo',
'PHP_AUTH_PW' => '',
), $bag->getHeaders());
}
}

View File

@@ -43,8 +43,9 @@ class AttributeBagTest extends \PHPUnit_Framework_TestCase
'category' => array(
'fishing' => array(
'first' => 'cod',
'second' => 'sole',),
'second' => 'sole',
),
),
);
$this->bag = new AttributeBag('_sf2');
$this->bag->initialize($this->array);
@@ -169,9 +170,6 @@ class AttributeBagTest extends \PHPUnit_Framework_TestCase
);
}
/**
* @covers Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag::getIterator
*/
public function testGetIterator()
{
$i = 0;
@@ -183,9 +181,6 @@ class AttributeBagTest extends \PHPUnit_Framework_TestCase
$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

@@ -43,8 +43,9 @@ class NamespacedAttributeBagTest extends \PHPUnit_Framework_TestCase
'category' => array(
'fishing' => array(
'first' => 'cod',
'second' => 'sole',),
'second' => 'sole',
),
),
);
$this->bag = new NamespacedAttributeBag('_sf2', '/');
$this->bag->initialize($this->array);

Some files were not shown because too many files have changed in this diff Show More