update to laravel 5.7 and try getting autologin saved

This commit is contained in:
Kode
2018-10-14 20:50:32 +01:00
parent c3da17befc
commit 6501aacb1b
2402 changed files with 79064 additions and 28971 deletions

View File

@@ -52,12 +52,17 @@ class AcceptHeader
{
$index = 0;
return new self(array_map(function ($itemValue) use (&$index) {
$item = AcceptHeaderItem::fromString($itemValue);
$parts = HeaderUtils::split((string) $headerValue, ',;=');
return new self(array_map(function ($subParts) use (&$index) {
$part = array_shift($subParts);
$attributes = HeaderUtils::combine($subParts);
$item = new AcceptHeaderItem($part[0], $attributes);
$item->setIndex($index++);
return $item;
}, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)));
}, $parts));
}
/**
@@ -91,7 +96,7 @@ class AcceptHeader
*/
public function get($value)
{
return isset($this->items[$value]) ? $this->items[$value] : null;
return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null;
}
/**

View File

@@ -23,11 +23,7 @@ class AcceptHeaderItem
private $index = 0;
private $attributes = array();
/**
* @param string $value
* @param array $attributes
*/
public function __construct($value, array $attributes = array())
public function __construct(string $value, array $attributes = array())
{
$this->value = $value;
foreach ($attributes as $name => $value) {
@@ -44,24 +40,12 @@ class AcceptHeaderItem
*/
public static function fromString($itemValue)
{
$bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$value = array_shift($bits);
$attributes = array();
$parts = HeaderUtils::split($itemValue, ';=');
$lastNullAttribute = null;
foreach ($bits as $bit) {
if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ('"' === $start || '\'' === $start)) {
$attributes[$lastNullAttribute] = substr($bit, 1, -1);
} elseif ('=' === $end) {
$lastNullAttribute = $bit = substr($bit, 0, -1);
$attributes[$bit] = null;
} else {
$parts = explode('=', $bit);
$attributes[$parts[0]] = isset($parts[1]) && strlen($parts[1]) > 0 ? $parts[1] : '';
}
}
$part = array_shift($parts);
$attributes = HeaderUtils::combine($parts);
return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ('"' === $start || '\'' === $start) ? substr($value, 1, -1) : $value, $attributes);
return new self($part[0], $attributes);
}
/**
@@ -72,10 +56,8 @@ class AcceptHeaderItem
public function __toString()
{
$string = $this->value.($this->quality < 1 ? ';q='.$this->quality : '');
if (count($this->attributes) > 0) {
$string .= ';'.implode(';', array_map(function ($name, $value) {
return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value);
}, array_keys($this->attributes), $this->attributes));
if (\count($this->attributes) > 0) {
$string .= '; '.HeaderUtils::toString($this->attributes, ';');
}
return $string;

View File

@@ -35,7 +35,7 @@ class ApacheRequest extends Request
if (false === strpos($this->server->get('REQUEST_URI'), $baseUrl)) {
// assume mod_rewrite
return rtrim(dirname($baseUrl), '/\\');
return rtrim(\dirname($baseUrl), '/\\');
}
return $baseUrl;

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\File;
/**
* BinaryFileResponse represents an HTTP response delivering a file.
@@ -31,8 +31,8 @@ class BinaryFileResponse extends Response
* @var File
*/
protected $file;
protected $offset;
protected $maxlen;
protected $offset = 0;
protected $maxlen = -1;
protected $deleteFileAfterSend = false;
/**
@@ -40,11 +40,11 @@ class BinaryFileResponse extends Response
* @param int $status The response status code
* @param array $headers An array of response headers
* @param bool $public Files are public by default
* @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename
* @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename
* @param bool $autoEtag Whether the ETag header should be automatically set
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
*/
public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
public function __construct($file, int $status = 200, array $headers = array(), bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true)
{
parent::__construct(null, $status, $headers);
@@ -60,7 +60,7 @@ class BinaryFileResponse extends Response
* @param int $status The response status code
* @param array $headers An array of response headers
* @param bool $public Files are public by default
* @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename
* @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename
* @param bool $autoEtag Whether the ETag header should be automatically set
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
*
@@ -165,7 +165,7 @@ class BinaryFileResponse extends Response
for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) {
$char = mb_substr($filename, $i, 1, $encoding);
if ('%' === $char || ord($char) < 32 || ord($char) > 126) {
if ('%' === $char || \ord($char) < 32 || \ord($char) > 126) {
$filenameFallback .= '_';
} else {
$filenameFallback .= $char;
@@ -218,17 +218,12 @@ class BinaryFileResponse extends Response
if ('x-accel-redirect' === strtolower($type)) {
// 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)) {
$pathPrefix = trim($mapping[0]);
$location = trim($mapping[1]);
if (substr($path, 0, strlen($pathPrefix)) === $pathPrefix) {
$path = $location.substr($path, strlen($pathPrefix));
break;
}
$parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',=');
foreach ($parts as $part) {
list($pathPrefix, $location) = $part;
if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) {
$path = $location.substr($path, \strlen($pathPrefix));
break;
}
}
}
@@ -350,7 +345,7 @@ class BinaryFileResponse extends Response
*
* @return $this
*/
public function deleteFileAfterSend($shouldDelete)
public function deleteFileAfterSend($shouldDelete = true)
{
$this->deleteFileAfterSend = $shouldDelete;

View File

@@ -1,6 +1,50 @@
CHANGELOG
=========
4.1.3
-----
* [BC BREAK] Support for the IIS-only `X_ORIGINAL_URL` and `X_REWRITE_URL`
HTTP headers has been dropped for security reasons.
4.1.0
-----
* Query string normalization uses `parse_str()` instead of custom parsing logic.
* Passing the file size to the constructor of the `UploadedFile` class is deprecated.
* The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead.
* added `RedisSessionHandler` to use Redis as a session storage
* The `get()` method of the `AcceptHeader` class now takes into account the
`*` and `*/*` default values (if they are present in the Accept HTTP header)
when looking for items.
* deprecated `Request::getSession()` when no session has been set. Use `Request::hasSession()` instead.
* added `CannotWriteFileException`, `ExtensionFileException`, `FormSizeFileException`,
`IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to
handle failed `UploadedFile`.
* added `MigratingSessionHandler` for migrating between two session handlers without losing sessions
* added `HeaderUtils`.
4.0.0
-----
* the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()`
methods have been removed
* the `Request::HEADER_CLIENT_IP` constant has been removed, use
`Request::HEADER_X_FORWARDED_FOR` instead
* the `Request::HEADER_CLIENT_HOST` constant has been removed, use
`Request::HEADER_X_FORWARDED_HOST` instead
* the `Request::HEADER_CLIENT_PROTO` constant has been removed, use
`Request::HEADER_X_FORWARDED_PROTO` instead
* the `Request::HEADER_CLIENT_PORT` constant has been removed, use
`Request::HEADER_X_FORWARDED_PORT` instead
* checking for cacheable HTTP methods using the `Request::isMethodSafe()`
method (by not passing `false` as its argument) is not supported anymore and
throws a `\BadMethodCallException`
* the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes have been removed
* setting session save handlers that do not implement `\SessionHandlerInterface` in
`NativeSessionStorage::setSaveHandler()` is not supported anymore and throws a
`\TypeError`
3.4.0
-----

View File

@@ -50,34 +50,20 @@ class Cookie
'raw' => !$decode,
'samesite' => null,
);
foreach (explode(';', $cookie) as $part) {
if (false === strpos($part, '=')) {
$key = trim($part);
$value = true;
} else {
list($key, $value) = explode('=', trim($part), 2);
$key = trim($key);
$value = trim($value);
}
if (!isset($data['name'])) {
$data['name'] = $decode ? urldecode($key) : $key;
$data['value'] = true === $value ? null : ($decode ? urldecode($value) : $value);
continue;
}
switch ($key = strtolower($key)) {
case 'name':
case 'value':
break;
case 'max-age':
$data['expires'] = time() + (int) $value;
break;
default:
$data[$key] = $value;
break;
}
$parts = HeaderUtils::split($cookie, ';=');
$part = array_shift($parts);
$name = $decode ? urldecode($part[0]) : $part[0];
$value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null;
$data = HeaderUtils::combine($parts) + $data;
if (isset($data['max-age'])) {
$data['expires'] = time() + (int) $data['max-age'];
}
return new static($data['name'], $data['value'], $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
}
/**
@@ -93,7 +79,7 @@ class Cookie
*
* @throws \InvalidArgumentException
*/
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null)
public function __construct(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true, bool $raw = false, string $sameSite = null)
{
// from PHP source code
if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
@@ -120,15 +106,15 @@ class Cookie
$this->domain = $domain;
$this->expire = 0 < $expire ? (int) $expire : 0;
$this->path = empty($path) ? '/' : $path;
$this->secure = (bool) $secure;
$this->httpOnly = (bool) $httpOnly;
$this->raw = (bool) $raw;
$this->secure = $secure;
$this->httpOnly = $httpOnly;
$this->raw = $raw;
if (null !== $sameSite) {
$sameSite = strtolower($sameSite);
}
if (!in_array($sameSite, array(self::SAMESITE_LAX, self::SAMESITE_STRICT, null), true)) {
if (!\in_array($sameSite, array(self::SAMESITE_LAX, self::SAMESITE_STRICT, null), true)) {
throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.');
}
@@ -266,7 +252,7 @@ class Cookie
*/
public function isCleared()
{
return $this->expire < time();
return 0 !== $this->expire && $this->expire < time();
}
/**

View File

@@ -21,7 +21,7 @@ class AccessDeniedException extends FileException
/**
* @param string $path The path to the accessed file
*/
public function __construct($path)
public function __construct(string $path)
{
parent::__construct(sprintf('The file %s could not be accessed', $path));
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class CannotWriteFileException extends FileException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class ExtensionFileException extends FileException
{
}

View File

@@ -21,7 +21,7 @@ class FileNotFoundException extends FileException
/**
* @param string $path The path to the file that was not found
*/
public function __construct($path)
public function __construct(string $path)
{
parent::__construct(sprintf('The file "%s" does not exist', $path));
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class FormSizeFileException extends FileException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class IniSizeFileException extends FileException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class NoFileException extends FileException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class NoTmpDirFileException extends FileException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile.
*
* @author Florent Mata <florentmata@gmail.com>
*/
class PartialFileException extends FileException
{
}

View File

@@ -13,8 +13,8 @@ namespace Symfony\Component\HttpFoundation\File\Exception;
class UnexpectedTypeException extends FileException
{
public function __construct($value, $expectedType)
public function __construct($value, string $expectedType)
{
parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, \is_object($value) ? \get_class($value) : \gettype($value)));
}
}

View File

@@ -13,8 +13,8 @@ namespace Symfony\Component\HttpFoundation\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
/**
* A file in the file system.
@@ -31,7 +31,7 @@ class File extends \SplFileInfo
*
* @throws FileNotFoundException If the given path is not a file
*/
public function __construct($path, $checkPath = true)
public function __construct(string $path, bool $checkPath = true)
{
if ($checkPath && !is_file($path)) {
throw new FileNotFoundException($path);
@@ -115,7 +115,7 @@ class File extends \SplFileInfo
throw new FileException(sprintf('Unable to write in the "%s" directory', $directory));
}
$target = rtrim($directory, '/\\').DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name));
$target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name));
return new self($target, false);
}

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
/**
* Guesses the mime type with the binary "file" (only available on *nix).
@@ -31,7 +31,7 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
*
* @param string $cmd The command to run to get the mime type of a file
*/
public function __construct($cmd = 'file -b --mime %s 2>/dev/null')
public function __construct(string $cmd = 'file -b --mime %s 2>/dev/null')
{
$this->cmd = $cmd;
}
@@ -49,7 +49,7 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
return $supported;
}
if ('\\' === DIRECTORY_SEPARATOR || !function_exists('passthru') || !function_exists('escapeshellarg')) {
if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) {
return $supported = false;
}

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
/**
* Guesses the mime type using the PECL extension FileInfo.
@@ -28,7 +28,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
*
* @see http://www.php.net/manual/en/function.finfo-open.php
*/
public function __construct($magicFile = null)
public function __construct(string $magicFile = null)
{
$this->magicFile = $magicFile;
}
@@ -40,7 +40,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
*/
public static function isSupported()
{
return function_exists('finfo_open');
return \function_exists('finfo_open');
}
/**

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
/**
* A singleton mime type guesser.

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
/**
* Guesses the mime type of a file.

View File

@@ -11,8 +11,15 @@
namespace Symfony\Component\HttpFoundation\File;
use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
/**
@@ -27,7 +34,6 @@ class UploadedFile extends File
private $test = false;
private $originalName;
private $mimeType;
private $size;
private $error;
/**
@@ -47,7 +53,6 @@ class UploadedFile extends File
* @param string $path The full temporary path to the file
* @param string $originalName The original file name of the uploaded file
* @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 provided by the uploader
* @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
* Local files are used in test mode hence the code should not enforce HTTP uploads
@@ -55,13 +60,19 @@ class UploadedFile extends File
* @throws FileException If file_uploads is disabled
* @throws FileNotFoundException If the file does not exist
*/
public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null, $test = false)
public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, $test = false)
{
$this->originalName = $this->getName($originalName);
$this->mimeType = $mimeType ?: 'application/octet-stream';
$this->size = $size;
if (4 < \func_num_args() ? !\is_bool($test) : null !== $error && @filesize($path) === $error) {
@trigger_error(sprintf('Passing a size as 4th argument to the constructor of "%s" is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
$error = $test;
$test = 5 < \func_num_args() ? func_get_arg(5) : false;
}
$this->error = $error ?: UPLOAD_ERR_OK;
$this->test = (bool) $test;
$this->test = $test;
parent::__construct($path, UPLOAD_ERR_OK === $this->error);
}
@@ -141,11 +152,15 @@ class UploadedFile extends File
* It is extracted from the request from which the file has been uploaded.
* Then it should not be considered as a safe value.
*
* @return int|null The file size
* @deprecated since Symfony 4.1, use getSize() instead.
*
* @return int|null The file sizes
*/
public function getClientSize()
{
return $this->size;
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use getSize() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->getSize();
}
/**
@@ -204,6 +219,23 @@ class UploadedFile extends File
return $target;
}
switch ($this->error) {
case UPLOAD_ERR_INI_SIZE:
throw new IniSizeFileException($this->getErrorMessage());
case UPLOAD_ERR_FORM_SIZE:
throw new FormSizeFileException($this->getErrorMessage());
case UPLOAD_ERR_PARTIAL:
throw new PartialFileException($this->getErrorMessage());
case UPLOAD_ERR_NO_FILE:
throw new NoFileException($this->getErrorMessage());
case UPLOAD_ERR_CANT_WRITE:
throw new CannotWriteFileException($this->getErrorMessage());
case UPLOAD_ERR_NO_TMP_DIR:
throw new NoTmpDirFileException($this->getErrorMessage());
case UPLOAD_ERR_EXTENSION:
throw new ExtensionFileException($this->getErrorMessage());
}
throw new FileException($this->getErrorMessage());
}
@@ -222,9 +254,9 @@ class UploadedFile extends File
$max = ltrim($iniMax, '+');
if (0 === strpos($max, '0x')) {
$max = intval($max, 16);
$max = \intval($max, 16);
} elseif (0 === strpos($max, '0')) {
$max = intval($max, 8);
$max = \intval($max, 8);
} else {
$max = (int) $max;
}

View File

@@ -45,7 +45,7 @@ class FileBag extends ParameterBag
*/
public function set($key, $value)
{
if (!is_array($value) && !$value instanceof UploadedFile) {
if (!\is_array($value) && !$value instanceof UploadedFile) {
throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.');
}
@@ -76,7 +76,7 @@ class FileBag extends ParameterBag
}
$file = $this->fixPhpFilesArray($file);
if (is_array($file)) {
if (\is_array($file)) {
$keys = array_keys($file);
sort($keys);
@@ -84,7 +84,7 @@ class FileBag extends ParameterBag
if (UPLOAD_ERR_NO_FILE == $file['error']) {
$file = null;
} else {
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']);
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']);
}
} else {
$file = array_map(array($this, 'convertFileInformation'), $file);
@@ -113,14 +113,14 @@ class FileBag extends ParameterBag
*/
protected function fixPhpFilesArray($data)
{
if (!is_array($data)) {
if (!\is_array($data)) {
return $data;
}
$keys = array_keys($data);
sort($keys);
if (self::$fileKeys != $keys || !isset($data['name']) || !is_array($data['name'])) {
if (self::$fileKeys != $keys || !isset($data['name']) || !\is_array($data['name'])) {
return $data;
}

View File

@@ -46,7 +46,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
$max = max(array_map('strlen', array_keys($headers))) + 1;
$content = '';
foreach ($headers as $name => $values) {
$name = implode('-', array_map('ucfirst', explode('-', $name)));
$name = ucwords($name, '-');
foreach ($values as $value) {
$content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
}
@@ -101,11 +101,11 @@ class HeaderBag implements \IteratorAggregate, \Countable
/**
* Returns a header value by name.
*
* @param string $key The header name
* @param string|string[] $default The default value
* @param bool $first Whether to return the first value or all header values
* @param string $key The header name
* @param string|string[]|null $default The default value
* @param bool $first Whether to return the first value or all header values
*
* @return string|string[] The first header value or default value if $first is true, an array of values otherwise
* @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise
*/
public function get($key, $default = null, $first = true)
{
@@ -181,7 +181,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/
public function contains($key, $value)
{
return in_array($value, $this->get($key, null, false));
return \in_array($value, $this->get($key, null, false));
}
/**
@@ -206,7 +206,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
* @param string $key The parameter key
* @param \DateTime $default The default value
*
* @return null|\DateTime The parsed DateTime or the default value if the header does not exist
* @return \DateTime|null The parsed DateTime or the default value if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*/
@@ -289,26 +289,14 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/
public function count()
{
return count($this->headers);
return \count($this->headers);
}
protected function getCacheControlHeader()
{
$parts = array();
ksort($this->cacheControl);
foreach ($this->cacheControl as $key => $value) {
if (true === $value) {
$parts[] = $key;
} else {
if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
$value = '"'.$value.'"';
}
$parts[] = "$key=$value";
}
}
return implode(', ', $parts);
return HeaderUtils::toString($this->cacheControl, ',');
}
/**
@@ -320,12 +308,8 @@ class HeaderBag implements \IteratorAggregate, \Countable
*/
protected function parseCacheControl($header)
{
$cacheControl = array();
preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
}
$parts = HeaderUtils::split($header, ',=');
return $cacheControl;
return HeaderUtils::combine($parts);
}
}

View File

@@ -0,0 +1,174 @@
<?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;
/**
* HTTP header utility functions.
*
* @author Christian Schmidt <github@chsc.dk>
*/
class HeaderUtils
{
/**
* This class should not be instantiated.
*/
private function __construct()
{
}
/**
* Splits an HTTP header by one or more separators.
*
* Example:
*
* HeaderUtils::split("da, en-gb;q=0.8", ",;")
* // => array(array('da'), array('en-gb', 'q=0.8'))
*
* @param string $header HTTP header value
* @param string $separators List of characters to split on, ordered by
* precedence, e.g. ",", ";=", or ",;="
*
* @return array Nested array with as many levels as there are characters in
* $separators
*/
public static function split(string $header, string $separators): array
{
$quotedSeparators = preg_quote($separators, '/');
preg_match_all('
/
(?!\s)
(?:
# quoted-string
"(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$)
|
# token
[^"'.$quotedSeparators.']+
)+
(?<!\s)
|
# separator
\s*
(?<separator>['.$quotedSeparators.'])
\s*
/x', trim($header), $matches, PREG_SET_ORDER);
return self::groupParts($matches, $separators);
}
/**
* Combines an array of arrays into one associative array.
*
* Each of the nested arrays should have one or two elements. The first
* value will be used as the keys in the associative array, and the second
* will be used as the values, or true if the nested array only contains one
* element. Array keys are lowercased.
*
* Example:
*
* HeaderUtils::combine(array(array("foo", "abc"), array("bar")))
* // => array("foo" => "abc", "bar" => true)
*/
public static function combine(array $parts): array
{
$assoc = array();
foreach ($parts as $part) {
$name = strtolower($part[0]);
$value = $part[1] ?? true;
$assoc[$name] = $value;
}
return $assoc;
}
/**
* Joins an associative array into a string for use in an HTTP header.
*
* The key and value of each entry are joined with "=", and all entries
* are joined with the specified separator and an additional space (for
* readability). Values are quoted if necessary.
*
* Example:
*
* HeaderUtils::toString(array("foo" => "abc", "bar" => true, "baz" => "a b c"), ",")
* // => 'foo=abc, bar, baz="a b c"'
*/
public static function toString(array $assoc, string $separator): string
{
$parts = array();
foreach ($assoc as $name => $value) {
if (true === $value) {
$parts[] = $name;
} else {
$parts[] = $name.'='.self::quote($value);
}
}
return implode($separator.' ', $parts);
}
/**
* Encodes a string as a quoted string, if necessary.
*
* If a string contains characters not allowed by the "token" construct in
* the HTTP specification, it is backslash-escaped and enclosed in quotes
* to match the "quoted-string" construct.
*/
public static function quote(string $s): string
{
if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) {
return $s;
}
return '"'.addcslashes($s, '"\\"').'"';
}
/**
* Decodes a quoted string.
*
* If passed an unquoted string that matches the "token" construct (as
* defined in the HTTP specification), it is passed through verbatimly.
*/
public static function unquote(string $s): string
{
return preg_replace('/\\\\(.)|"/', '$1', $s);
}
private static function groupParts(array $matches, string $separators): array
{
$separator = $separators[0];
$partSeparators = substr($separators, 1);
$i = 0;
$partMatches = array();
foreach ($matches as $match) {
if (isset($match['separator']) && $match['separator'] === $separator) {
++$i;
} else {
$partMatches[$i][] = $match;
}
}
$parts = array();
if ($partSeparators) {
foreach ($partMatches as $matches) {
$parts[] = self::groupParts($matches, $partSeparators);
}
} else {
foreach ($partMatches as $matches) {
$parts[] = self::unquote($matches[0][0]);
}
}
return $parts;
}
}

View File

@@ -37,7 +37,7 @@ class IpUtils
*/
public static function checkIp($requestIp, $ips)
{
if (!is_array($ips)) {
if (!\is_array($ips)) {
$ips = array($ips);
}
@@ -116,7 +116,7 @@ class IpUtils
return self::$checkedIps[$cacheKey];
}
if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) {
if (!((\extension_loaded('sockets') && \defined('AF_INET6')) || @inet_pton('::1'))) {
throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
}

View File

@@ -39,7 +39,7 @@ class JsonResponse extends Response
* @param array $headers An array of response headers
* @param bool $json If the data is already a JSON string
*/
public function __construct($data = null, $status = 200, $headers = array(), $json = false)
public function __construct($data = null, int $status = 200, array $headers = array(), bool $json = false)
{
parent::__construct('', $status, $headers);
@@ -101,7 +101,7 @@ class JsonResponse extends Response
);
$parts = explode('.', $callback);
foreach ($parts as $part) {
if (!preg_match($pattern, $part) || in_array($part, $reserved, true)) {
if (!preg_match($pattern, $part) || \in_array($part, $reserved, true)) {
throw new \InvalidArgumentException('The callback name is not valid.');
}
}
@@ -139,29 +139,13 @@ class JsonResponse extends Response
*/
public function setData($data = array())
{
if (defined('HHVM_VERSION')) {
// HHVM does not trigger any warnings and let exceptions
// thrown from a JsonSerializable object pass through.
// If only PHP did the same...
try {
$data = json_encode($data, $this->encodingOptions);
} else {
if (!interface_exists('JsonSerializable', false)) {
set_error_handler(function () { return false; });
try {
$data = @json_encode($data, $this->encodingOptions);
} finally {
restore_error_handler();
}
} else {
try {
$data = json_encode($data, $this->encodingOptions);
} catch (\Exception $e) {
if ('Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
throw $e->getPrevious() ?: $e;
}
throw $e;
}
} catch (\Exception $e) {
if ('Exception' === \get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
throw $e->getPrevious() ?: $e;
}
throw $e;
}
if (JSON_ERROR_NONE !== json_last_error()) {

View File

@@ -200,12 +200,12 @@ class ParameterBag implements \IteratorAggregate, \Countable
$value = $this->get($key, $default);
// Always turn $options into an array - this allows filter_var option shortcuts.
if (!is_array($options) && $options) {
if (!\is_array($options) && $options) {
$options = array('flags' => $options);
}
// Add a convenience check for arrays.
if (is_array($value) && !isset($options['flags'])) {
if (\is_array($value) && !isset($options['flags'])) {
$options['flags'] = FILTER_REQUIRE_ARRAY;
}
@@ -229,6 +229,6 @@ class ParameterBag implements \IteratorAggregate, \Countable
*/
public function count()
{
return count($this->parameters);
return \count($this->parameters);
}
}

View File

@@ -32,7 +32,7 @@ class RedirectResponse extends Response
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3
*/
public function __construct($url, $status = 302, $headers = array())
public function __construct(?string $url, int $status = 302, array $headers = array())
{
parent::__construct('', $status, $headers);

View File

@@ -38,15 +38,6 @@ class Request
const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers
const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO;
/** @deprecated since version 3.3, to be removed in 4.0 */
const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT;
const METHOD_HEAD = 'HEAD';
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
@@ -73,25 +64,6 @@ class Request
*/
protected static $trustedHosts = array();
/**
* Names for headers that can be trusted when
* using trusted proxies.
*
* 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).
*
* @deprecated since version 3.3, to be removed in 4.0
*/
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',
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);
protected static $httpMethodParameterOverride = false;
/**
@@ -225,15 +197,6 @@ class Request
private static $trustedHeaderSet = -1;
/** @deprecated since version 3.3, to be removed in 4.0 */
private static $trustedHeaderNames = 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',
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);
private static $forwardedParams = array(
self::HEADER_X_FORWARDED_FOR => 'for',
self::HEADER_X_FORWARDED_HOST => 'host',
@@ -241,6 +204,23 @@ class Request
self::HEADER_X_FORWARDED_PORT => 'host',
);
/**
* Names for headers that can be trusted when
* using trusted proxies.
*
* 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).
*/
private static $trustedHeaders = array(
self::HEADER_FORWARDED => 'FORWARDED',
self::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
self::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
self::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
self::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
);
/**
* @param array $query The GET parameters
* @param array $request The POST parameters
@@ -298,23 +278,10 @@ class Request
*/
public static function createFromGlobals()
{
// With the php's bug #66606, the php's built-in web server
// 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) {
if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
$server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
}
if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
$server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
}
}
$request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server);
$request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
&& in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
) {
parse_str($request->getContent(), $data);
$request->request = new ParameterBag($data);
@@ -345,7 +312,7 @@ class Request
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'HTTP_HOST' => 'localhost',
'HTTP_USER_AGENT' => 'Symfony/3.X',
'HTTP_USER_AGENT' => 'Symfony',
'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',
@@ -377,7 +344,7 @@ class Request
if (isset($components['port'])) {
$server['SERVER_PORT'] = $components['port'];
$server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$components['port'];
$server['HTTP_HOST'] .= ':'.$components['port'];
}
if (isset($components['user'])) {
@@ -566,7 +533,7 @@ class Request
foreach ($this->headers->all() as $key => $value) {
$key = strtoupper(str_replace('-', '_', $key));
if (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
if (\in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
$_SERVER[$key] = implode(', ', $value);
} else {
$_SERVER['HTTP_'.$key] = implode(', ', $value);
@@ -594,20 +561,9 @@ class Request
*
* @throws \InvalidArgumentException When $trustedHeaderSet is invalid
*/
public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/)
public static function setTrustedProxies(array $proxies, int $trustedHeaderSet)
{
self::$trustedProxies = $proxies;
if (2 > func_num_args()) {
@trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED);
return;
}
$trustedHeaderSet = (int) func_get_arg(1);
foreach (self::$trustedHeaderNames as $header => $name) {
self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null;
}
self::$trustedHeaderSet = $trustedHeaderSet;
}
@@ -657,78 +613,6 @@ class Request
return self::$trustedHostPatterns;
}
/**
* Sets the name for trusted headers.
*
* The following header keys are supported:
*
* * Request::HEADER_CLIENT_IP: defaults to X-Forwarded-For (see getClientIp())
* * Request::HEADER_CLIENT_HOST: defaults to X-Forwarded-Host (see getHost())
* * Request::HEADER_CLIENT_PORT: defaults to X-Forwarded-Port (see getPort())
* * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure())
* * Request::HEADER_FORWARDED: defaults to Forwarded (see RFC 7239)
*
* Setting an empty value allows to disable the trusted header for the given key.
*
* @param string $key The header key
* @param string $value The header name
*
* @throws \InvalidArgumentException
*
* @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public static function setTrustedHeaderName($key, $value)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
if ('forwarded' === $key) {
$key = self::HEADER_FORWARDED;
} elseif ('client_ip' === $key) {
$key = self::HEADER_CLIENT_IP;
} elseif ('client_host' === $key) {
$key = self::HEADER_CLIENT_HOST;
} elseif ('client_proto' === $key) {
$key = self::HEADER_CLIENT_PROTO;
} elseif ('client_port' === $key) {
$key = self::HEADER_CLIENT_PORT;
} elseif (!array_key_exists($key, self::$trustedHeaders)) {
throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
}
self::$trustedHeaders[$key] = $value;
if (null !== $value) {
self::$trustedHeaderNames[$key] = $value;
self::$trustedHeaderSet |= $key;
} else {
self::$trustedHeaderSet &= ~$key;
}
}
/**
* Gets the trusted proxy header name.
*
* @param string $key The header key
*
* @return string The header name
*
* @throws \InvalidArgumentException
*
* @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.
*/
public static function getTrustedHeaderName($key)
{
if (2 > func_num_args() || func_get_arg(1)) {
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), E_USER_DEPRECATED);
}
if (!array_key_exists($key, self::$trustedHeaders)) {
throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key));
}
return self::$trustedHeaders[$key];
}
/**
* Normalizes a query string.
*
@@ -745,31 +629,10 @@ class Request
return '';
}
$parts = array();
$order = array();
parse_str($qs, $qs);
ksort($qs);
foreach (explode('&', $qs) as $param) {
if ('' === $param || '=' === $param[0]) {
// Ignore useless delimiters, e.g. "x=y&".
// Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
// PHP also does not include them when building _GET.
continue;
}
$keyValuePair = explode('=', $param, 2);
// GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
// PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. This is why we use urldecode and then normalize to
// RFC 3986 with rawurlencode.
$parts[] = isset($keyValuePair[1]) ?
rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) :
rawurlencode(urldecode($keyValuePair[0]));
$order[] = urldecode($keyValuePair[0]);
}
array_multisort($order, SORT_ASC, $parts);
return implode('&', $parts);
return http_build_query($qs, '', '&', PHP_QUERY_RFC3986);
}
/**
@@ -836,7 +699,17 @@ class Request
*/
public function getSession()
{
return $this->session;
$session = $this->session;
if (!$session instanceof SessionInterface && null !== $session) {
$this->setSession($session = $session());
}
if (null === $session) {
@trigger_error(sprintf('Calling "%s()" when no session has been set is deprecated since Symfony 4.1 and will throw an exception in 5.0. Use "hasSession()" instead.', __METHOD__), E_USER_DEPRECATED);
// throw new \BadMethodCallException('Session has not been set');
}
return $session;
}
/**
@@ -848,7 +721,7 @@ class Request
public function hasPreviousSession()
{
// the check for $this->session avoids malicious users trying to fake a session cookie with proper name
return $this->hasSession() && $this->cookies->has($this->session->getName());
return $this->hasSession() && $this->cookies->has($this->getSession()->getName());
}
/**
@@ -875,6 +748,14 @@ class Request
$this->session = $session;
}
/**
* @internal
*/
public function setSessionFactory(callable $factory)
{
$this->session = $factory;
}
/**
* Returns the client IP addresses.
*
@@ -896,7 +777,7 @@ class Request
return array($ip);
}
return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: array($ip);
return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: array($ip);
}
/**
@@ -908,10 +789,6 @@ class Request
* being the original client, and each successive proxy that passed the request
* adding the IP address where it received the request from.
*
* If your reverse proxy uses a different header name than "X-Forwarded-For",
* ("Client-Ip" for instance), configure it via the $trustedHeaderSet
* argument of the Request::setTrustedProxies() method instead.
*
* @return string|null The client IP address
*
* @see getClientIps()
@@ -1015,17 +892,13 @@ class Request
*
* The "X-Forwarded-Port" header must contain the client port.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
* configure it via via the $trustedHeaderSet argument of the
* Request::setTrustedProxies() method instead.
*
* @return int|string can be a string if fetched from the server bag
*/
public function getPort()
{
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) {
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) {
$host = $host[0];
} elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
} elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
$host = $host[0];
} elseif (!$host = $this->headers->get('HOST')) {
return $this->server->get('SERVER_PORT');
@@ -1186,7 +1059,7 @@ class Request
}
$sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
$targetDirs = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
$targetDirs = explode('/', substr($path, 1));
array_pop($sourceDirs);
$targetFile = array_pop($targetDirs);
@@ -1199,7 +1072,7 @@ class Request
}
$targetDirs[] = $targetFile;
$path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
$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
@@ -1233,16 +1106,12 @@ class Request
*
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
*
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
* ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet
* argument of the Request::setTrustedProxies() method instead.
*
* @return bool
*/
public function isSecure()
{
if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) {
return in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true);
if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) {
return \in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true);
}
$https = $this->server->get('HTTPS');
@@ -1258,17 +1127,13 @@ class Request
*
* The "X-Forwarded-Host" header must contain the client host name.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
* configure it via the $trustedHeaderSet argument of the
* Request::setTrustedProxies() method instead.
*
* @return string
*
* @throws SuspiciousOperationException when the host name is invalid or not trusted
*/
public function getHost()
{
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
$host = $host[0];
} elseif (!$host = $this->headers->get('HOST')) {
if (!$host = $this->server->get('SERVER_NAME')) {
@@ -1292,10 +1157,10 @@ class Request
throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host));
}
if (count(self::$trustedHostPatterns) > 0) {
if (\count(self::$trustedHostPatterns) > 0) {
// to avoid host header injection attacks, you should provide a list of trusted host patterns
if (in_array($host, self::$trustedHosts)) {
if (\in_array($host, self::$trustedHosts)) {
return $host;
}
@@ -1353,7 +1218,10 @@ class Request
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
$method = $this->request->get('_method', $this->query->get('_method', 'POST'));
if (\is_string($method)) {
$this->method = strtoupper($method);
}
}
}
}
@@ -1424,10 +1292,10 @@ class Request
}
foreach (static::$formats as $format => $mimeTypes) {
if (in_array($mimeType, (array) $mimeTypes)) {
if (\in_array($mimeType, (array) $mimeTypes)) {
return $format;
}
if (null !== $canonicalMimeType && in_array($canonicalMimeType, (array) $mimeTypes)) {
if (null !== $canonicalMimeType && \in_array($canonicalMimeType, (array) $mimeTypes)) {
return $format;
}
}
@@ -1445,7 +1313,7 @@ class Request
static::initializeFormats();
}
static::$formats[$format] = is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : array($mimeTypes);
}
/**
@@ -1457,7 +1325,7 @@ class Request
* * _format request attribute
* * $default
*
* @param string $default The default format
* @param string|null $default The default format
*
* @return string The request format
*/
@@ -1557,15 +1425,12 @@ class Request
*/
public function isMethodSafe(/* $andCacheable = true */)
{
if (!func_num_args() || func_get_arg(0)) {
// This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature)
// then setting $andCacheable to false should be deprecated in 4.1
@trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', E_USER_DEPRECATED);
return in_array($this->getMethod(), array('GET', 'HEAD'));
if (!\func_num_args() || func_get_arg(0)) {
// setting $andCacheable to false should be deprecated in 4.1
throw new \BadMethodCallException('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is not supported.');
}
return in_array($this->getMethod(), array('GET', 'HEAD', 'OPTIONS', 'TRACE'));
return \in_array($this->getMethod(), array('GET', 'HEAD', 'OPTIONS', 'TRACE'));
}
/**
@@ -1575,7 +1440,7 @@ class Request
*/
public function isMethodIdempotent()
{
return in_array($this->getMethod(), array('HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE'));
return \in_array($this->getMethod(), array('HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE'));
}
/**
@@ -1587,7 +1452,7 @@ class Request
*/
public function isMethodCacheable()
{
return in_array($this->getMethod(), array('GET', 'HEAD'));
return \in_array($this->getMethod(), array('GET', 'HEAD'));
}
/**
@@ -1625,10 +1490,7 @@ class Request
*/
public function getContent($asResource = false)
{
$currentContentIsResource = is_resource($this->content);
if (\PHP_VERSION_ID < 50600 && false === $this->content) {
throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.');
}
$currentContentIsResource = \is_resource($this->content);
if (true === $asResource) {
if ($currentContentIsResource) {
@@ -1638,7 +1500,7 @@ class Request
}
// Content passed in parameter (test)
if (is_string($this->content)) {
if (\is_string($this->content)) {
$resource = fopen('php://temp', 'r+');
fwrite($resource, $this->content);
rewind($resource);
@@ -1706,7 +1568,7 @@ class Request
$extendedPreferredLanguages[] = $language;
if (false !== $position = strpos($language, '_')) {
$superLanguage = substr($language, 0, $position);
if (!in_array($superLanguage, $preferredLanguages)) {
if (!\in_array($superLanguage, $preferredLanguages)) {
$extendedPreferredLanguages[] = $superLanguage;
}
}
@@ -1737,11 +1599,11 @@ class Request
// Language not listed in ISO 639 that are not variants
// of any listed language, which can be registered with the
// i-prefix, such as i-cherokee
if (count($codes) > 1) {
if (\count($codes) > 1) {
$lang = $codes[1];
}
} else {
for ($i = 0, $max = count($codes); $i < $max; ++$i) {
for ($i = 0, $max = \count($codes); $i < $max; ++$i) {
if (0 === $i) {
$lang = strtolower($codes[0]);
} else {
@@ -1826,18 +1688,7 @@ class Request
{
$requestUri = '';
if ($this->headers->has('X_ORIGINAL_URL')) {
// IIS with Microsoft Rewrite Module
$requestUri = $this->headers->get('X_ORIGINAL_URL');
$this->headers->remove('X_ORIGINAL_URL');
$this->server->remove('HTTP_X_ORIGINAL_URL');
$this->server->remove('UNENCODED_URL');
$this->server->remove('IIS_WasUrlRewritten');
} elseif ($this->headers->has('X_REWRITE_URL')) {
// IIS with ISAPI_Rewrite
$requestUri = $this->headers->get('X_REWRITE_URL');
$this->headers->remove('X_REWRITE_URL');
} elseif ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
// IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
$requestUri = $this->server->get('UNENCODED_URL');
$this->server->remove('UNENCODED_URL');
@@ -1847,7 +1698,7 @@ class Request
// HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, only use URL path
$schemeAndHttpHost = $this->getSchemeAndHttpHost();
if (0 === strpos($requestUri, $schemeAndHttpHost)) {
$requestUri = substr($requestUri, strlen($schemeAndHttpHost));
$requestUri = substr($requestUri, \strlen($schemeAndHttpHost));
}
} elseif ($this->server->has('ORIG_PATH_INFO')) {
// IIS 5.0, PHP as CGI
@@ -1887,7 +1738,7 @@ class Request
$segs = explode('/', trim($file, '/'));
$segs = array_reverse($segs);
$index = 0;
$last = count($segs);
$last = \count($segs);
$baseUrl = '';
do {
$seg = $segs[$index];
@@ -1907,9 +1758,9 @@ class Request
return $prefix;
}
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/'.DIRECTORY_SEPARATOR).'/')) {
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) {
// directory portion of $baseUrl matches
return rtrim($prefix, '/'.DIRECTORY_SEPARATOR);
return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR);
}
$truncatedRequestUri = $requestUri;
@@ -1926,11 +1777,11 @@ class Request
// If using mod_rewrite or ISAPI_Rewrite strip the script filename
// out of baseUrl. $pos !== 0 makes sure it is not matching a value
// from PATH_INFO or QUERY_STRING
if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) {
$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
if (\strlen($requestUri) >= \strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) {
$baseUrl = substr($requestUri, 0, $pos + \strlen($baseUrl));
}
return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR);
return rtrim($baseUrl, '/'.\DIRECTORY_SEPARATOR);
}
/**
@@ -1947,12 +1798,12 @@ class Request
$filename = basename($this->server->get('SCRIPT_FILENAME'));
if (basename($baseUrl) === $filename) {
$basePath = dirname($baseUrl);
$basePath = \dirname($baseUrl);
} else {
$basePath = $baseUrl;
}
if ('\\' === DIRECTORY_SEPARATOR) {
if ('\\' === \DIRECTORY_SEPARATOR) {
$basePath = str_replace('\\', '/', $basePath);
}
@@ -1982,7 +1833,7 @@ class Request
return $requestUri;
}
$pathInfo = substr($requestUri, strlen($baseUrl));
$pathInfo = substr($requestUri, \strlen($baseUrl));
if (false === $pathInfo || '' === $pathInfo) {
// If substr() returns false then PATH_INFO is set to an empty string
return '/';
@@ -2011,12 +1862,7 @@ class Request
);
}
/**
* Sets the default PHP locale.
*
* @param string $locale
*/
private function setPhpDefaultLocale($locale)
private function setPhpDefaultLocale(string $locale)
{
// if either the class Locale doesn't exist, or an exception is thrown when
// setting the default locale, the intl module is not installed, and
@@ -2033,18 +1879,15 @@ class Request
* Returns the prefix as encoded in the string when the string starts with
* the given prefix, false otherwise.
*
* @param string $string The urlencoded string
* @param string $prefix The prefix not encoded
*
* @return string|false The prefix as it is encoded in $string, or false
*/
private function getUrlencodedPrefix($string, $prefix)
private function getUrlencodedPrefix(string $string, string $prefix)
{
if (0 !== strpos(rawurldecode($string), $prefix)) {
return false;
}
$len = strlen($prefix);
$len = \strlen($prefix);
if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) {
return $match[0];
@@ -2056,7 +1899,7 @@ class Request
private static function createRequestFromFactory(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
if (self::$requestFactory) {
$request = call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
$request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content);
if (!$request instanceof self) {
throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.');
@@ -2086,15 +1929,29 @@ class Request
$clientValues = array();
$forwardedValues = array();
if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) {
if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::$trustedHeaders[$type])) {
foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) {
$clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v);
$clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ? '0.0.0.0:' : '').trim($v);
}
}
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
$forwarded = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
$parts = HeaderUtils::split($forwarded, ',;=');
$forwardedValues = array();
$param = self::$forwardedParams[$type];
foreach ($parts as $subParts) {
if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) {
continue;
}
if (self::HEADER_X_FORWARDED_PORT === $type) {
if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) {
$v = $this->isSecure() ? ':443' : ':80';
}
$v = '0.0.0.0'.$v;
}
$forwardedValues[] = $v;
}
}
if (null !== $ip) {
@@ -2127,9 +1984,17 @@ class Request
$firstTrustedIp = null;
foreach ($clientIps as $key => $clientIp) {
// Remove port (unfortunately, it does happen)
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
$clientIps[$key] = $clientIp = $match[1];
if (strpos($clientIp, '.')) {
// Strip :port from IPv4 addresses. This is allowed in Forwarded
// and may occur in X-Forwarded-For.
$i = strpos($clientIp, ':');
if ($i) {
$clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
}
} elseif (0 === strpos($clientIp, '[')) {
// Strip brackets and :port from IPv6 addresses.
$i = strpos($clientIp, ']', 1);
$clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
}
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {

View File

@@ -56,7 +56,7 @@ class RequestMatcher implements RequestMatcherInterface
* @param array $attributes
* @param string|string[]|null $schemes
*/
public function __construct($path = null, $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null)
public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null)
{
$this->matchPath($path);
$this->matchHost($host);
@@ -145,11 +145,11 @@ class RequestMatcher implements RequestMatcherInterface
*/
public function matches(Request $request)
{
if ($this->schemes && !in_array($request->getScheme(), $this->schemes, true)) {
if ($this->schemes && !\in_array($request->getScheme(), $this->schemes, true)) {
return false;
}
if ($this->methods && !in_array($request->getMethod(), $this->methods, true)) {
if ($this->methods && !\in_array($request->getMethod(), $this->methods, true)) {
return false;
}
@@ -173,6 +173,6 @@ class RequestMatcher implements RequestMatcherInterface
// Note to future implementors: add additional checks above the
// foreach above or else your check might not be run!
return 0 === count($this->ips);
return 0 === \count($this->ips);
}
}

View File

@@ -92,7 +92,7 @@ class RequestStack
*/
public function getParentRequest()
{
$pos = count($this->requests) - 2;
$pos = \count($this->requests) - 2;
if (!isset($this->requests[$pos])) {
return;

View File

@@ -64,7 +64,12 @@ class Response
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
const HTTP_LOCKED = 423; // RFC4918
const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
/**
* @deprecated
*/
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04
const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
@@ -169,7 +174,7 @@ class Response
422 => 'Unprocessable Entity', // RFC4918
423 => 'Locked', // RFC4918
424 => 'Failed Dependency', // RFC4918
425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817
425 => 'Too Early', // RFC-ietf-httpbis-replay-04
426 => 'Upgrade Required', // RFC2817
428 => 'Precondition Required', // RFC6585
429 => 'Too Many Requests', // RFC6585
@@ -189,13 +194,9 @@ class Response
);
/**
* @param mixed $content The response content, see setContent()
* @param int $status The response status code
* @param array $headers An array of response headers
*
* @throws \InvalidArgumentException When the HTTP status code is not valid
*/
public function __construct($content = '', $status = 200, $headers = array())
public function __construct($content = '', int $status = 200, array $headers = array())
{
$this->headers = new ResponseHeaderBag($headers);
$this->setContent($content);
@@ -328,12 +329,17 @@ class Response
}
// headers
foreach ($this->headers->allPreserveCase() as $name => $values) {
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
foreach ($values as $value) {
header($name.': '.$value, false, $this->statusCode);
}
}
// cookies
foreach ($this->headers->getCookies() as $cookie) {
header('Set-Cookie: '.$cookie->getName().strstr($cookie, '='), false, $this->statusCode);
}
// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
@@ -362,9 +368,9 @@ class Response
$this->sendHeaders();
$this->sendContent();
if (function_exists('fastcgi_finish_request')) {
if (\function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (!\in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) {
} elseif (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
static::closeOutputBuffers(0, true);
}
@@ -384,8 +390,8 @@ class Response
*/
public function setContent($content)
{
if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) {
throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', gettype($content)));
if (null !== $content && !\is_string($content) && !is_numeric($content) && !\is_callable(array($content, '__toString'))) {
throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', \gettype($content)));
}
$this->content = (string) $content;
@@ -406,13 +412,11 @@ class Response
/**
* Sets the HTTP protocol version (1.0 or 1.1).
*
* @param string $version The HTTP protocol version
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setProtocolVersion($version)
public function setProtocolVersion(string $version)
{
$this->version = $version;
@@ -422,11 +426,9 @@ class Response
/**
* Gets the HTTP protocol version.
*
* @return string The HTTP protocol version
*
* @final since version 3.2
* @final
*/
public function getProtocolVersion()
public function getProtocolVersion(): string
{
return $this->version;
}
@@ -437,18 +439,15 @@ class Response
* If the status text is null it will be automatically populated for the known
* status codes and left empty otherwise.
*
* @param int $code HTTP status code
* @param mixed $text HTTP status text
*
* @return $this
*
* @throws \InvalidArgumentException When the HTTP status code is not valid
*
* @final since version 3.2
* @final
*/
public function setStatusCode($code, $text = null)
public function setStatusCode(int $code, $text = null)
{
$this->statusCode = $code = (int) $code;
$this->statusCode = $code;
if ($this->isInvalid()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
}
@@ -473,11 +472,9 @@ class Response
/**
* Retrieves the status code for the current web response.
*
* @return int Status code
*
* @final since version 3.2
* @final
*/
public function getStatusCode()
public function getStatusCode(): int
{
return $this->statusCode;
}
@@ -485,13 +482,11 @@ class Response
/**
* Sets the response charset.
*
* @param string $charset Character set
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setCharset($charset)
public function setCharset(string $charset)
{
$this->charset = $charset;
@@ -501,11 +496,9 @@ class Response
/**
* Retrieves the response charset.
*
* @return string Character set
*
* @final since version 3.2
* @final
*/
public function getCharset()
public function getCharset(): ?string
{
return $this->charset;
}
@@ -525,13 +518,11 @@ class Response
* can be reused by a cache with heuristic expiration unless otherwise indicated"
* (https://tools.ietf.org/html/rfc7231#section-6.1)
*
* @return bool true if the response is worth caching, false otherwise
*
* @final since version 3.3
* @final
*/
public function isCacheable()
public function isCacheable(): bool
{
if (!in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) {
if (!\in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) {
return false;
}
@@ -549,11 +540,9 @@ class Response
* origin. A response is considered fresh when it includes a Cache-Control/max-age
* indicator or Expires header and the calculated age is less than the freshness lifetime.
*
* @return bool true if the response is fresh, false otherwise
*
* @final since version 3.3
* @final
*/
public function isFresh()
public function isFresh(): bool
{
return $this->getTtl() > 0;
}
@@ -562,11 +551,9 @@ class Response
* Returns true if the response includes headers that can be used to validate
* the response with the origin server using a conditional GET request.
*
* @return bool true if the response is validateable, false otherwise
*
* @final since version 3.3
* @final
*/
public function isValidateable()
public function isValidateable(): bool
{
return $this->headers->has('Last-Modified') || $this->headers->has('ETag');
}
@@ -578,7 +565,7 @@ class Response
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setPrivate()
{
@@ -595,7 +582,7 @@ class Response
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setPublic()
{
@@ -608,13 +595,11 @@ class Response
/**
* Marks the response as "immutable".
*
* @param bool $immutable enables or disables the immutable directive
*
* @return $this
*
* @final
*/
public function setImmutable($immutable = true)
public function setImmutable(bool $immutable = true)
{
if ($immutable) {
$this->headers->addCacheControlDirective('immutable');
@@ -628,11 +613,9 @@ class Response
/**
* Returns true if the response is marked as "immutable".
*
* @return bool returns true if the response is marked as "immutable"; otherwise false
*
* @final
*/
public function isImmutable()
public function isImmutable(): bool
{
return $this->headers->hasCacheControlDirective('immutable');
}
@@ -645,11 +628,9 @@ class Response
* When present, the TTL of the response should not be overridden to be
* greater than the value provided by the origin.
*
* @return bool true if the response must be revalidated by a cache, false otherwise
*
* @final since version 3.3
* @final
*/
public function mustRevalidate()
public function mustRevalidate(): bool
{
return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate');
}
@@ -657,13 +638,11 @@ class Response
/**
* Returns the Date header as a DateTime instance.
*
* @return \DateTime A \DateTime instance
*
* @throws \RuntimeException When the header is not parseable
*
* @final since version 3.2
* @final
*/
public function getDate()
public function getDate(): ?\DateTimeInterface
{
return $this->headers->getDate('Date');
}
@@ -673,24 +652,26 @@ class Response
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setDate(\DateTime $date)
public function setDate(\DateTimeInterface $date)
{
$date->setTimezone(new \DateTimeZone('UTC'));
if ($date instanceof \DateTime) {
$date = \DateTimeImmutable::createFromMutable($date);
}
$date = $date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
/**
* Returns the age of the response.
* Returns the age of the response in seconds.
*
* @return int The age of the response in seconds
*
* @final since version 3.2
* @final
*/
public function getAge()
public function getAge(): int
{
if (null !== $age = $this->headers->get('Age')) {
return (int) $age;
@@ -708,6 +689,7 @@ class Response
{
if ($this->isFresh()) {
$this->headers->set('Age', $this->getMaxAge());
$this->headers->remove('Expires');
}
return $this;
@@ -716,17 +698,15 @@ 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
*
* @final since version 3.2
* @final
*/
public function getExpires()
public function getExpires(): ?\DateTimeInterface
{
try {
return $this->headers->getDate('Expires');
} catch (\RuntimeException $e) {
// according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past
return \DateTime::createFromFormat(DATE_RFC2822, 'Sat, 01 Jan 00 00:00:00 +0000');
return \DateTime::createFromFormat('U', time() - 172800);
}
}
@@ -735,22 +715,25 @@ class Response
*
* Passing null as value will remove the header.
*
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setExpires(\DateTime $date = null)
public function setExpires(\DateTimeInterface $date = null)
{
if (null === $date) {
$this->headers->remove('Expires');
} else {
$date = clone $date;
$date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
if ($date instanceof \DateTime) {
$date = \DateTimeImmutable::createFromMutable($date);
}
$date = $date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
@@ -761,11 +744,9 @@ class Response
* First, it checks for a s-maxage directive, then a max-age directive, and then it falls
* back on an expires header. It returns null when no maximum age can be established.
*
* @return int|null Number of seconds
*
* @final since version 3.2
* @final
*/
public function getMaxAge()
public function getMaxAge(): ?int
{
if ($this->headers->hasCacheControlDirective('s-maxage')) {
return (int) $this->headers->getCacheControlDirective('s-maxage');
@@ -776,8 +757,10 @@ class Response
}
if (null !== $this->getExpires()) {
return $this->getExpires()->format('U') - $this->getDate()->format('U');
return (int) ($this->getExpires()->format('U') - $this->getDate()->format('U'));
}
return null;
}
/**
@@ -785,13 +768,11 @@ class Response
*
* This methods sets the Cache-Control max-age directive.
*
* @param int $value Number of seconds
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setMaxAge($value)
public function setMaxAge(int $value)
{
$this->headers->addCacheControlDirective('max-age', $value);
@@ -803,13 +784,11 @@ class Response
*
* This methods sets the Cache-Control s-maxage directive.
*
* @param int $value Number of seconds
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setSharedMaxAge($value)
public function setSharedMaxAge(int $value)
{
$this->setPublic();
$this->headers->addCacheControlDirective('s-maxage', $value);
@@ -825,29 +804,25 @@ class Response
* When the responses TTL is <= 0, the response may not be served from cache without first
* revalidating with the origin.
*
* @return int|null The TTL in seconds
*
* @final since version 3.2
* @final
*/
public function getTtl()
public function getTtl(): ?int
{
if (null !== $maxAge = $this->getMaxAge()) {
return $maxAge - $this->getAge();
}
$maxAge = $this->getMaxAge();
return null !== $maxAge ? $maxAge - $this->getAge() : null;
}
/**
* Sets the response's time-to-live for shared caches.
* Sets the response's time-to-live for shared caches in seconds.
*
* This method adjusts the Cache-Control/s-maxage directive.
*
* @param int $seconds Number of seconds
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setTtl($seconds)
public function setTtl(int $seconds)
{
$this->setSharedMaxAge($this->getAge() + $seconds);
@@ -855,17 +830,15 @@ class Response
}
/**
* Sets the response's time-to-live for private/client caches.
* Sets the response's time-to-live for private/client caches in seconds.
*
* This method adjusts the Cache-Control/max-age directive.
*
* @param int $seconds Number of seconds
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setClientTtl($seconds)
public function setClientTtl(int $seconds)
{
$this->setMaxAge($this->getAge() + $seconds);
@@ -875,13 +848,11 @@ class Response
/**
* Returns the Last-Modified HTTP header as a DateTime instance.
*
* @return \DateTime|null A DateTime instance or null if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*
* @final since version 3.2
* @final
*/
public function getLastModified()
public function getLastModified(): ?\DateTimeInterface
{
return $this->headers->getDate('Last-Modified');
}
@@ -891,33 +862,34 @@ class Response
*
* Passing null as value will remove the header.
*
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setLastModified(\DateTime $date = null)
public function setLastModified(\DateTimeInterface $date = null)
{
if (null === $date) {
$this->headers->remove('Last-Modified');
} else {
$date = clone $date;
$date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
if ($date instanceof \DateTime) {
$date = \DateTimeImmutable::createFromMutable($date);
}
$date = $date->setTimezone(new \DateTimeZone('UTC'));
$this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT');
return $this;
}
/**
* Returns the literal value of the ETag HTTP header.
*
* @return string|null The ETag HTTP header or null if it does not exist
*
* @final since version 3.2
* @final
*/
public function getEtag()
public function getEtag(): ?string
{
return $this->headers->get('ETag');
}
@@ -930,9 +902,9 @@ class Response
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setEtag($etag = null, $weak = false)
public function setEtag(string $etag = null, bool $weak = false)
{
if (null === $etag) {
$this->headers->remove('Etag');
@@ -952,13 +924,11 @@ class Response
*
* Available options are: etag, last_modified, max_age, s_maxage, private, public and immutable.
*
* @param array $options An array of cache options
*
* @return $this
*
* @throws \InvalidArgumentException
*
* @final since version 3.3
* @final
*/
public function setCache(array $options)
{
@@ -1015,7 +985,7 @@ class Response
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3.5
*
* @final since version 3.3
* @final
*/
public function setNotModified()
{
@@ -1033,11 +1003,9 @@ class Response
/**
* Returns true if the response includes a Vary header.
*
* @return bool true if the response includes a Vary header, false otherwise
*
* @final since version 3.2
* @final
*/
public function hasVary()
public function hasVary(): bool
{
return null !== $this->headers->get('Vary');
}
@@ -1045,11 +1013,9 @@ class Response
/**
* Returns an array of header names given in the Vary header.
*
* @return array An array of Vary names
*
* @final since version 3.2
* @final
*/
public function getVary()
public function getVary(): array
{
if (!$vary = $this->headers->get('Vary', null, false)) {
return array();
@@ -1071,9 +1037,9 @@ class Response
*
* @return $this
*
* @final since version 3.2
* @final
*/
public function setVary($headers, $replace = true)
public function setVary($headers, bool $replace = true)
{
$this->headers->set('Vary', $headers, $replace);
@@ -1089,9 +1055,9 @@ class Response
*
* @return bool true if the Response validators match the Request, false otherwise
*
* @final since version 3.3
* @final
*/
public function isNotModified(Request $request)
public function isNotModified(Request $request): bool
{
if (!$request->isMethodCacheable()) {
return false;
@@ -1102,7 +1068,7 @@ class Response
$modifiedSince = $request->headers->get('If-Modified-Since');
if ($etags = $request->getETags()) {
$notModified = in_array($this->getEtag(), $etags) || in_array('*', $etags);
$notModified = \in_array($this->getEtag(), $etags) || \in_array('*', $etags);
}
if ($modifiedSince && $lastModified) {
@@ -1119,13 +1085,11 @@ class Response
/**
* Is response invalid?
*
* @return bool
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*
* @final since version 3.2
* @final
*/
public function isInvalid()
public function isInvalid(): bool
{
return $this->statusCode < 100 || $this->statusCode >= 600;
}
@@ -1133,11 +1097,9 @@ class Response
/**
* Is response informative?
*
* @return bool
*
* @final since version 3.3
* @final
*/
public function isInformational()
public function isInformational(): bool
{
return $this->statusCode >= 100 && $this->statusCode < 200;
}
@@ -1145,11 +1107,9 @@ class Response
/**
* Is response successful?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isSuccessful()
public function isSuccessful(): bool
{
return $this->statusCode >= 200 && $this->statusCode < 300;
}
@@ -1157,11 +1117,9 @@ class Response
/**
* Is the response a redirect?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isRedirection()
public function isRedirection(): bool
{
return $this->statusCode >= 300 && $this->statusCode < 400;
}
@@ -1169,11 +1127,9 @@ class Response
/**
* Is there a client error?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isClientError()
public function isClientError(): bool
{
return $this->statusCode >= 400 && $this->statusCode < 500;
}
@@ -1181,11 +1137,9 @@ class Response
/**
* Was there a server side error?
*
* @return bool
*
* @final since version 3.3
* @final
*/
public function isServerError()
public function isServerError(): bool
{
return $this->statusCode >= 500 && $this->statusCode < 600;
}
@@ -1193,11 +1147,9 @@ class Response
/**
* Is the response OK?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isOk()
public function isOk(): bool
{
return 200 === $this->statusCode;
}
@@ -1205,11 +1157,9 @@ class Response
/**
* Is the response forbidden?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isForbidden()
public function isForbidden(): bool
{
return 403 === $this->statusCode;
}
@@ -1217,11 +1167,9 @@ class Response
/**
* Is the response a not found error?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isNotFound()
public function isNotFound(): bool
{
return 404 === $this->statusCode;
}
@@ -1229,27 +1177,21 @@ class Response
/**
* Is the response a redirect of some form?
*
* @param string $location
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isRedirect($location = null)
public function isRedirect(string $location = null): bool
{
return in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (null === $location ?: $location == $this->headers->get('Location'));
return \in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (null === $location ?: $location == $this->headers->get('Location'));
}
/**
* Is the response empty?
*
* @return bool
*
* @final since version 3.2
* @final
*/
public function isEmpty()
public function isEmpty(): bool
{
return in_array($this->statusCode, array(204, 304));
return \in_array($this->statusCode, array(204, 304));
}
/**
@@ -1257,17 +1199,13 @@ class Response
*
* Resulting level can be greater than target level if a non-removable buffer has been encountered.
*
* @param int $targetLevel The target output buffering level
* @param bool $flush Whether to flush or clean the buffers
*
* @final since version 3.3
* @final
*/
public static function closeOutputBuffers($targetLevel, $flush)
public static function closeOutputBuffers(int $targetLevel, bool $flush)
{
$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;
$level = \count($status);
$flags = PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE);
while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) {
if ($flush) {
@@ -1283,7 +1221,7 @@ class Response
*
* @see http://support.microsoft.com/kb/323308
*
* @final since version 3.3
* @final
*/
protected function ensureIEOverSSLCompatibility(Request $request)
{

View File

@@ -210,13 +210,13 @@ class ResponseHeaderBag extends HeaderBag
*
* @param string $format
*
* @return array
* @return Cookie[]
*
* @throws \InvalidArgumentException When the $format is invalid
*/
public function getCookies($format = self::COOKIES_FLAT)
{
if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
if (!\in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
}
@@ -267,7 +267,7 @@ class ResponseHeaderBag extends HeaderBag
*/
public function makeDisposition($disposition, $filename, $filenameFallback = '')
{
if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
if (!\in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
}
@@ -290,13 +290,12 @@ class ResponseHeaderBag extends HeaderBag
throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
}
$output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
$params = array('filename' => $filenameFallback);
if ($filename !== $filenameFallback) {
$output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
$params['filename*'] = "utf-8''".rawurlencode($filename);
}
return $output;
return $disposition.'; '.HeaderUtils::toString($params, ';');
}
/**

View File

@@ -68,7 +68,7 @@ class ServerBag extends ParameterBag
if (0 === stripos($authorizationHeader, 'basic ')) {
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)), 2);
if (2 == count($exploded)) {
if (2 == \count($exploded)) {
list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
}
} elseif (empty($this->parameters['PHP_AUTH_DIGEST']) && (0 === stripos($authorizationHeader, 'digest '))) {

View File

@@ -24,7 +24,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
/**
* @param string $storageKey The key used to store attributes in the session
*/
public function __construct($storageKey = '_sf2_attributes')
public function __construct(string $storageKey = '_sf2_attributes')
{
$this->storageKey = $storageKey;
}
@@ -143,6 +143,6 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
*/
public function count()
{
return count($this->attributes);
return \count($this->attributes);
}
}

View File

@@ -25,7 +25,7 @@ class NamespacedAttributeBag extends AttributeBag
* @param string $storageKey Session storage key
* @param string $namespaceCharacter Namespace character to use in keys
*/
public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/')
public function __construct(string $storageKey = '_sf2_attributes', string $namespaceCharacter = '/')
{
$this->namespaceCharacter = $namespaceCharacter;
parent::__construct($storageKey);
@@ -110,7 +110,7 @@ class NamespacedAttributeBag extends AttributeBag
}
$parts = explode($this->namespaceCharacter, $name);
if (count($parts) < 2) {
if (\count($parts) < 2) {
if (!$writeContext) {
return $array;
}
@@ -120,11 +120,17 @@ class NamespacedAttributeBag extends AttributeBag
return $array;
}
unset($parts[count($parts) - 1]);
unset($parts[\count($parts) - 1]);
foreach ($parts as $part) {
if (null !== $array && !array_key_exists($part, $array)) {
$array[$part] = $writeContext ? array() : null;
if (!$writeContext) {
$null = null;
return $null;
}
$array[$part] = array();
}
$array = &$array[$part];

View File

@@ -25,7 +25,7 @@ class AutoExpireFlashBag implements FlashBagInterface
/**
* @param string $storageKey The key used to store flashes in the session
*/
public function __construct($storageKey = '_symfony_flashes')
public function __construct(string $storageKey = '_symfony_flashes')
{
$this->storageKey = $storageKey;
}

View File

@@ -25,7 +25,7 @@ class FlashBag implements FlashBagInterface
/**
* @param string $storageKey The key used to store flashes in the session
*/
public function __construct($storageKey = '_symfony_flashes')
public function __construct(string $storageKey = '_symfony_flashes')
{
$this->storageKey = $storageKey;
}

View File

@@ -24,7 +24,7 @@ interface FlashBagInterface extends SessionBagInterface
* Adds a flash message for type.
*
* @param string $type
* @param string $message
* @param mixed $message
*/
public function add($type, $message);

View File

@@ -11,12 +11,12 @@
namespace Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
@@ -29,7 +29,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
private $flashName;
private $attributeName;
private $data = array();
private $hasBeenStarted;
private $usageIndex = 0;
/**
* @param SessionStorageInterface $storage A SessionStorageInterface instance
@@ -138,17 +138,17 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function count()
{
return count($this->getAttributeBag()->all());
return \count($this->getAttributeBag()->all());
}
/**
* @return bool
* @return int
*
* @internal
*/
public function hasBeenStarted()
public function getUsageIndex()
{
return $this->hasBeenStarted;
return $this->usageIndex;
}
/**
@@ -158,6 +158,9 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function isEmpty()
{
if ($this->isStarted()) {
++$this->usageIndex;
}
foreach ($this->data as &$data) {
if (!empty($data)) {
return false;
@@ -206,7 +209,9 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function setId($id)
{
$this->storage->setId($id);
if ($this->storage->getId() !== $id) {
$this->storage->setId($id);
}
}
/**
@@ -230,6 +235,8 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function getMetadataBag()
{
++$this->usageIndex;
return $this->storage->getMetadataBag();
}
@@ -238,7 +245,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
*/
public function registerBag(SessionBagInterface $bag)
{
$this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->hasBeenStarted));
$this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex));
}
/**

View File

@@ -20,13 +20,13 @@ final class SessionBagProxy implements SessionBagInterface
{
private $bag;
private $data;
private $hasBeenStarted;
private $usageIndex;
public function __construct(SessionBagInterface $bag, array &$data, &$hasBeenStarted)
public function __construct(SessionBagInterface $bag, array &$data, &$usageIndex)
{
$this->bag = $bag;
$this->data = &$data;
$this->hasBeenStarted = &$hasBeenStarted;
$this->usageIndex = &$usageIndex;
}
/**
@@ -34,6 +34,8 @@ final class SessionBagProxy implements SessionBagInterface
*/
public function getBag()
{
++$this->usageIndex;
return $this->bag;
}
@@ -42,6 +44,11 @@ final class SessionBagProxy implements SessionBagInterface
*/
public function isEmpty()
{
if (!isset($this->data[$this->bag->getStorageKey()])) {
return true;
}
++$this->usageIndex;
return empty($this->data[$this->bag->getStorageKey()]);
}
@@ -58,7 +65,7 @@ final class SessionBagProxy implements SessionBagInterface
*/
public function initialize(array &$array)
{
$this->hasBeenStarted = true;
++$this->usageIndex;
$this->data[$this->bag->getStorageKey()] = &$array;
$this->bag->initialize($array);

View File

@@ -91,9 +91,6 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
$data = $this->doRead($sessionId);
$this->newSessionId = '' === $data ? $sessionId : null;
if (\PHP_VERSION_ID < 70000) {
$this->prefetchData = $data;
}
return $data;
}
@@ -103,14 +100,6 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
*/
public function write($sessionId, $data)
{
if (\PHP_VERSION_ID < 70000 && $this->prefetchData) {
$readData = $this->prefetchData;
$this->prefetchData = null;
if ($readData === $data) {
return $this->updateTimestamp($sessionId, $data);
}
}
if (null === $this->igbinaryEmptyData) {
// see https://github.com/igbinary/igbinary/issues/146
$this->igbinaryEmptyData = \function_exists('igbinary_serialize') ? igbinary_serialize(array()) : '';
@@ -128,12 +117,9 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
*/
public function destroy($sessionId)
{
if (\PHP_VERSION_ID < 70000) {
$this->prefetchData = null;
}
if (!headers_sent() && ini_get('session.use_cookies')) {
if (!$this->sessionName) {
throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', get_class($this)));
throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', \get_class($this)));
}
$sessionCookie = sprintf(' %s=', urlencode($this->sessionName));
$sessionCookieWithId = sprintf('%s%s;', $sessionCookie, urlencode($sessionId));

View File

@@ -1,120 +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;
@trigger_error(sprintf('The class %s is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead.', MemcacheSessionHandler::class), E_USER_DEPRECATED);
/**
* @author Drak <drak@zikula.org>
*
* @deprecated since version 3.4, to be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead.
*/
class MemcacheSessionHandler implements \SessionHandlerInterface
{
private $memcache;
/**
* @var int Time to live in seconds
*/
private $ttl;
/**
* @var string Key prefix for shared environments
*/
private $prefix;
/**
* Constructor.
*
* List of available options:
* * prefix: The prefix to use for the memcache keys in order to avoid collision
* * expiretime: The time to live in seconds
*
* @param \Memcache $memcache A \Memcache instance
* @param array $options An associative array of Memcache options
*
* @throws \InvalidArgumentException When unsupported options are passed
*/
public function __construct(\Memcache $memcache, array $options = array())
{
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
throw new \InvalidArgumentException(sprintf(
'The following options are not supported "%s"', implode(', ', $diff)
));
}
$this->memcache = $memcache;
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s';
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* {@inheritdoc}
*/
public function close()
{
return true;
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
return $this->memcache->get($this->prefix.$sessionId) ?: '';
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $data)
{
return $this->memcache->set($this->prefix.$sessionId, $data, 0, time() + $this->ttl);
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
$this->memcache->delete($this->prefix.$sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime)
{
// not required here because memcache will auto expire the records anyhow.
return true;
}
/**
* Return a Memcache instance.
*
* @return \Memcache
*/
protected function getMemcache()
{
return $this->memcache;
}
}

View File

@@ -50,9 +50,7 @@ class MemcachedSessionHandler extends AbstractSessionHandler
$this->memcached = $memcached;
if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) {
throw new \InvalidArgumentException(sprintf(
'The following options are not supported "%s"', implode(', ', $diff)
));
throw new \InvalidArgumentException(sprintf('The following options are not supported "%s"', implode(', ', $diff)));
}
$this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400;

View File

@@ -0,0 +1,124 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
/**
* Migrating session handler for migrating from one handler to another. It reads
* from the current handler and writes both the current and new ones.
*
* It ignores errors from the new handler.
*
* @author Ross Motley <ross.motley@amara.com>
* @author Oliver Radwell <oliver.radwell@amara.com>
*/
class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
private $currentHandler;
private $writeOnlyHandler;
public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler)
{
if (!$currentHandler instanceof \SessionUpdateTimestampHandlerInterface) {
$currentHandler = new StrictSessionHandler($currentHandler);
}
if (!$writeOnlyHandler instanceof \SessionUpdateTimestampHandlerInterface) {
$writeOnlyHandler = new StrictSessionHandler($writeOnlyHandler);
}
$this->currentHandler = $currentHandler;
$this->writeOnlyHandler = $writeOnlyHandler;
}
/**
* {@inheritdoc}
*/
public function close()
{
$result = $this->currentHandler->close();
$this->writeOnlyHandler->close();
return $result;
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
$result = $this->currentHandler->destroy($sessionId);
$this->writeOnlyHandler->destroy($sessionId);
return $result;
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime)
{
$result = $this->currentHandler->gc($maxlifetime);
$this->writeOnlyHandler->gc($maxlifetime);
return $result;
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
$result = $this->currentHandler->open($savePath, $sessionName);
$this->writeOnlyHandler->open($savePath, $sessionName);
return $result;
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
// No reading from new handler until switch-over
return $this->currentHandler->read($sessionId);
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $sessionData)
{
$result = $this->currentHandler->write($sessionId, $sessionData);
$this->writeOnlyHandler->write($sessionId, $sessionData);
return $result;
}
/**
* {@inheritdoc}
*/
public function validateId($sessionId)
{
// No reading from new handler until switch-over
return $this->currentHandler->validateId($sessionId);
}
/**
* {@inheritdoc}
*/
public function updateTimestamp($sessionId, $sessionData)
{
$result = $this->currentHandler->updateTimestamp($sessionId, $sessionData);
$this->writeOnlyHandler->updateTimestamp($sessionId, $sessionData);
return $result;
}
}

View File

@@ -24,7 +24,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
private $mongo;
/**
* @var \MongoCollection
* @var \MongoDB\Collection
*/
private $collection;
@@ -64,19 +64,10 @@ class MongoDbSessionHandler extends AbstractSessionHandler
* @param \MongoDB\Client $mongo A MongoDB\Client instance
* @param array $options An associative array of field options
*
* @throws \InvalidArgumentException When MongoClient or Mongo instance not provided
* @throws \InvalidArgumentException When "database" or "collection" not provided
*/
public function __construct($mongo, array $options)
public function __construct(\MongoDB\Client $mongo, array $options)
{
if ($mongo instanceof \MongoClient || $mongo instanceof \Mongo) {
@trigger_error(sprintf('Using %s with the legacy mongo extension is deprecated as of 3.4 and will be removed in 4.0. Use it with the mongodb/mongodb package and ext-mongodb instead.', __CLASS__), E_USER_DEPRECATED);
}
if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
throw new \InvalidArgumentException('MongoClient or Mongo instance required');
}
if (!isset($options['database']) || !isset($options['collection'])) {
throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler');
}
@@ -104,9 +95,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
*/
protected function doDestroy($sessionId)
{
$methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
$this->getCollection()->$methodName(array(
$this->getCollection()->deleteOne(array(
$this->options['id_field'] => $sessionId,
));
@@ -118,10 +107,8 @@ class MongoDbSessionHandler extends AbstractSessionHandler
*/
public function gc($maxlifetime)
{
$methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteMany' : 'remove';
$this->getCollection()->$methodName(array(
$this->options['expiry_field'] => array('$lt' => $this->createDateTime()),
$this->getCollection()->deleteMany(array(
$this->options['expiry_field'] => array('$lt' => new \MongoDB\BSON\UTCDateTime()),
));
return true;
@@ -132,28 +119,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler
*/
protected function doWrite($sessionId, $data)
{
$expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime'));
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
$fields = array(
$this->options['time_field'] => $this->createDateTime(),
$this->options['time_field'] => new \MongoDB\BSON\UTCDateTime(),
$this->options['expiry_field'] => $expiry,
$this->options['data_field'] => new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY),
);
$options = array('upsert' => true);
if ($this->mongo instanceof \MongoDB\Client) {
$fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
} else {
$fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY);
$options['multiple'] = false;
}
$methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update';
$this->getCollection()->$methodName(
$this->getCollection()->updateOne(
array($this->options['id_field'] => $sessionId),
array('$set' => $fields),
$options
array('upsert' => true)
);
return true;
@@ -164,23 +141,14 @@ class MongoDbSessionHandler extends AbstractSessionHandler
*/
public function updateTimestamp($sessionId, $data)
{
$expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime'));
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
if ($this->mongo instanceof \MongoDB\Client) {
$methodName = 'updateOne';
$options = array();
} else {
$methodName = 'update';
$options = array('multiple' => false);
}
$this->getCollection()->$methodName(
$this->getCollection()->updateOne(
array($this->options['id_field'] => $sessionId),
array('$set' => array(
$this->options['time_field'] => $this->createDateTime(),
$this->options['time_field'] => new \MongoDB\BSON\UTCDateTime(),
$this->options['expiry_field'] => $expiry,
)),
$options
))
);
return true;
@@ -193,24 +161,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler
{
$dbData = $this->getCollection()->findOne(array(
$this->options['id_field'] => $sessionId,
$this->options['expiry_field'] => array('$gte' => $this->createDateTime()),
$this->options['expiry_field'] => array('$gte' => new \MongoDB\BSON\UTCDateTime()),
));
if (null === $dbData) {
return '';
}
if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) {
return $dbData[$this->options['data_field']]->getData();
}
return $dbData[$this->options['data_field']]->bin;
return $dbData[$this->options['data_field']]->getData();
}
/**
* Return a "MongoCollection" instance.
*
* @return \MongoCollection
* @return \MongoDB\Collection
*/
private function getCollection()
{
@@ -222,34 +184,10 @@ class MongoDbSessionHandler extends AbstractSessionHandler
}
/**
* Return a Mongo instance.
*
* @return \Mongo|\MongoClient|\MongoDB\Client
* @return \MongoDB\Client
*/
protected function getMongo()
{
return $this->mongo;
}
/**
* Create a date object using the class appropriate for the current mongo connection.
*
* Return an instance of a MongoDate or \MongoDB\BSON\UTCDateTime
*
* @param int $seconds An integer representing UTC seconds since Jan 1 1970. Defaults to now.
*
* @return \MongoDate|\MongoDB\BSON\UTCDateTime
*/
private function createDateTime($seconds = null)
{
if (null === $seconds) {
$seconds = time();
}
if ($this->mongo instanceof \MongoDB\Client) {
return new \MongoDB\BSON\UTCDateTime($seconds * 1000);
}
return new \MongoDate($seconds);
}
}

View File

@@ -16,7 +16,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
*
* @author Drak <drak@zikula.org>
*/
class NativeFileSessionHandler extends NativeSessionHandler
class NativeFileSessionHandler extends \SessionHandler
{
/**
* @param string $savePath Path of directory to save session files
@@ -28,7 +28,7 @@ class NativeFileSessionHandler extends NativeSessionHandler
* @throws \InvalidArgumentException On invalid $savePath
* @throws \RuntimeException When failing to create the save directory
*/
public function __construct($savePath = null)
public function __construct(string $savePath = null)
{
if (null === $savePath) {
$savePath = ini_get('session.save_path');

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\Session\Storage\Handler;
/**
* @deprecated since version 3.4, to be removed in 4.0. Use \SessionHandler instead.
* @see http://php.net/sessionhandler
*/
class NativeSessionHandler extends \SessionHandler
{
public function __construct()
{
@trigger_error('The '.__NAMESPACE__.'\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead.', E_USER_DEPRECATED);
}
}

View File

@@ -71,7 +71,7 @@ class PdoSessionHandler extends AbstractSessionHandler
private $pdo;
/**
* @var string|null|false DSN string or null for session.save_path or false when lazy connection disabled
* @var string|false|null DSN string or null for session.save_path or false when lazy connection disabled
*/
private $dsn = false;
@@ -178,7 +178,7 @@ class PdoSessionHandler extends AbstractSessionHandler
$this->pdo = $pdoOrDsn;
$this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
} elseif (is_string($pdoOrDsn) && false !== strpos($pdoOrDsn, '://')) {
} elseif (\is_string($pdoOrDsn) && false !== strpos($pdoOrDsn, '://')) {
$this->dsn = $this->buildDsnFromUrl($pdoOrDsn);
} else {
$this->dsn = $pdoOrDsn;
@@ -629,7 +629,7 @@ class PdoSessionHandler extends AbstractSessionHandler
return '';
}
return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
return \is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
}
if (null !== $insertStmt) {
@@ -668,8 +668,6 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Executes an application-level lock on the database.
*
* @param string $sessionId Session ID
*
* @return \PDOStatement The statement that needs to be executed later to release the lock
*
* @throws \DomainException When an unsupported PDO driver is used
@@ -678,7 +676,7 @@ class PdoSessionHandler extends AbstractSessionHandler
* - for oci using DBMS_LOCK.REQUEST
* - for sqlsrv using sp_getapplock with LockOwner = Session
*/
private function doAdvisoryLock($sessionId)
private function doAdvisoryLock(string $sessionId)
{
switch ($this->driver) {
case 'mysql':
@@ -733,19 +731,15 @@ class PdoSessionHandler extends AbstractSessionHandler
* Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer.
*
* Keep in mind, PHP integers are signed.
*
* @param string $string
*
* @return int
*/
private function convertStringToInt($string)
private function convertStringToInt(string $string): int
{
if (4 === \PHP_INT_SIZE) {
return (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);
return (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]);
}
$int1 = (ord($string[7]) << 24) + (ord($string[6]) << 16) + (ord($string[5]) << 8) + ord($string[4]);
$int2 = (ord($string[3]) << 24) + (ord($string[2]) << 16) + (ord($string[1]) << 8) + ord($string[0]);
$int1 = (\ord($string[7]) << 24) + (\ord($string[6]) << 16) + (\ord($string[5]) << 8) + \ord($string[4]);
$int2 = (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]);
return $int2 + ($int1 << 32);
}
@@ -753,11 +747,9 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Return a locking or nonlocking SQL query to read session information.
*
* @return string The SQL string
*
* @throws \DomainException When an unsupported PDO driver is used
*/
private function getSelectSql()
private function getSelectSql(): string
{
if (self::LOCK_TRANSACTIONAL === $this->lockMode) {
$this->beginTransaction();
@@ -848,14 +840,8 @@ class PdoSessionHandler extends AbstractSessionHandler
/**
* Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.
*
* @param string $sessionId Session ID
* @param string $data Encoded session data
* @param int $maxlifetime session.gc_maxlifetime
*
* @return \PDOStatement|null The merge statement or null when not supported
*/
private function getMergeStatement($sessionId, $data, $maxlifetime)
private function getMergeStatement(string $sessionId, string $data, int $maxlifetime): ?\PDOStatement
{
switch (true) {
case 'mysql' === $this->driver:

View File

@@ -0,0 +1,112 @@
<?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;
use Predis\Response\ErrorInterface;
use Symfony\Component\Cache\Traits\RedisProxy;
/**
* Redis based session storage handler based on the Redis class
* provided by the PHP redis extension.
*
* @author Dalibor Karlović <dalibor@flexolabs.io>
*/
class RedisSessionHandler extends AbstractSessionHandler
{
private $redis;
/**
* @var string Key prefix for shared environments
*/
private $prefix;
/**
* List of available options:
* * prefix: The prefix to use for the keys in order to avoid collision on the Redis server.
*
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|RedisProxy $redis
* @param array $options An associative array of options
*
* @throws \InvalidArgumentException When unsupported client or options are passed
*/
public function __construct($redis, array $options = array())
{
if (
!$redis instanceof \Redis &&
!$redis instanceof \RedisArray &&
!$redis instanceof \RedisCluster &&
!$redis instanceof \Predis\Client &&
!$redis instanceof RedisProxy
) {
throw new \InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis)));
}
if ($diff = array_diff(array_keys($options), array('prefix'))) {
throw new \InvalidArgumentException(sprintf('The following options are not supported "%s"', implode(', ', $diff)));
}
$this->redis = $redis;
$this->prefix = $options['prefix'] ?? 'sf_s';
}
/**
* {@inheritdoc}
*/
protected function doRead($sessionId): string
{
return $this->redis->get($this->prefix.$sessionId) ?: '';
}
/**
* {@inheritdoc}
*/
protected function doWrite($sessionId, $data): bool
{
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime'), $data);
return $result && !$result instanceof ErrorInterface;
}
/**
* {@inheritdoc}
*/
protected function doDestroy($sessionId): bool
{
$this->redis->del($this->prefix.$sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function close(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function updateTimestamp($sessionId, $data)
{
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime'));
}
}

View File

@@ -24,7 +24,7 @@ class StrictSessionHandler extends AbstractSessionHandler
public function __construct(\SessionHandlerInterface $handler)
{
if ($handler instanceof \SessionUpdateTimestampHandlerInterface) {
throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_class($handler), self::class));
throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', \get_class($handler), self::class));
}
$this->handler = $handler;

View File

@@ -1,92 +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;
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead.', WriteCheckSessionHandler::class), E_USER_DEPRECATED);
/**
* Wraps another SessionHandlerInterface to only write the session when it has been modified.
*
* @author Adrien Brault <adrien.brault@gmail.com>
*
* @deprecated since version 3.4, to be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead.
*/
class WriteCheckSessionHandler implements \SessionHandlerInterface
{
private $wrappedSessionHandler;
/**
* @var array sessionId => session
*/
private $readSessions;
public function __construct(\SessionHandlerInterface $wrappedSessionHandler)
{
$this->wrappedSessionHandler = $wrappedSessionHandler;
}
/**
* {@inheritdoc}
*/
public function close()
{
return $this->wrappedSessionHandler->close();
}
/**
* {@inheritdoc}
*/
public function destroy($sessionId)
{
return $this->wrappedSessionHandler->destroy($sessionId);
}
/**
* {@inheritdoc}
*/
public function gc($maxlifetime)
{
return $this->wrappedSessionHandler->gc($maxlifetime);
}
/**
* {@inheritdoc}
*/
public function open($savePath, $sessionName)
{
return $this->wrappedSessionHandler->open($savePath, $sessionName);
}
/**
* {@inheritdoc}
*/
public function read($sessionId)
{
$session = $this->wrappedSessionHandler->read($sessionId);
$this->readSessions[$sessionId] = $session;
return $session;
}
/**
* {@inheritdoc}
*/
public function write($sessionId, $data)
{
if (isset($this->readSessions[$sessionId]) && $data === $this->readSessions[$sessionId]) {
return true;
}
return $this->wrappedSessionHandler->write($sessionId, $data);
}
}

View File

@@ -57,7 +57,7 @@ class MetadataBag implements SessionBagInterface
* @param string $storageKey The key used to store bag in the session
* @param int $updateThreshold The time to wait between two UPDATED updates
*/
public function __construct($storageKey = '_sf2_meta', $updateThreshold = 0)
public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0)
{
$this->storageKey = $storageKey;
$this->updateThreshold = $updateThreshold;

View File

@@ -62,11 +62,7 @@ class MockArraySessionStorage implements SessionStorageInterface
*/
protected $bags = array();
/**
* @param string $name Session name
* @param MetadataBag $metaBag MetadataBag instance
*/
public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null)
public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
{
$this->name = $name;
$this->setMetadataBag($metaBag);

View File

@@ -31,7 +31,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
* @param string $name Session name
* @param MetadataBag $metaBag MetadataBag instance
*/
public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null)
public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
{
if (null === $savePath) {
$savePath = sys_get_temp_dir();

View File

@@ -67,13 +67,9 @@ class NativeSessionStorage implements SessionStorageInterface
* cookie_lifetime, "0"
* cookie_path, "/"
* cookie_secure, ""
* entropy_file, ""
* entropy_length, "0"
* gc_divisor, "100"
* gc_maxlifetime, "1440"
* gc_probability, "1"
* hash_bits_per_character, "4"
* hash_function, "0"
* lazy_write, "1"
* name, "PHPSESSID"
* referer_check, ""
@@ -105,6 +101,7 @@ class NativeSessionStorage implements SessionStorageInterface
'cache_expire' => 0,
'use_cookies' => 1,
'lazy_write' => 1,
'use_strict_mode' => 1,
);
session_register_shutdown();
@@ -230,29 +227,22 @@ class NativeSessionStorage implements SessionStorageInterface
unset($_SESSION[$key]);
}
// Register custom error handler to catch a possible failure warning during session write
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
throw new \ErrorException($errstr, $errno, E_WARNING, $errfile, $errline);
}, E_WARNING);
// Register error handler to add information about the current save handler
$previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) {
if (E_WARNING === $type && 0 === strpos($msg, 'session_write_close():')) {
$handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler;
$msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', \get_class($handler));
}
return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false;
});
try {
$e = null;
session_write_close();
} catch (\ErrorException $e) {
} finally {
restore_error_handler();
$_SESSION = $session;
}
if (null !== $e) {
// The default PHP error message is not very helpful, as it does not give any information on the current save handler.
// Therefore, we catch this error and trigger a warning with a better error message
$handler = $this->getSaveHandler();
if ($handler instanceof SessionHandlerProxy) {
$handler = $handler->getHandler();
}
trigger_error(sprintf('session_write_close(): Failed to write session data with %s handler', get_class($handler)), E_USER_WARNING);
}
$this->closed = true;
$this->started = false;
@@ -351,9 +341,8 @@ class NativeSessionStorage implements SessionStorageInterface
$validOptions = array_flip(array(
'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly',
'cookie_lifetime', 'cookie_path', 'cookie_secure',
'entropy_file', 'entropy_length', 'gc_divisor',
'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
'hash_function', 'lazy_write', 'name', 'referer_check',
'gc_divisor', 'gc_maxlifetime', 'gc_probability',
'lazy_write', 'name', 'referer_check',
'serialize_handler', 'use_strict_mode', 'use_cookies',
'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
@@ -411,8 +400,6 @@ class NativeSessionStorage implements SessionStorageInterface
}
if ($this->saveHandler instanceof SessionHandlerProxy) {
session_set_save_handler($this->saveHandler->getHandler(), false);
} elseif ($this->saveHandler instanceof \SessionHandlerInterface) {
session_set_save_handler($this->saveHandler, false);
}
}

View File

@@ -1,40 +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\Proxy;
@trigger_error('The '.__NAMESPACE__.'\NativeProxy class is deprecated since Symfony 3.4 and will be removed in 4.0. Use your session handler implementation directly.', E_USER_DEPRECATED);
/**
* This proxy is built-in session handlers in PHP 5.3.x.
*
* @deprecated since version 3.4, to be removed in 4.0. Use your session handler implementation directly.
*
* @author Drak <drak@zikula.org>
*/
class NativeProxy extends AbstractProxy
{
public function __construct()
{
// this makes an educated guess as to what the handler is since it should already be set.
$this->saveHandlerName = ini_get('session.save_handler');
}
/**
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
*
* @return bool False
*/
public function isWrapper()
{
return false;
}
}

View File

@@ -14,7 +14,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
/**
* @author Drak <drak@zikula.org>
*/
class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface
class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
protected $handler;
@@ -82,4 +82,20 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
{
return (bool) $this->handler->gc($maxlifetime);
}
/**
* {@inheritdoc}
*/
public function validateId($sessionId)
{
return !$this->handler instanceof \SessionUpdateTimestampHandlerInterface || $this->handler->validateId($sessionId);
}
/**
* {@inheritdoc}
*/
public function updateTimestamp($sessionId, $data)
{
return $this->handler instanceof \SessionUpdateTimestampHandlerInterface ? $this->handler->updateTimestamp($sessionId, $data) : $this->write($sessionId, $data);
}
}

View File

@@ -35,7 +35,7 @@ class StreamedResponse extends Response
* @param int $status The response status code
* @param array $headers An array of response headers
*/
public function __construct(callable $callback = null, $status = 200, $headers = array())
public function __construct(callable $callback = null, int $status = 200, array $headers = array())
{
parent::__construct(null, $status, $headers);
@@ -111,7 +111,7 @@ class StreamedResponse extends Response
throw new \LogicException('The Response callback must not be null.');
}
call_user_func($this->callback);
\call_user_func($this->callback);
return $this;
}
@@ -129,6 +129,8 @@ class StreamedResponse extends Response
throw new \LogicException('The content cannot be set on a StreamedResponse instance.');
}
$this->streamed = true;
return $this;
}

View File

@@ -66,7 +66,7 @@ class AcceptHeaderItemTest extends TestCase
),
array(
'text/plain', array('charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'),
'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true',
'text/plain; charset=utf-8; param="this;should,not=matter"; footnotes=true',
),
);
}

View File

@@ -100,4 +100,31 @@ class AcceptHeaderTest extends TestCase
'order matters when q is equal2' => array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('utf-8', 'ISO-8859-1', '*')),
);
}
/**
* @dataProvider provideDefaultValueData
*/
public function testDefaultValue($acceptHeader, $value, $expectedQuality)
{
$header = AcceptHeader::fromString($acceptHeader);
$this->assertSame($expectedQuality, $header->get($value)->getQuality());
}
public function provideDefaultValueData()
{
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, *;q=0.3', 'text/xml', 0.3);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/xml', 0.3);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/html', 1.0);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/plain', 0.5);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', '*', 0.3);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', '*', 1.0);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', 'text/xml', 1.0);
yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', 'text/*', 1.0);
yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/*', 0.8);
yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/html', 1.0);
yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/x-dvi', 0.8);
yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', '*', 0.3);
yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', 'utf-8', 0.7);
yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', 'SHIFT_JIS', 0.3);
}
}

View File

@@ -32,7 +32,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$response = BinaryFileResponse::create($file, 404, array(), true, ResponseHeaderBag::DISPOSITION_INLINE);
$this->assertEquals(404, $response->getStatusCode());
$this->assertFalse($response->headers->has('ETag'));
$this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition'));
$this->assertEquals('inline; filename=README.md', $response->headers->get('Content-Disposition'));
}
public function testConstructWithNonAsciiFilename()
@@ -66,7 +66,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$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'));
$this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
}
public function testSetContentDispositionGeneratesSafeFallbackFilenameForWronglyEncodedFilename()
@@ -77,7 +77,7 @@ class BinaryFileResponseTest extends ResponseTestCase
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $iso88591EncodedFilename);
// the parameter filename* is invalid in this case (rawurldecode('f%F6%F6') does not provide a UTF-8 string but an ISO-8859-1 encoded one)
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition'));
$this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition'));
}
/**
@@ -208,6 +208,19 @@ class BinaryFileResponseTest extends ResponseTestCase
);
}
public function testUnpreparedResponseSendsFullFile()
{
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200);
$data = file_get_contents(__DIR__.'/File/Fixtures/test.gif');
$this->expectOutputString($data);
$response = clone $response;
$response->sendContent();
$this->assertEquals(200, $response->getStatusCode());
}
/**
* @dataProvider provideInvalidRanges
*/
@@ -324,7 +337,8 @@ class BinaryFileResponseTest extends ResponseTestCase
{
return array(
array('/var/www/var/www/files/foo.txt', '/var/www/=/files/', '/files/var/www/files/foo.txt'),
array('/home/foo/bar.txt', '/var/www/=/files/,/home/foo/=/baz/', '/baz/bar.txt'),
array('/home/Foo/bar.txt', '/var/www/=/files/,/home/Foo/=/baz/', '/baz/bar.txt'),
array('/home/Foo/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', '/baz/bar.txt'),
);
}

View File

@@ -104,9 +104,6 @@ class CookieTest extends TestCase
$this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date');
}
/**
* @requires PHP 5.5
*/
public function testConstructorWithDateTimeImmutable()
{
$expire = new \DateTimeImmutable();
@@ -157,6 +154,18 @@ class CookieTest extends TestCase
$cookie = new Cookie('foo', 'bar', time() - 20);
$this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired');
$cookie = new Cookie('foo', 'bar');
$this->assertFalse($cookie->isCleared());
$cookie = new Cookie('foo', 'bar', 0);
$this->assertFalse($cookie->isCleared());
$cookie = new Cookie('foo', 'bar', -1);
$this->assertFalse($cookie->isCleared());
}
public function testToString()
@@ -204,6 +213,9 @@ class CookieTest extends TestCase
$cookie = Cookie::fromString('foo=bar', true);
$this->assertEquals(new Cookie('foo', 'bar', 0, '/', null, false, false), $cookie);
$cookie = Cookie::fromString('foo', true);
$this->assertEquals(new Cookie('foo', null, 0, '/', null, false, false), $cookie);
}
public function testFromStringWithHttpOnly()

View File

@@ -12,8 +12,8 @@
namespace Symfony\Component\HttpFoundation\Tests\File\MimeType;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
/**
* @requires extension fileinfo
@@ -59,7 +59,7 @@ class MimeTypeTest extends TestCase
public function testGuessWithNonReadablePath()
{
if ('\\' === DIRECTORY_SEPARATOR) {
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Can not verify chmod operations on Windows');
}

View File

@@ -12,6 +12,14 @@
namespace Symfony\Component\HttpFoundation\Tests\File;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class UploadedFileTest extends TestCase
@@ -40,13 +48,12 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$this->assertEquals('application/octet-stream', $file->getClientMimeType());
if (extension_loaded('fileinfo')) {
if (\extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', $file->getMimeType());
}
}
@@ -57,7 +64,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/.unknownextension',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/.unknownextension'),
UPLOAD_ERR_OK
);
@@ -70,7 +76,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
@@ -83,7 +88,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/jpeg',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
@@ -96,7 +100,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
@@ -109,7 +112,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
@@ -122,7 +124,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
);
@@ -138,13 +139,60 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
}
public function failedUploadedFile()
{
foreach (array(UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, UPLOAD_ERR_PARTIAL, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_CANT_WRITE, UPLOAD_ERR_NO_TMP_DIR, UPLOAD_ERR_EXTENSION, -1) as $error) {
yield array(new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
$error
));
}
}
/**
* @dataProvider failedUploadedFile
*/
public function testMoveFailed(UploadedFile $file)
{
switch ($file->getError()) {
case UPLOAD_ERR_INI_SIZE:
$exceptionClass = IniSizeFileException::class;
break;
case UPLOAD_ERR_FORM_SIZE:
$exceptionClass = FormSizeFileException::class;
break;
case UPLOAD_ERR_PARTIAL:
$exceptionClass = PartialFileException::class;
break;
case UPLOAD_ERR_NO_FILE:
$exceptionClass = NoFileException::class;
break;
case UPLOAD_ERR_CANT_WRITE:
$exceptionClass = CannotWriteFileException::class;
break;
case UPLOAD_ERR_NO_TMP_DIR:
$exceptionClass = NoTmpDirFileException::class;
break;
case UPLOAD_ERR_EXTENSION:
$exceptionClass = ExtensionFileException::class;
break;
default:
$exceptionClass = FileException::class;
}
$this->expectException($exceptionClass);
$file->move(__DIR__.'/Fixtures/directory');
}
public function testMoveLocalFileIsAllowedInTestMode()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
@@ -158,7 +206,6 @@ class UploadedFileTest extends TestCase
$path,
'original.gif',
'image/gif',
filesize($path),
UPLOAD_ERR_OK,
true
);
@@ -177,9 +224,7 @@ class UploadedFileTest extends TestCase
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'../../original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
'image/gif'
);
$this->assertEquals('original.gif', $file->getClientOriginalName());
@@ -190,9 +235,7 @@ class UploadedFileTest extends TestCase
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
null
'image/gif'
);
$this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize());
@@ -206,12 +249,45 @@ class UploadedFileTest extends TestCase
$this->assertEquals(filesize(__DIR__.'/Fixtures/test'), $file->getSize());
}
public function testGetExtension()
/**
* @group legacy
* @expectedDeprecation Passing a size as 4th argument to the constructor of "Symfony\Component\HttpFoundation\File\UploadedFile" is deprecated since Symfony 4.1.
*/
public function testConstructDeprecatedSize()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
null
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK,
false
);
$this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize());
}
/**
* @group legacy
* @expectedDeprecation Passing a size as 4th argument to the constructor of "Symfony\Component\HttpFoundation\File\UploadedFile" is deprecated since Symfony 4.1.
*/
public function testConstructDeprecatedSizeWhenPassingOnlyThe4Needed()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif')
);
$this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize());
}
public function testGetExtension()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif'
);
$this->assertEquals('gif', $file->getExtension());
@@ -223,7 +299,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK,
true
);
@@ -240,7 +315,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
$error
);
@@ -264,7 +338,6 @@ class UploadedFileTest extends TestCase
__DIR__.'/Fixtures/test.gif',
'original.gif',
null,
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);

View File

@@ -34,14 +34,14 @@ class FileBagTest extends TestCase
public function testShouldConvertsUploadedFiles()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain');
$bag = new FileBag(array('file' => array(
'name' => basename($tmpFile),
'type' => 'text/plain',
'tmp_name' => $tmpFile,
'error' => 0,
'size' => 100,
'size' => null,
)));
$this->assertEquals($file, $bag->get('file'));
@@ -89,7 +89,7 @@ class FileBagTest extends TestCase
public function testShouldConvertUploadedFilesWithPhpBug()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain');
$bag = new FileBag(array(
'child' => array(
@@ -106,7 +106,7 @@ class FileBagTest extends TestCase
'file' => 0,
),
'size' => array(
'file' => 100,
'file' => null,
),
),
));
@@ -118,7 +118,7 @@ class FileBagTest extends TestCase
public function testShouldConvertNestedUploadedFilesWithPhpBug()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain');
$bag = new FileBag(array(
'child' => array(
@@ -135,7 +135,7 @@ class FileBagTest extends TestCase
'sub' => array('file' => 0),
),
'size' => array(
'sub' => array('file' => 100),
'sub' => array('file' => null),
),
),
));
@@ -147,7 +147,7 @@ class FileBagTest extends TestCase
public function testShouldNotConvertNestedUploadedFiles()
{
$tmpFile = $this->createTempFile();
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0);
$file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain');
$bag = new FileBag(array('image' => array('file' => $file)));
$files = $bag->all();
@@ -156,7 +156,10 @@ class FileBagTest extends TestCase
protected function createTempFile()
{
return tempnam(sys_get_temp_dir().'/form_test', 'FormTest');
$tempFile = tempnam(sys_get_temp_dir().'/form_test', 'FormTest');
file_put_contents($tempFile, '1');
return $tempFile;
}
protected function setUp()

View File

@@ -22,6 +22,10 @@ error_reporting(-1);
ini_set('html_errors', 0);
ini_set('display_errors', 1);
if (ini_get('xdebug.default_enable')) {
xdebug_disable();
}
header_remove('X-Powered-By');
header('Content-Type: text/plain; charset=utf-8');

View File

@@ -4,7 +4,7 @@ Array
[0] => Content-Type: text/plain; charset=utf-8
[1] => Cache-Control: no-cache, private
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
[3] => Set-Cookie: %3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
[3] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
[4] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
)
shutdown

View File

@@ -192,7 +192,7 @@ class HeaderBagTest extends TestCase
$this->assertEquals(array($headers[$key]), $val);
}
$this->assertEquals(count($headers), $i);
$this->assertEquals(\count($headers), $i);
}
public function testCount()
@@ -200,6 +200,6 @@ class HeaderBagTest extends TestCase
$headers = array('foo' => 'bar', 'HELLO' => 'WORLD');
$headerBag = new HeaderBag($headers);
$this->assertCount(count($headers), $headerBag);
$this->assertCount(\count($headers), $headerBag);
}
}

View File

@@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\HeaderUtils;
class HeaderUtilsTest extends TestCase
{
public function testSplit()
{
$this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123,bar', ','));
$this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123, bar', ','));
$this->assertSame(array(array('foo=123', 'bar')), HeaderUtils::split('foo=123; bar', ',;'));
$this->assertSame(array(array('foo=123'), array('bar')), HeaderUtils::split('foo=123, bar', ',;'));
$this->assertSame(array('foo', '123, bar'), HeaderUtils::split('foo=123, bar', '='));
$this->assertSame(array('foo', '123, bar'), HeaderUtils::split(' foo = 123, bar ', '='));
$this->assertSame(array(array('foo', '123'), array('bar')), HeaderUtils::split('foo=123, bar', ',='));
$this->assertSame(array(array(array('foo', '123')), array(array('bar'), array('foo', '456'))), HeaderUtils::split('foo=123, bar; foo=456', ',;='));
$this->assertSame(array(array(array('foo', 'a,b;c=d'))), HeaderUtils::split('foo="a,b;c=d"', ',;='));
$this->assertSame(array('foo', 'bar'), HeaderUtils::split('foo,,,, bar', ','));
$this->assertSame(array('foo', 'bar'), HeaderUtils::split(',foo, bar,', ','));
$this->assertSame(array('foo', 'bar'), HeaderUtils::split(' , foo, bar, ', ','));
$this->assertSame(array('foo bar'), HeaderUtils::split('foo "bar"', ','));
$this->assertSame(array('foo bar'), HeaderUtils::split('"foo" bar', ','));
$this->assertSame(array('foo bar'), HeaderUtils::split('"foo" "bar"', ','));
// These are not a valid header values. We test that they parse anyway,
// and that both the valid and invalid parts are returned.
$this->assertSame(array(), HeaderUtils::split('', ','));
$this->assertSame(array(), HeaderUtils::split(',,,', ','));
$this->assertSame(array('foo', 'bar', 'baz'), HeaderUtils::split('foo, "bar", "baz', ','));
$this->assertSame(array('foo', 'bar, baz'), HeaderUtils::split('foo, "bar, baz', ','));
$this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\', ','));
$this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\\\', ','));
}
public function testCombine()
{
$this->assertSame(array('foo' => '123'), HeaderUtils::combine(array(array('foo', '123'))));
$this->assertSame(array('foo' => true), HeaderUtils::combine(array(array('foo'))));
$this->assertSame(array('foo' => true), HeaderUtils::combine(array(array('Foo'))));
$this->assertSame(array('foo' => '123', 'bar' => true), HeaderUtils::combine(array(array('foo', '123'), array('bar'))));
}
public function testToString()
{
$this->assertSame('foo', HeaderUtils::toString(array('foo' => true), ','));
$this->assertSame('foo; bar', HeaderUtils::toString(array('foo' => true, 'bar' => true), ';'));
$this->assertSame('foo=123', HeaderUtils::toString(array('foo' => '123'), ','));
$this->assertSame('foo="1 2 3"', HeaderUtils::toString(array('foo' => '1 2 3'), ','));
$this->assertSame('foo="1 2 3", bar', HeaderUtils::toString(array('foo' => '1 2 3', 'bar' => true), ','));
}
public function testQuote()
{
$this->assertSame('foo', HeaderUtils::quote('foo'));
$this->assertSame('az09!#$%&\'*.^_`|~-', HeaderUtils::quote('az09!#$%&\'*.^_`|~-'));
$this->assertSame('"foo bar"', HeaderUtils::quote('foo bar'));
$this->assertSame('"foo [bar]"', HeaderUtils::quote('foo [bar]'));
$this->assertSame('"foo \"bar\""', HeaderUtils::quote('foo "bar"'));
$this->assertSame('"foo \\\\ bar"', HeaderUtils::quote('foo \\ bar'));
}
public function testUnquote()
{
$this->assertEquals('foo', HeaderUtils::unquote('foo'));
$this->assertEquals('az09!#$%&\'*.^_`|~-', HeaderUtils::unquote('az09!#$%&\'*.^_`|~-'));
$this->assertEquals('foo bar', HeaderUtils::unquote('"foo bar"'));
$this->assertEquals('foo [bar]', HeaderUtils::unquote('"foo [bar]"'));
$this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"bar\""'));
$this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"\b\a\r\""'));
$this->assertEquals('foo \\ bar', HeaderUtils::unquote('"foo \\\\ bar"'));
}
}

View File

@@ -47,7 +47,7 @@ class IpUtilsTest extends TestCase
*/
public function testIpv6($matches, $remoteAddr, $cidr)
{
if (!defined('AF_INET6')) {
if (!\defined('AF_INET6')) {
$this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".');
}
@@ -78,7 +78,7 @@ class IpUtilsTest extends TestCase
*/
public function testAnIpv6WithOptionDisabledIpv6()
{
if (defined('AF_INET6')) {
if (\defined('AF_INET6')) {
$this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".');
}

View File

@@ -171,7 +171,7 @@ class ParameterBagTest extends TestCase
$this->assertEquals($parameters[$key], $val);
}
$this->assertEquals(count($parameters), $i);
$this->assertEquals(\count($parameters), $i);
}
public function testCount()
@@ -179,7 +179,7 @@ class ParameterBagTest extends TestCase
$parameters = array('foo' => 'bar', 'hello' => 'world');
$bag = new ParameterBag($parameters);
$this->assertCount(count($parameters), $bag);
$this->assertCount(\count($parameters), $bag);
}
public function testGetBoolean()

View File

@@ -12,8 +12,8 @@
namespace Symfony\Component\HttpFoundation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\RequestMatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcher;
class RequestMatcherTest extends TestCase
{

View File

@@ -13,15 +13,14 @@ namespace Symfony\Component\HttpFoundation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
class RequestTest extends TestCase
{
protected function tearDown()
{
// reset
Request::setTrustedProxies(array(), -1);
Request::setTrustedHosts(array());
}
@@ -676,7 +675,7 @@ class RequestTest extends TestCase
public function getQueryStringNormalizationData()
{
return array(
array('foo', 'foo', 'works with valueless parameters'),
array('foo', 'foo=', 'works with valueless parameters'),
array('foo=', 'foo=', 'includes a dangling equal sign'),
array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'),
array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'),
@@ -685,18 +684,24 @@ class RequestTest extends TestCase
// PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str.
array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'),
array('foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'),
array('foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'),
array('foo[]=1&foo[]=2', 'foo%5B0%5D=1&foo%5B1%5D=2', 'allows array notation'),
array('foo=1&foo=2', 'foo=2', 'merges repeated parameters'),
array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'),
array('0', '0', 'allows "0"'),
array('Jane Doe&John%20Doe', 'Jane%20Doe&John%20Doe', 'normalizes encoding in keys'),
array('0', '0=', 'allows "0"'),
array('Jane Doe&John%20Doe', 'Jane_Doe=&John_Doe=', 'normalizes encoding in keys'),
array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'),
array('foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'),
array('foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'),
array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'),
// Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
// PHP also does not include them when building _GET.
array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'),
// Don't reorder nested query string keys
array('foo[]=Z&foo[]=A', 'foo%5B0%5D=Z&foo%5B1%5D=A', 'keeps order of values'),
array('foo[Z]=B&foo[A]=B', 'foo%5BZ%5D=B&foo%5BA%5D=B', 'keeps order of keys'),
array('utf8=✓', 'utf8=%E2%9C%93', 'encodes UTF-8'),
);
}
@@ -849,6 +854,11 @@ class RequestTest extends TestCase
$request->setMethod('POST');
$request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
$this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST');
$request = new Request();
$request->setMethod('POST');
$request->query->set('_method', array('delete', 'patch'));
$this->assertSame('POST', $request->getMethod(), '->getMethod() returns the request method if invalid type is defined in query');
}
/**
@@ -889,14 +899,14 @@ class RequestTest extends TestCase
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('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 getClientIpsProvider()
{
// $expected $remoteAddr $httpForwardedFor $trustedProxies
// $expected $remoteAddr $httpForwardedFor $trustedProxies
return array(
// simple IPv4
array(array('88.88.88.88'), '88.88.88.88', null, null),
@@ -910,8 +920,8 @@ class RequestTest extends TestCase
// forwarded for with remote IPv4 addr not trusted
array(array('127.0.0.1'), '127.0.0.1', '88.88.88.88', null),
// forwarded for with remote IPv4 addr trusted
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1')),
// forwarded for with remote IPv4 addr trusted + comma
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88,', array('127.0.0.1')),
// forwarded for with remote IPv4 and all FF addrs trusted
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1', '88.88.88.88')),
// forwarded for with remote IPv4 range trusted
@@ -1015,7 +1025,7 @@ class RequestTest extends TestCase
'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
);
Request::setTrustedProxies(array('88.88.88.88'), Request::HEADER_X_FORWARDED_ALL);
Request::setTrustedProxies(array('88.88.88.88'), -1);
$request->initialize(array(), array(), array(), array(), array(), $server);
@@ -1073,21 +1083,6 @@ class RequestTest extends TestCase
$this->assertEquals('My other content', $req->getContent());
}
/**
* @expectedException \LogicException
* @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
*/
public function testGetContentCantBeCalledTwiceWithResources($first, $second)
{
if (\PHP_VERSION_ID >= 50600) {
$this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.');
}
$req = new Request();
$req->getContent($first);
$req->getContent($second);
}
public function getContentCantBeCalledTwiceWithResourcesProvider()
{
return array(
@@ -1098,7 +1093,6 @@ class RequestTest extends TestCase
/**
* @dataProvider getContentCanBeCalledTwiceWithResourcesProvider
* @requires PHP 5.6
*/
public function testGetContentCanBeCalledTwiceWithResources($first, $second)
{
@@ -1508,6 +1502,15 @@ class RequestTest extends TestCase
$this->assertObjectHasAttribute('attributeName', $session);
}
/**
* @group legacy
* @expectedDeprecation Calling "Symfony\Component\HttpFoundation\Request::getSession()" when no session has been set is deprecated since Symfony 4.1 and will throw an exception in 5.0. Use "hasSession()" instead.
*/
public function testGetSessionNullable()
{
(new Request())->getSession();
}
public function testHasPreviousSession()
{
$request = new Request();
@@ -1765,53 +1768,6 @@ class RequestTest extends TestCase
$this->assertTrue($request->isSecure());
}
/**
* @group legacy
* @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public function testLegacyTrustedProxies()
{
$request = Request::create('http://example.com/');
$request->server->set('REMOTE_ADDR', '3.3.3.3');
$request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
$request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080');
$request->headers->set('X_FORWARDED_PROTO', 'https');
$request->headers->set('X_FORWARDED_PORT', 443);
$request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4');
$request->headers->set('X_MY_HOST', 'my.example.com');
$request->headers->set('X_MY_PROTO', 'http');
$request->headers->set('X_MY_PORT', 81);
Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL);
// custom header names
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO');
$this->assertEquals('4.4.4.4', $request->getClientIp());
$this->assertEquals('my.example.com', $request->getHost());
$this->assertEquals(81, $request->getPort());
$this->assertFalse($request->isSecure());
// disabling via empty header names
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null);
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null);
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null);
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null);
$this->assertEquals('3.3.3.3', $request->getClientIp());
$this->assertEquals('example.com', $request->getHost());
$this->assertEquals(80, $request->getPort());
$this->assertFalse($request->isSecure());
//reset
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
}
public function testTrustedProxiesForwarded()
{
$request = Request::create('http://example.com/');
@@ -1861,26 +1817,6 @@ class RequestTest extends TestCase
$this->assertTrue($request->isSecure());
}
/**
* @group legacy
* @expectedException \InvalidArgumentException
*/
public function testSetTrustedProxiesInvalidHeaderName()
{
Request::create('http://example.com/');
Request::setTrustedHeaderName('bogus name', 'X_MY_FOR');
}
/**
* @group legacy
* @expectedException \InvalidArgumentException
*/
public function testGetTrustedProxiesInvalidHeaderName()
{
Request::create('http://example.com/');
Request::getTrustedHeaderName('bogus name');
}
/**
* @dataProvider iisRequestUriProvider
*/
@@ -1900,20 +1836,6 @@ class RequestTest extends TestCase
public function iisRequestUriProvider()
{
return array(
array(
array(
'X_ORIGINAL_URL' => '/foo/bar',
),
array(),
'/foo/bar',
),
array(
array(
'X_REWRITE_URL' => '/foo/bar',
),
array(),
'/foo/bar',
),
array(
array(),
array(
@@ -1922,36 +1844,6 @@ class RequestTest extends TestCase
),
'/foo/bar',
),
array(
array(
'X_ORIGINAL_URL' => '/foo/bar',
),
array(
'HTTP_X_ORIGINAL_URL' => '/foo/bar',
),
'/foo/bar',
),
array(
array(
'X_ORIGINAL_URL' => '/foo/bar',
),
array(
'IIS_WasUrlRewritten' => '1',
'UNENCODED_URL' => '/foo/bar',
),
'/foo/bar',
),
array(
array(
'X_ORIGINAL_URL' => '/foo/bar',
),
array(
'HTTP_X_ORIGINAL_URL' => '/foo/bar',
'IIS_WasUrlRewritten' => '1',
'UNENCODED_URL' => '/foo/bar',
),
'/foo/bar',
),
array(
array(),
array(
@@ -2142,14 +2034,13 @@ class RequestTest extends TestCase
}
/**
* @group legacy
* @expectedDeprecation Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.
* @expectedException \BadMethodCallException
*/
public function testMethodSafeChecksCacheable()
{
$request = new Request();
$request->setMethod('OPTIONS');
$this->assertFalse($request->isMethodSafe());
$request->isMethodSafe();
}
/**
@@ -2178,61 +2069,6 @@ class RequestTest extends TestCase
);
}
/**
* @group legacy
*/
public function testGetTrustedHeaderName()
{
Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL);
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
$this->assertSame('X_FORWARDED_FOR', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
$this->assertSame('X_FORWARDED_HOST', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
$this->assertSame('X_FORWARDED_PORT', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
$this->assertSame('X_FORWARDED_PROTO', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
$this->assertSame('FORWARDED', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'A');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'B');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'C');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'D');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'E');
Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
$this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL);
$this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
$this->assertSame('B', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP));
$this->assertSame('C', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST));
$this->assertSame('D', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT));
$this->assertSame('E', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO));
Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED);
$this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED));
//reset
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
}
/**
* @dataProvider protocolVersionProvider
*/
@@ -2317,6 +2153,55 @@ class RequestTest extends TestCase
$this->assertEquals($expectedBaseUrl, $request->getBaseUrl());
$this->assertEquals($expectedBasePath, $request->getBasePath());
}
public function testTrustedHost()
{
Request::setTrustedProxies(array('1.1.1.1'), -1);
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost:8080');
$request->headers->set('X-Forwarded-Host', 'localhost:8080');
$this->assertSame('localhost:8080', $request->getHttpHost());
$this->assertSame(8080, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host="[::1]:443"');
$request->headers->set('X-Forwarded-Host', '[::1]:443');
$request->headers->set('X-Forwarded-Port', 443);
$this->assertSame('[::1]:443', $request->getHttpHost());
$this->assertSame(443, $request->getPort());
}
public function testTrustedPort()
{
Request::setTrustedProxies(array('1.1.1.1'), -1);
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost:8080');
$request->headers->set('X-Forwarded-Port', 8080);
$this->assertSame(8080, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost');
$request->headers->set('X-Forwarded-Port', 80);
$this->assertSame(80, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host="[::1]"');
$request->headers->set('X-Forwarded-Proto', 'https');
$request->headers->set('X-Forwarded-Port', 443);
$this->assertSame(443, $request->getPort());
}
}
class RequestContentProxy extends Request

View File

@@ -12,8 +12,8 @@
namespace Symfony\Component\HttpFoundation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
/**
* @group time-sensitive
@@ -287,12 +287,12 @@ class ResponseHeaderBagTest extends TestCase
public function provideMakeDisposition()
{
return array(
array('attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'),
array('attachment', 'foo.html', '', 'attachment; filename="foo.html"'),
array('attachment', 'foo.html', 'foo.html', 'attachment; filename=foo.html'),
array('attachment', 'foo.html', '', 'attachment; filename=foo.html'),
array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'),
array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'),
array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'),
array('attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
array('attachment', 'föö.html', 'foo.html', 'attachment; filename=foo.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
);
}

View File

@@ -126,7 +126,7 @@ class ResponseTest extends ResponseTestCase
public function testSetNotModified()
{
$response = new Response();
$response = new Response('foo');
$modified = $response->setNotModified();
$this->assertObjectHasAttribute('headers', $modified);
$this->assertObjectHasAttribute('content', $modified);
@@ -135,6 +135,11 @@ class ResponseTest extends ResponseTestCase
$this->assertObjectHasAttribute('statusText', $modified);
$this->assertObjectHasAttribute('charset', $modified);
$this->assertEquals(304, $modified->getStatusCode());
ob_start();
$modified->sendContent();
$string = ob_get_clean();
$this->assertEmpty($string);
}
public function testIsSuccessful()
@@ -300,7 +305,7 @@ class ResponseTest extends ResponseTestCase
$response = new Response();
$response->headers->set('Cache-Control', 'must-revalidate');
$response->headers->set('Expires', -1);
$this->assertEquals('Sat, 01 Jan 00 00:00:00 +0000', $response->getExpires()->format(DATE_RFC822));
$this->assertLessThanOrEqual(time() - 2 * 86400, $response->getExpires()->format('U'));
$response = new Response();
$this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available');
@@ -357,6 +362,11 @@ class ResponseTest extends ResponseTestCase
$response->headers->set('Expires', -1);
$response->expire();
$this->assertNull($response->headers->get('Age'), '->expire() does not set the Age when the response is expired');
$response = new Response();
$response->headers->set('Expires', date(DATE_RFC2822, time() + 600));
$response->expire();
$this->assertNull($response->headers->get('Expires'), '->expire() removes the Expires header when the response is fresh');
}
public function testGetTtl()
@@ -653,6 +663,22 @@ class ResponseTest extends ResponseTestCase
$this->assertTrue($response->isImmutable());
}
public function testSetDate()
{
$response = new Response();
$response->setDate(\DateTime::createFromFormat(\DateTime::ATOM, '2013-01-26T09:21:56+0100', new \DateTimeZone('Europe/Berlin')));
$this->assertEquals('2013-01-26T08:21:56+00:00', $response->getDate()->format(\DateTime::ATOM));
}
public function testSetDateWithImmutable()
{
$response = new Response();
$response->setDate(\DateTimeImmutable::createFromFormat(\DateTime::ATOM, '2013-01-26T09:21:56+0100', new \DateTimeZone('Europe/Berlin')));
$this->assertEquals('2013-01-26T08:21:56+00:00', $response->getDate()->format(\DateTime::ATOM));
}
public function testSetExpires()
{
$response = new Response();
@@ -666,6 +692,16 @@ class ResponseTest extends ResponseTestCase
$this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
}
public function testSetExpiresWithImmutable()
{
$response = new Response();
$now = $this->createDateTimeImmutableNow();
$response->setExpires($now);
$this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
}
public function testSetLastModified()
{
$response = new Response();
@@ -676,6 +712,16 @@ class ResponseTest extends ResponseTestCase
$this->assertNull($response->getLastModified());
}
public function testSetLastModifiedWithImmutable()
{
$response = new Response();
$response->setLastModified($this->createDateTimeImmutableNow());
$this->assertNotNull($response->getLastModified());
$response->setLastModified(null);
$this->assertNull($response->getLastModified());
}
public function testIsInvalid()
{
$response = new Response();
@@ -912,6 +958,13 @@ class ResponseTest extends ResponseTestCase
return $date->setTimestamp(time());
}
protected function createDateTimeImmutableNow()
{
$date = new \DateTimeImmutable();
return $date->setTimestamp(time());
}
protected function provideResponse()
{
return new Response();
@@ -926,7 +979,7 @@ class ResponseTest extends ResponseTestCase
*/
public function ianaCodesReasonPhrasesProvider()
{
if (!in_array('https', stream_get_wrappers(), true)) {
if (!\in_array('https', stream_get_wrappers(), true)) {
$this->markTestSkipped('The "https" wrapper is not available');
}
@@ -954,7 +1007,7 @@ class ResponseTest extends ResponseTestCase
$value = $xpath->query('.//ns:value', $record)->item(0)->nodeValue;
$description = $xpath->query('.//ns:description', $record)->item(0)->nodeValue;
if (in_array($description, array('Unassigned', '(Unused)'), true)) {
if (\in_array($description, array('Unassigned', '(Unused)'), true)) {
continue;
}
@@ -990,14 +1043,3 @@ class StringableObject
class DefaultResponse extends Response
{
}
class ExtendedResponse extends Response
{
public function setLastModified(\DateTime $date = null)
{
}
public function getDate()
{
}
}

View File

@@ -176,11 +176,11 @@ class AttributeBagTest extends TestCase
++$i;
}
$this->assertEquals(count($this->array), $i);
$this->assertEquals(\count($this->array), $i);
}
public function testCount()
{
$this->assertCount(count($this->array), $this->bag);
$this->assertCount(\count($this->array), $this->bag);
}
}

View File

@@ -82,6 +82,17 @@ class NamespacedAttributeBagTest extends TestCase
$this->assertEquals($exists, $this->bag->has($key));
}
/**
* @dataProvider attributesProvider
*/
public function testHasNoSideEffect($key, $value, $expected)
{
$expected = json_encode($this->bag->all());
$this->bag->has($key);
$this->assertEquals($expected, json_encode($this->bag->all()));
}
/**
* @dataProvider attributesProvider
*/
@@ -96,6 +107,17 @@ class NamespacedAttributeBagTest extends TestCase
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
}
/**
* @dataProvider attributesProvider
*/
public function testGetNoSideEffect($key, $value, $expected)
{
$expected = json_encode($this->bag->all());
$this->bag->get($key);
$this->assertEquals($expected, json_encode($this->bag->all()));
}
/**
* @dataProvider attributesProvider
*/

View File

@@ -74,6 +74,18 @@ class FlashBagTest extends TestCase
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testAdd()
{
$tab = array('bar' => 'baz');
$this->bag->add('string_message', 'lorem');
$this->bag->add('object_message', new \stdClass());
$this->bag->add('array_message', $tab);
$this->assertEquals(array('lorem'), $this->bag->get('string_message'));
$this->assertEquals(array(new \stdClass()), $this->bag->get('object_message'));
$this->assertEquals(array($tab), $this->bag->get('array_message'));
}
public function testGet()
{
$this->assertEquals(array(), $this->bag->get('non_existing'));
@@ -112,6 +124,19 @@ class FlashBagTest extends TestCase
$this->assertEquals(array('notice'), $this->bag->keys());
}
public function testSetAll()
{
$this->bag->add('one_flash', 'Foo');
$this->bag->add('another_flash', 'Bar');
$this->assertTrue($this->bag->has('one_flash'));
$this->assertTrue($this->bag->has('another_flash'));
$this->bag->setAll(array('unique_flash' => 'FooBar'));
$this->assertFalse($this->bag->has('one_flash'));
$this->assertFalse($this->bag->has('another_flash'));
$this->assertSame(array('unique_flash' => 'FooBar'), $this->bag->all());
$this->assertSame(array(), $this->bag->all());
}
public function testPeekAll()
{
$this->bag->set('notice', 'Foo');

View File

@@ -12,9 +12,9 @@
namespace Symfony\Component\HttpFoundation\Tests\Session;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
/**
@@ -70,6 +70,27 @@ class SessionTest extends TestCase
$this->assertEquals('0123456789abcdef', $this->session->getId());
}
public function testSetIdAfterStart()
{
$this->session->start();
$id = $this->session->getId();
$e = null;
try {
$this->session->setId($id);
} catch (\Exception $e) {
}
$this->assertNull($e);
try {
$this->session->setId('different');
} catch (\Exception $e) {
}
$this->assertInstanceOf('\LogicException', $e);
}
public function testSetName()
{
$this->assertEquals('MOCKSESSID', $this->session->getName());
@@ -206,7 +227,7 @@ class SessionTest extends TestCase
++$i;
}
$this->assertEquals(count($attributes), $i);
$this->assertEquals(\count($attributes), $i);
}
public function testGetCount()

View File

@@ -0,0 +1,145 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler;
/**
* @requires extension redis
* @group time-sensitive
*/
abstract class AbstractRedisSessionHandlerTestCase extends TestCase
{
protected const PREFIX = 'prefix_';
/**
* @var RedisSessionHandler
*/
protected $storage;
/**
* @var \Redis|\RedisArray|\RedisCluster|\Predis\Client
*/
protected $redisClient;
/**
* @return \Redis|\RedisArray|\RedisCluster|\Predis\Client
*/
abstract protected function createRedisClient(string $host);
protected function setUp()
{
parent::setUp();
if (!\extension_loaded('redis')) {
self::markTestSkipped('Extension redis required.');
}
$host = getenv('REDIS_HOST') ?: 'localhost';
$this->redisClient = $this->createRedisClient($host);
$this->storage = new RedisSessionHandler(
$this->redisClient,
array('prefix' => self::PREFIX)
);
}
protected function tearDown()
{
$this->redisClient = null;
$this->storage = null;
parent::tearDown();
}
public function testOpenSession()
{
$this->assertTrue($this->storage->open('', ''));
}
public function testCloseSession()
{
$this->assertTrue($this->storage->close());
}
public function testReadSession()
{
$this->redisClient->set(self::PREFIX.'id1', null);
$this->redisClient->set(self::PREFIX.'id2', 'abc123');
$this->assertEquals('', $this->storage->read('id1'));
$this->assertEquals('abc123', $this->storage->read('id2'));
}
public function testWriteSession()
{
$this->assertTrue($this->storage->write('id', 'data'));
$this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id'));
$this->assertEquals('data', $this->redisClient->get(self::PREFIX.'id'));
}
public function testUseSessionGcMaxLifetimeAsTimeToLive()
{
$this->storage->write('id', 'data');
$ttl = $this->redisClient->ttl(self::PREFIX.'id');
$this->assertLessThanOrEqual(ini_get('session.gc_maxlifetime'), $ttl);
$this->assertGreaterThanOrEqual(0, $ttl);
}
public function testDestroySession()
{
$this->redisClient->set(self::PREFIX.'id', 'foo');
$this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id'));
$this->assertTrue($this->storage->destroy('id'));
$this->assertFalse((bool) $this->redisClient->exists(self::PREFIX.'id'));
}
public function testGcSession()
{
$this->assertTrue($this->storage->gc(123));
}
public function testUpdateTimestamp()
{
$lowTtl = 10;
$this->redisClient->setex(self::PREFIX.'id', $lowTtl, 'foo');
$this->storage->updateTimestamp('id', array());
$this->assertGreaterThan($lowTtl, $this->redisClient->ttl(self::PREFIX.'id'));
}
/**
* @dataProvider getOptionFixtures
*/
public function testSupportedParam(array $options, bool $supported)
{
try {
new RedisSessionHandler($this->redisClient, $options);
$this->assertTrue($supported);
} catch (\InvalidArgumentException $e) {
$this->assertFalse($supported);
}
}
public function getOptionFixtures(): array
{
return array(
array(array('prefix' => 'session'), true),
array(array('prefix' => 'sfs', 'foo' => 'bar'), false),
);
}
}

View File

@@ -13,9 +13,6 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use PHPUnit\Framework\TestCase;
/**
* @requires PHP 7.0
*/
class AbstractSessionHandlerTest extends TestCase
{
private static $server;

View File

@@ -1,135 +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 PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler;
/**
* @requires extension memcache
* @group time-sensitive
* @group legacy
*/
class MemcacheSessionHandlerTest extends TestCase
{
const PREFIX = 'prefix_';
const TTL = 1000;
/**
* @var MemcacheSessionHandler
*/
protected $storage;
protected $memcache;
protected function setUp()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcache class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
}
parent::setUp();
$this->memcache = $this->getMockBuilder('Memcache')->getMock();
$this->storage = new MemcacheSessionHandler(
$this->memcache,
array('prefix' => self::PREFIX, 'expiretime' => self::TTL)
);
}
protected function tearDown()
{
$this->memcache = null;
$this->storage = null;
parent::tearDown();
}
public function testOpenSession()
{
$this->assertTrue($this->storage->open('', ''));
}
public function testCloseSession()
{
$this->assertTrue($this->storage->close());
}
public function testReadSession()
{
$this->memcache
->expects($this->once())
->method('get')
->with(self::PREFIX.'id')
;
$this->assertEquals('', $this->storage->read('id'));
}
public function testWriteSession()
{
$this->memcache
->expects($this->once())
->method('set')
->with(self::PREFIX.'id', 'data', 0, $this->equalTo(time() + self::TTL, 2))
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->write('id', 'data'));
}
public function testDestroySession()
{
$this->memcache
->expects($this->once())
->method('delete')
->with(self::PREFIX.'id')
->will($this->returnValue(true))
;
$this->assertTrue($this->storage->destroy('id'));
}
public function testGcSession()
{
$this->assertTrue($this->storage->gc(123));
}
/**
* @dataProvider getOptionFixtures
*/
public function testSupportedOptions($options, $supported)
{
try {
new MemcacheSessionHandler($this->memcache, $options);
$this->assertTrue($supported);
} catch (\InvalidArgumentException $e) {
$this->assertFalse($supported);
}
}
public function getOptionFixtures()
{
return array(
array(array('prefix' => 'session'), true),
array(array('expiretime' => 100), true),
array(array('prefix' => 'session', 'expiretime' => 200), true),
array(array('expiretime' => 100, 'foo' => 'bar'), false),
);
}
public function testGetConnection()
{
$method = new \ReflectionMethod($this->storage, 'getMemcache');
$method->setAccessible(true);
$this->assertInstanceOf('\Memcache', $method->invoke($this->storage));
}
}

View File

@@ -32,10 +32,6 @@ class MemcachedSessionHandlerTest extends TestCase
protected function setUp()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcached class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
}
parent::setUp();
if (version_compare(phpversion('memcached'), '2.2.0', '>=') && version_compare(phpversion('memcached'), '3.0.0b1', '<')) {

View File

@@ -0,0 +1,186 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MigratingSessionHandler;
class MigratingSessionHandlerTest extends TestCase
{
private $dualHandler;
private $currentHandler;
private $writeOnlyHandler;
protected function setUp()
{
$this->currentHandler = $this->createMock(\SessionHandlerInterface::class);
$this->writeOnlyHandler = $this->createMock(\SessionHandlerInterface::class);
$this->dualHandler = new MigratingSessionHandler($this->currentHandler, $this->writeOnlyHandler);
}
public function testInstanceOf()
{
$this->assertInstanceOf(\SessionHandlerInterface::class, $this->dualHandler);
$this->assertInstanceOf(\SessionUpdateTimestampHandlerInterface::class, $this->dualHandler);
}
public function testClose()
{
$this->currentHandler->expects($this->once())
->method('close')
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('close')
->will($this->returnValue(false));
$result = $this->dualHandler->close();
$this->assertTrue($result);
}
public function testDestroy()
{
$sessionId = 'xyz';
$this->currentHandler->expects($this->once())
->method('destroy')
->with($sessionId)
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('destroy')
->with($sessionId)
->will($this->returnValue(false));
$result = $this->dualHandler->destroy($sessionId);
$this->assertTrue($result);
}
public function testGc()
{
$maxlifetime = 357;
$this->currentHandler->expects($this->once())
->method('gc')
->with($maxlifetime)
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('gc')
->with($maxlifetime)
->will($this->returnValue(false));
$result = $this->dualHandler->gc($maxlifetime);
$this->assertTrue($result);
}
public function testOpen()
{
$savePath = '/path/to/save/location';
$sessionName = 'xyz';
$this->currentHandler->expects($this->once())
->method('open')
->with($savePath, $sessionName)
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('open')
->with($savePath, $sessionName)
->will($this->returnValue(false));
$result = $this->dualHandler->open($savePath, $sessionName);
$this->assertTrue($result);
}
public function testRead()
{
$sessionId = 'xyz';
$readValue = 'something';
$this->currentHandler->expects($this->once())
->method('read')
->with($sessionId)
->will($this->returnValue($readValue));
$this->writeOnlyHandler->expects($this->never())
->method('read')
->with($this->any());
$result = $this->dualHandler->read($sessionId);
$this->assertSame($readValue, $result);
}
public function testWrite()
{
$sessionId = 'xyz';
$data = 'my-serialized-data';
$this->currentHandler->expects($this->once())
->method('write')
->with($sessionId, $data)
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('write')
->with($sessionId, $data)
->will($this->returnValue(false));
$result = $this->dualHandler->write($sessionId, $data);
$this->assertTrue($result);
}
public function testValidateId()
{
$sessionId = 'xyz';
$readValue = 'something';
$this->currentHandler->expects($this->once())
->method('read')
->with($sessionId)
->will($this->returnValue($readValue));
$this->writeOnlyHandler->expects($this->never())
->method('read')
->with($this->any());
$result = $this->dualHandler->validateId($sessionId);
$this->assertTrue($result);
}
public function testUpdateTimestamp()
{
$sessionId = 'xyz';
$data = 'my-serialized-data';
$this->currentHandler->expects($this->once())
->method('write')
->with($sessionId, $data)
->will($this->returnValue(true));
$this->writeOnlyHandler->expects($this->once())
->method('write')
->with($sessionId, $data)
->will($this->returnValue(false));
$result = $this->dualHandler->updateTimestamp($sessionId, $data);
$this->assertTrue($result);
}
}

View File

@@ -17,7 +17,7 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandl
/**
* @author Markus Bachmann <markus.bachmann@bachi.biz>
* @group time-sensitive
* @group legacy
* @requires extension mongodb
*/
class MongoDbSessionHandlerTest extends TestCase
{
@@ -32,21 +32,11 @@ class MongoDbSessionHandlerTest extends TestCase
{
parent::setUp();
if (extension_loaded('mongodb')) {
if (!class_exists('MongoDB\Client')) {
$this->markTestSkipped('The mongodb/mongodb package is required.');
}
} elseif (!extension_loaded('mongo')) {
$this->markTestSkipped('The Mongo or MongoDB extension is required.');
if (!class_exists(\MongoDB\Client::class)) {
$this->markTestSkipped('The mongodb/mongodb package is required.');
}
if (phpversion('mongodb')) {
$mongoClass = 'MongoDB\Client';
} else {
$mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient';
}
$this->mongo = $this->getMockBuilder($mongoClass)
$this->mongo = $this->getMockBuilder(\MongoDB\Client::class)
->disableOriginalConstructor()
->getMock();
@@ -62,14 +52,6 @@ class MongoDbSessionHandlerTest extends TestCase
$this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorShouldThrowExceptionForInvalidMongo()
{
new MongoDbSessionHandler(new \stdClass(), $this->options);
}
/**
* @expectedException \InvalidArgumentException
*/
@@ -110,27 +92,14 @@ class MongoDbSessionHandlerTest extends TestCase
$this->assertArrayHasKey($this->options['expiry_field'], $criteria);
$this->assertArrayHasKey('$gte', $criteria[$this->options['expiry_field']]);
if (phpversion('mongodb')) {
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$gte']);
$this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout);
} else {
$this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$gte']);
$this->assertGreaterThanOrEqual($criteria[$this->options['expiry_field']]['$gte']->sec, $testTimeout);
}
$this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $criteria[$this->options['expiry_field']]['$gte']);
$this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout);
$fields = array(
return array(
$this->options['id_field'] => 'foo',
$this->options['expiry_field'] => new \MongoDB\BSON\UTCDateTime(),
$this->options['data_field'] => new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY),
);
if (phpversion('mongodb')) {
$fields[$this->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
$fields[$this->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000);
} else {
$fields[$this->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY);
$fields[$this->options['id_field']] = new \MongoDate();
}
return $fields;
}));
$this->assertEquals('bar', $this->storage->read('foo'));
@@ -145,89 +114,22 @@ class MongoDbSessionHandlerTest extends TestCase
->with($this->options['database'], $this->options['collection'])
->will($this->returnValue($collection));
$data = array();
$methodName = phpversion('mongodb') ? 'updateOne' : 'update';
$collection->expects($this->once())
->method($methodName)
->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) {
->method('updateOne')
->will($this->returnCallback(function ($criteria, $updateData, $options) {
$this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria);
if (phpversion('mongodb')) {
$this->assertEquals(array('upsert' => true), $options);
} else {
$this->assertEquals(array('upsert' => true, 'multiple' => false), $options);
}
$data = $updateData['$set'];
}));
$expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime');
$this->assertTrue($this->storage->write('foo', 'bar'));
if (phpversion('mongodb')) {
$this->assertEquals('bar', $data[$this->options['data_field']]->getData());
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]);
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]);
$this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000));
} else {
$this->assertEquals('bar', $data[$this->options['data_field']]->bin);
$this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
$this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]);
$this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec);
}
}
public function testWriteWhenUsingExpiresField()
{
$this->options = array(
'id_field' => '_id',
'data_field' => 'data',
'time_field' => 'time',
'database' => 'sf2-test',
'collection' => 'session-test',
'expiry_field' => 'expiresAt',
);
$this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
$collection = $this->createMongoCollectionMock();
$this->mongo->expects($this->once())
->method('selectCollection')
->with($this->options['database'], $this->options['collection'])
->will($this->returnValue($collection));
$data = array();
$methodName = phpversion('mongodb') ? 'updateOne' : 'update';
$collection->expects($this->once())
->method($methodName)
->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) {
$this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria);
if (phpversion('mongodb')) {
$this->assertEquals(array('upsert' => true), $options);
} else {
$this->assertEquals(array('upsert' => true, 'multiple' => false), $options);
}
$this->assertEquals(array('upsert' => true), $options);
$data = $updateData['$set'];
$expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime');
$this->assertInstanceOf(\MongoDB\BSON\Binary::class, $data[$this->options['data_field']]);
$this->assertEquals('bar', $data[$this->options['data_field']]->getData());
$this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $data[$this->options['time_field']]);
$this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $data[$this->options['expiry_field']]);
$this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000));
}));
$this->assertTrue($this->storage->write('foo', 'bar'));
if (phpversion('mongodb')) {
$this->assertEquals('bar', $data[$this->options['data_field']]->getData());
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]);
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]);
} else {
$this->assertEquals('bar', $data[$this->options['data_field']]->bin);
$this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
$this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]);
}
}
public function testReplaceSessionData()
@@ -241,10 +143,8 @@ class MongoDbSessionHandlerTest extends TestCase
$data = array();
$methodName = phpversion('mongodb') ? 'updateOne' : 'update';
$collection->expects($this->exactly(2))
->method($methodName)
->method('updateOne')
->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) {
$data = $updateData;
}));
@@ -252,11 +152,7 @@ class MongoDbSessionHandlerTest extends TestCase
$this->storage->write('foo', 'bar');
$this->storage->write('foo', 'foobar');
if (phpversion('mongodb')) {
$this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData());
} else {
$this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin);
}
$this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData());
}
public function testDestroy()
@@ -268,10 +164,8 @@ class MongoDbSessionHandlerTest extends TestCase
->with($this->options['database'], $this->options['collection'])
->will($this->returnValue($collection));
$methodName = phpversion('mongodb') ? 'deleteOne' : 'remove';
$collection->expects($this->once())
->method($methodName)
->method('deleteOne')
->with(array($this->options['id_field'] => 'foo'));
$this->assertTrue($this->storage->destroy('foo'));
@@ -286,18 +180,11 @@ class MongoDbSessionHandlerTest extends TestCase
->with($this->options['database'], $this->options['collection'])
->will($this->returnValue($collection));
$methodName = phpversion('mongodb') ? 'deleteMany' : 'remove';
$collection->expects($this->once())
->method($methodName)
->method('deleteMany')
->will($this->returnCallback(function ($criteria) {
if (phpversion('mongodb')) {
$this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$lt']);
$this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000));
} else {
$this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$lt']);
$this->assertGreaterThanOrEqual(time() - 1, $criteria[$this->options['expiry_field']]['$lt']->sec);
}
$this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $criteria[$this->options['expiry_field']]['$lt']);
$this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000));
}));
$this->assertTrue($this->storage->gc(1));
@@ -308,23 +195,12 @@ class MongoDbSessionHandlerTest extends TestCase
$method = new \ReflectionMethod($this->storage, 'getMongo');
$method->setAccessible(true);
if (phpversion('mongodb')) {
$mongoClass = 'MongoDB\Client';
} else {
$mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient';
}
$this->assertInstanceOf($mongoClass, $method->invoke($this->storage));
$this->assertInstanceOf(\MongoDB\Client::class, $method->invoke($this->storage));
}
private function createMongoCollectionMock()
{
$collectionClass = 'MongoCollection';
if (phpversion('mongodb')) {
$collectionClass = 'MongoDB\Collection';
}
$collection = $this->getMockBuilder($collectionClass)
$collection = $this->getMockBuilder(\MongoDB\Collection::class)
->disableOriginalConstructor()
->getMock();

View File

@@ -29,7 +29,6 @@ class NativeFileSessionHandlerTest extends TestCase
{
$storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir()));
$this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName());
$this->assertEquals('user', ini_get('session.save_handler'));
$this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path'));

View File

@@ -1,38 +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 PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
/**
* Test class for NativeSessionHandler.
*
* @author Drak <drak@zikula.org>
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @group legacy
*/
class NativeSessionHandlerTest extends TestCase
{
/**
* @expectedDeprecation The Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead.
*/
public function testConstruct()
{
$handler = new NativeSessionHandler();
$this->assertInstanceOf('SessionHandler', $handler);
$this->assertTrue($handler instanceof NativeSessionHandler);
}
}

View File

@@ -12,9 +12,9 @@
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* Test class for NullSessionHandler.

View File

@@ -136,10 +136,6 @@ class PdoSessionHandlerTest extends TestCase
public function testReadConvertsStreamToString()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
}
$pdo = new MockPdo('pgsql');
$pdo->prepareResult = $this->getMockBuilder('PDOStatement')->getMock();
@@ -157,9 +153,6 @@ class PdoSessionHandlerTest extends TestCase
public function testReadLockedConvertsStreamToString()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
}
if (ini_get('session.use_strict_mode')) {
$this->markTestSkipped('Strict mode needs no locking for new sessions.');
}
@@ -396,8 +389,8 @@ class MockPdo extends \PDO
public function prepare($statement, $driverOptions = array())
{
return is_callable($this->prepareResult)
? call_user_func($this->prepareResult, $statement, $driverOptions)
return \is_callable($this->prepareResult)
? \call_user_func($this->prepareResult, $statement, $driverOptions)
: $this->prepareResult;
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use Predis\Client;
class PredisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
{
protected function createRedisClient(string $host): Client
{
return new Client(array(array('host' => $host)));
}
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
use Predis\Client;
class PredisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
{
protected function createRedisClient(string $host): Client
{
return new Client(array('host' => $host));
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
class RedisArraySessionHandlerTest extends AbstractRedisSessionHandlerTestCase
{
protected function createRedisClient(string $host): \RedisArray
{
return new \RedisArray(array($host));
}
}

View File

@@ -0,0 +1,31 @@
<?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;
class RedisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
{
public static function setupBeforeClass()
{
if (!class_exists('RedisCluster')) {
self::markTestSkipped('The RedisCluster class is required.');
}
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
}
}
protected function createRedisClient(string $host): \RedisCluster
{
return new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS')));
}
}

View File

@@ -0,0 +1,23 @@
<?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;
class RedisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase
{
protected function createRedisClient(string $host): \Redis
{
$client = new \Redis();
$client->connect($host);
return $client;
}
}

View File

@@ -1,97 +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 PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler;
/**
* @author Adrien Brault <adrien.brault@gmail.com>
*
* @group legacy
*/
class WriteCheckSessionHandlerTest extends TestCase
{
public function test()
{
$wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock();
$writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock);
$wrappedSessionHandlerMock
->expects($this->once())
->method('close')
->with()
->will($this->returnValue(true))
;
$this->assertTrue($writeCheckSessionHandler->close());
}
public function testWrite()
{
$wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock();
$writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock);
$wrappedSessionHandlerMock
->expects($this->once())
->method('write')
->with('foo', 'bar')
->will($this->returnValue(true))
;
$this->assertTrue($writeCheckSessionHandler->write('foo', 'bar'));
}
public function testSkippedWrite()
{
$wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock();
$writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock);
$wrappedSessionHandlerMock
->expects($this->once())
->method('read')
->with('foo')
->will($this->returnValue('bar'))
;
$wrappedSessionHandlerMock
->expects($this->never())
->method('write')
;
$this->assertEquals('bar', $writeCheckSessionHandler->read('foo'));
$this->assertTrue($writeCheckSessionHandler->write('foo', 'bar'));
}
public function testNonSkippedWrite()
{
$wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock();
$writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock);
$wrappedSessionHandlerMock
->expects($this->once())
->method('read')
->with('foo')
->will($this->returnValue('bar'))
;
$wrappedSessionHandlerMock
->expects($this->once())
->method('write')
->with('foo', 'baZZZ')
->will($this->returnValue(true))
;
$this->assertEquals('bar', $writeCheckSessionHandler->read('foo'));
$this->assertTrue($writeCheckSessionHandler->write('foo', 'baZZZ'));
}
}

View File

@@ -12,9 +12,9 @@
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
/**
* Test class for MockArraySessionStorage.
@@ -48,7 +48,7 @@ class MockArraySessionStorageTest extends TestCase
$this->data = array(
$this->attributes->getStorageKey() => array('foo' => 'bar'),
$this->flashes->getStorageKey() => array('notice' => 'hello'),
);
);
$this->storage = new MockArraySessionStorage();
$this->storage->registerBag($this->flashes);

View File

@@ -12,9 +12,9 @@
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
/**
* Test class for MockFileSessionStorage.

View File

@@ -184,7 +184,7 @@ class NativeSessionStorageTest extends TestCase
public function testSessionOptions()
{
if (defined('HHVM_VERSION')) {
if (\defined('HHVM_VERSION')) {
$this->markTestSkipped('HHVM is not handled in this test case.');
}

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