Update to Drupal 8.2.6. For more information, see https://www.drupal.org/project/drupal/releases/8.2.6
This commit is contained in:
parent
db56c09587
commit
f1e72395cb
588 changed files with 26857 additions and 2777 deletions
|
@ -48,7 +48,7 @@ class AcceptHeader
|
|||
*
|
||||
* @param string $headerValue
|
||||
*
|
||||
* @return AcceptHeader
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($headerValue)
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ class AcceptHeader
|
|||
*
|
||||
* @param AcceptHeaderItem $item
|
||||
*
|
||||
* @return AcceptHeader
|
||||
* @return $this
|
||||
*/
|
||||
public function add(AcceptHeaderItem $item)
|
||||
{
|
||||
|
@ -128,7 +128,7 @@ class AcceptHeader
|
|||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return AcceptHeader
|
||||
* @return self
|
||||
*/
|
||||
public function filter($pattern)
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ class AcceptHeaderItem
|
|||
*
|
||||
* @param string $itemValue
|
||||
*
|
||||
* @return AcceptHeaderItem
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($itemValue)
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ class AcceptHeaderItem
|
|||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return AcceptHeaderItem
|
||||
* @return $this
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ class AcceptHeaderItem
|
|||
*
|
||||
* @param float $quality
|
||||
*
|
||||
* @return AcceptHeaderItem
|
||||
* @return $this
|
||||
*/
|
||||
public function setQuality($quality)
|
||||
{
|
||||
|
@ -151,7 +151,7 @@ class AcceptHeaderItem
|
|||
*
|
||||
* @param int $index
|
||||
*
|
||||
* @return AcceptHeaderItem
|
||||
* @return $this
|
||||
*/
|
||||
public function setIndex($index)
|
||||
{
|
||||
|
@ -211,7 +211,7 @@ class AcceptHeaderItem
|
|||
* @param string $name
|
||||
* @param string $value
|
||||
*
|
||||
* @return AcceptHeaderItem
|
||||
* @return $this
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ class BinaryFileResponse extends Response
|
|||
* @param bool $autoEtag Whether the ETag header should be automatically set
|
||||
* @param bool $autoLastModified Whether the Last-Modified header should be automatically set
|
||||
*
|
||||
* @return BinaryFileResponse The created response
|
||||
* @return static
|
||||
*/
|
||||
public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ class BinaryFileResponse extends Response
|
|||
* @param bool $autoEtag
|
||||
* @param bool $autoLastModified
|
||||
*
|
||||
* @return BinaryFileResponse
|
||||
* @return $this
|
||||
*
|
||||
* @throws FileException
|
||||
*/
|
||||
|
@ -153,7 +153,7 @@ class BinaryFileResponse extends Response
|
|||
* @param string $filename Optionally use this filename instead of the real name of the file
|
||||
* @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
|
||||
*
|
||||
* @return BinaryFileResponse
|
||||
* @return $this
|
||||
*/
|
||||
public function setContentDisposition($disposition, $filename = '', $filenameFallback = '')
|
||||
{
|
||||
|
@ -190,7 +190,7 @@ class BinaryFileResponse extends Response
|
|||
|
||||
if (!$this->headers->has('Accept-Ranges')) {
|
||||
// Only accept ranges on safe HTTP methods
|
||||
$this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none');
|
||||
$this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
|
||||
}
|
||||
|
||||
if (!$this->headers->has('Content-Type')) {
|
||||
|
@ -348,7 +348,7 @@ class BinaryFileResponse extends Response
|
|||
*
|
||||
* @param bool $shouldDelete
|
||||
*
|
||||
* @return BinaryFileResponse
|
||||
* @return $this
|
||||
*/
|
||||
public function deleteFileAfterSend($shouldDelete)
|
||||
{
|
||||
|
|
6
vendor/symfony/http-foundation/Cookie.php
vendored
6
vendor/symfony/http-foundation/Cookie.php
vendored
|
@ -56,7 +56,7 @@ class Cookie
|
|||
} elseif (!is_numeric($expire)) {
|
||||
$expire = strtotime($expire);
|
||||
|
||||
if (false === $expire || -1 === $expire) {
|
||||
if (false === $expire) {
|
||||
throw new \InvalidArgumentException('The cookie expiration time is not valid.');
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class Cookie
|
|||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->domain = $domain;
|
||||
$this->expire = $expire;
|
||||
$this->expire = 0 < $expire ? (int) $expire : 0;
|
||||
$this->path = empty($path) ? '/' : $path;
|
||||
$this->secure = (bool) $secure;
|
||||
$this->httpOnly = (bool) $httpOnly;
|
||||
|
@ -84,7 +84,7 @@ class Cookie
|
|||
} else {
|
||||
$str .= urlencode($this->getValue());
|
||||
|
||||
if ($this->getExpiresTime() !== 0) {
|
||||
if (0 !== $this->getExpiresTime()) {
|
||||
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime());
|
||||
}
|
||||
}
|
||||
|
|
23
vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php
vendored
Normal file
23
vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php
vendored
Normal 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\Exception;
|
||||
|
||||
/**
|
||||
* The HTTP request contains headers with conflicting information.
|
||||
*
|
||||
* This exception should trigger an HTTP 400 response in your application code.
|
||||
*
|
||||
* @author Magnus Nordlander <magnus@fervo.se>
|
||||
*/
|
||||
class ConflictingHeadersException extends \RuntimeException
|
||||
{
|
||||
}
|
4
vendor/symfony/http-foundation/File/File.php
vendored
4
vendor/symfony/http-foundation/File/File.php
vendored
|
@ -68,7 +68,7 @@ class File extends \SplFileInfo
|
|||
* mime_content_type() and the system binary "file" (in this order), depending on
|
||||
* which of those are available.
|
||||
*
|
||||
* @return string|null The guessed mime type (i.e. "application/pdf")
|
||||
* @return string|null The guessed mime type (e.g. "application/pdf")
|
||||
*
|
||||
* @see MimeTypeGuesser
|
||||
*/
|
||||
|
@ -85,7 +85,7 @@ class File extends \SplFileInfo
|
|||
* @param string $directory The destination folder
|
||||
* @param string $name The new file name
|
||||
*
|
||||
* @return File A File object representing the new file
|
||||
* @return self A File object representing the new file
|
||||
*
|
||||
* @throws FileException if the target file could not be created
|
||||
*/
|
||||
|
|
|
@ -42,7 +42,7 @@ class ExtensionGuesser implements ExtensionGuesserInterface
|
|||
/**
|
||||
* Returns the singleton instance.
|
||||
*
|
||||
* @return ExtensionGuesser
|
||||
* @return self
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
|
|||
*
|
||||
* @param string $magicFile A magic file to use with the finfo instance
|
||||
*
|
||||
* @link http://www.php.net/manual/en/function.finfo-open.php
|
||||
* @see http://www.php.net/manual/en/function.finfo-open.php
|
||||
*/
|
||||
public function __construct($magicFile = null)
|
||||
{
|
||||
|
|
|
@ -661,6 +661,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface
|
|||
'image/gif' => 'gif',
|
||||
'image/ief' => 'ief',
|
||||
'image/jpeg' => 'jpeg',
|
||||
'image/pjpeg' => 'jpeg',
|
||||
'image/ktx' => 'ktx',
|
||||
'image/png' => 'png',
|
||||
'image/prs.btif' => 'btif',
|
||||
|
|
|
@ -56,7 +56,7 @@ class MimeTypeGuesser implements MimeTypeGuesserInterface
|
|||
/**
|
||||
* Returns the singleton instance.
|
||||
*
|
||||
* @return MimeTypeGuesser
|
||||
* @return self
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
|
|
|
@ -50,7 +50,7 @@ class UploadedFile extends File
|
|||
/**
|
||||
* The file size provided by the uploader.
|
||||
*
|
||||
* @var string
|
||||
* @var int|null
|
||||
*/
|
||||
private $size;
|
||||
|
||||
|
@ -75,12 +75,12 @@ class UploadedFile extends File
|
|||
*
|
||||
* Calling any other method on an non-valid instance will cause an unpredictable result.
|
||||
*
|
||||
* @param string $path The full temporary path to the file
|
||||
* @param string $originalName The original file name
|
||||
* @param string $mimeType The type of the file as provided by PHP
|
||||
* @param int $size The file size
|
||||
* @param int $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants)
|
||||
* @param bool $test Whether the test mode is active
|
||||
* @param string $path The full temporary path to the file
|
||||
* @param string $originalName The original file name
|
||||
* @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream
|
||||
* @param int|null $size The file size
|
||||
* @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
|
||||
* @param bool $test Whether the test mode is active
|
||||
*
|
||||
* @throws FileException If file_uploads is disabled
|
||||
* @throws FileNotFoundException If the file does not exist
|
||||
|
@ -194,7 +194,7 @@ class UploadedFile extends File
|
|||
/**
|
||||
* Returns whether the file was uploaded successfully.
|
||||
*
|
||||
* @return bool True if the file has been uploaded with HTTP and no error occurred.
|
||||
* @return bool True if the file has been uploaded with HTTP and no error occurred
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
|
|
7
vendor/symfony/http-foundation/IpUtils.php
vendored
7
vendor/symfony/http-foundation/IpUtils.php
vendored
|
@ -57,15 +57,18 @@ class IpUtils
|
|||
* @param string $requestIp IPv4 address to check
|
||||
* @param string $ip IPv4 address or subnet in CIDR notation
|
||||
*
|
||||
* @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet.
|
||||
* @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet
|
||||
*/
|
||||
public static function checkIp4($requestIp, $ip)
|
||||
{
|
||||
if (!filter_var($requestIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false !== strpos($ip, '/')) {
|
||||
list($address, $netmask) = explode('/', $ip, 2);
|
||||
|
||||
if ($netmask === '0') {
|
||||
// Ensure IP is valid - using ip2long below implicitly validates, but we need to do it manually here
|
||||
return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
||||
}
|
||||
|
||||
|
|
37
vendor/symfony/http-foundation/JsonResponse.php
vendored
37
vendor/symfony/http-foundation/JsonResponse.php
vendored
|
@ -27,7 +27,7 @@ class JsonResponse extends Response
|
|||
protected $data;
|
||||
protected $callback;
|
||||
|
||||
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
|
||||
// Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML.
|
||||
// 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
|
||||
protected $encodingOptions = 15;
|
||||
|
||||
|
@ -50,7 +50,18 @@ class JsonResponse extends Response
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Factory method for chainability.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* return JsonResponse::create($data, 200)
|
||||
* ->setSharedMaxAge(300);
|
||||
*
|
||||
* @param mixed $data The json response data
|
||||
* @param int $status The response status code
|
||||
* @param array $headers An array of response headers
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create($data = null, $status = 200, $headers = array())
|
||||
{
|
||||
|
@ -62,18 +73,26 @@ class JsonResponse extends Response
|
|||
*
|
||||
* @param string|null $callback The JSONP callback or null to use none
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException When the callback name is not valid
|
||||
*/
|
||||
public function setCallback($callback = null)
|
||||
{
|
||||
if (null !== $callback) {
|
||||
// taken from http://www.geekality.net/2011/08/03/valid-javascript-identifier/
|
||||
$pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*+$/u';
|
||||
// partially token from http://www.geekality.net/2011/08/03/valid-javascript-identifier/
|
||||
// partially token from https://github.com/willdurand/JsonpCallbackValidator
|
||||
// JsonpCallbackValidator is released under the MIT License. See https://github.com/willdurand/JsonpCallbackValidator/blob/v1.1.0/LICENSE for details.
|
||||
// (c) William Durand <william.durand1@gmail.com>
|
||||
$pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*(?:\[(?:"(?:\\\.|[^"\\\])*"|\'(?:\\\.|[^\'\\\])*\'|\d+)\])*?$/u';
|
||||
$reserved = array(
|
||||
'break', 'do', 'instanceof', 'typeof', 'case', 'else', 'new', 'var', 'catch', 'finally', 'return', 'void', 'continue', 'for', 'switch', 'while',
|
||||
'debugger', 'function', 'this', 'with', 'default', 'if', 'throw', 'delete', 'in', 'try', 'class', 'enum', 'extends', 'super', 'const', 'export',
|
||||
'import', 'implements', 'let', 'private', 'public', 'yield', 'interface', 'package', 'protected', 'static', 'null', 'true', 'false',
|
||||
);
|
||||
$parts = explode('.', $callback);
|
||||
foreach ($parts as $part) {
|
||||
if (!preg_match($pattern, $part)) {
|
||||
if (!preg_match($pattern, $part) || in_array($part, $reserved, true)) {
|
||||
throw new \InvalidArgumentException('The callback name is not valid.');
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +108,7 @@ class JsonResponse extends Response
|
|||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
|
@ -165,7 +184,7 @@ class JsonResponse extends Response
|
|||
*
|
||||
* @param int $encodingOptions
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return $this
|
||||
*/
|
||||
public function setEncodingOptions($encodingOptions)
|
||||
{
|
||||
|
@ -177,7 +196,7 @@ class JsonResponse extends Response
|
|||
/**
|
||||
* Updates the content and headers according to the JSON data and callback.
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return $this
|
||||
*/
|
||||
protected function update()
|
||||
{
|
||||
|
|
2
vendor/symfony/http-foundation/LICENSE
vendored
2
vendor/symfony/http-foundation/LICENSE
vendored
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2004-2016 Fabien Potencier
|
||||
Copyright (c) 2004-2017 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
10
vendor/symfony/http-foundation/ParameterBag.php
vendored
10
vendor/symfony/http-foundation/ParameterBag.php
vendored
|
@ -248,11 +248,11 @@ class ParameterBag implements \IteratorAggregate, \Countable
|
|||
/**
|
||||
* Filter key.
|
||||
*
|
||||
* @param string $key Key.
|
||||
* @param mixed $default Default = null.
|
||||
* @param int $filter FILTER_* constant.
|
||||
* @param mixed $options Filter options.
|
||||
* @param bool $deep Default = false.
|
||||
* @param string $key Key
|
||||
* @param mixed $default Default = null
|
||||
* @param int $filter FILTER_* constant
|
||||
* @param mixed $options Filter options
|
||||
* @param bool $deep Default = false
|
||||
*
|
||||
* @see http://php.net/manual/en/function.filter-var.php
|
||||
*
|
||||
|
|
|
@ -66,7 +66,7 @@ class RedirectResponse extends Response
|
|||
*
|
||||
* @param string $url The URL to redirect to
|
||||
*
|
||||
* @return RedirectResponse The current response.
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
|
|
121
vendor/symfony/http-foundation/Request.php
vendored
121
vendor/symfony/http-foundation/Request.php
vendored
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace Symfony\Component\HttpFoundation;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
|
@ -260,7 +261,7 @@ class Request
|
|||
/**
|
||||
* Creates a new request with values from PHP's super globals.
|
||||
*
|
||||
* @return Request A new request
|
||||
* @return static
|
||||
*/
|
||||
public static function createFromGlobals()
|
||||
{
|
||||
|
@ -303,7 +304,7 @@ class Request
|
|||
* @param array $server The server parameters ($_SERVER)
|
||||
* @param string $content The raw body data
|
||||
*
|
||||
* @return Request A Request instance
|
||||
* @return static
|
||||
*/
|
||||
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
|
||||
{
|
||||
|
@ -421,7 +422,7 @@ class Request
|
|||
* @param array $files The FILES parameters
|
||||
* @param array $server The SERVER parameters
|
||||
*
|
||||
* @return Request The duplicated request
|
||||
* @return static
|
||||
*/
|
||||
public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
|
||||
{
|
||||
|
@ -553,7 +554,7 @@ class Request
|
|||
/**
|
||||
* Gets the list of trusted proxies.
|
||||
*
|
||||
* @return array An array of trusted proxies.
|
||||
* @return array An array of trusted proxies
|
||||
*/
|
||||
public static function getTrustedProxies()
|
||||
{
|
||||
|
@ -579,7 +580,7 @@ class Request
|
|||
/**
|
||||
* Gets the list of trusted host patterns.
|
||||
*
|
||||
* @return array An array of trusted host patterns.
|
||||
* @return array An array of trusted host patterns
|
||||
*/
|
||||
public static function getTrustedHosts()
|
||||
{
|
||||
|
@ -717,7 +718,7 @@ class Request
|
|||
* Note: Finding deep items is deprecated since version 2.8, to be removed in 3.0.
|
||||
*
|
||||
* @param string $key the key
|
||||
* @param mixed $default the default value
|
||||
* @param mixed $default the default value if the parameter key does not exist
|
||||
* @param bool $deep is parameter deep in multidimensional array
|
||||
*
|
||||
* @return mixed
|
||||
|
@ -811,41 +812,34 @@ class Request
|
|||
return array($ip);
|
||||
}
|
||||
|
||||
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
|
||||
$hasTrustedForwardedHeader = self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
||||
$hasTrustedClientIpHeader = self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP]);
|
||||
|
||||
if ($hasTrustedForwardedHeader) {
|
||||
$forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
|
||||
preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
|
||||
$clientIps = $matches[3];
|
||||
} elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
|
||||
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
|
||||
$forwardedClientIps = $matches[3];
|
||||
|
||||
$forwardedClientIps = $this->normalizeAndFilterClientIps($forwardedClientIps, $ip);
|
||||
$clientIps = $forwardedClientIps;
|
||||
}
|
||||
|
||||
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
|
||||
$firstTrustedIp = null;
|
||||
if ($hasTrustedClientIpHeader) {
|
||||
$xForwardedForClientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
|
||||
|
||||
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 (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
|
||||
unset($clientIps[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
|
||||
unset($clientIps[$key]);
|
||||
|
||||
// Fallback to this when the client IP falls into the range of trusted proxies
|
||||
if (null === $firstTrustedIp) {
|
||||
$firstTrustedIp = $clientIp;
|
||||
}
|
||||
}
|
||||
$xForwardedForClientIps = $this->normalizeAndFilterClientIps($xForwardedForClientIps, $ip);
|
||||
$clientIps = $xForwardedForClientIps;
|
||||
}
|
||||
|
||||
// Now the IP chain contains only untrusted proxies and the client IP
|
||||
return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
|
||||
if ($hasTrustedForwardedHeader && $hasTrustedClientIpHeader && $forwardedClientIps !== $xForwardedForClientIps) {
|
||||
throw new ConflictingHeadersException('The request has both a trusted Forwarded header and a trusted Client IP header, conflicting with each other with regards to the originating IP addresses of the request. This is the result of a misconfiguration. You should either configure your proxy only to send one of these headers, or configure Symfony to distrust one of them.');
|
||||
}
|
||||
|
||||
if (!$hasTrustedForwardedHeader && !$hasTrustedClientIpHeader) {
|
||||
return $this->normalizeAndFilterClientIps(array(), $ip);
|
||||
}
|
||||
|
||||
return $clientIps;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1402,7 +1396,7 @@ class Request
|
|||
/**
|
||||
* Sets the request format.
|
||||
*
|
||||
* @param string $format The request format.
|
||||
* @param string $format The request format
|
||||
*/
|
||||
public function setRequestFormat($format)
|
||||
{
|
||||
|
@ -1466,7 +1460,7 @@ class Request
|
|||
/**
|
||||
* Checks if the request method is of specified type.
|
||||
*
|
||||
* @param string $method Uppercase request method (GET, POST etc).
|
||||
* @param string $method Uppercase request method (GET, POST etc)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -1478,9 +1472,25 @@ class Request
|
|||
/**
|
||||
* Checks whether the method is safe or not.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7231#section-4.2.1
|
||||
*
|
||||
* @param bool $andCacheable Adds the additional condition that the method should be cacheable. True by default.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMethodSafe()
|
||||
public function isMethodSafe(/* $andCacheable = true */)
|
||||
{
|
||||
return in_array($this->getMethod(), 0 < func_num_args() && !func_get_arg(0) ? array('GET', 'HEAD', 'OPTIONS', 'TRACE') : array('GET', 'HEAD'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the method is cacheable or not.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7231#section-4.2.3
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMethodCacheable()
|
||||
{
|
||||
return in_array($this->getMethod(), array('GET', 'HEAD'));
|
||||
}
|
||||
|
@ -1490,7 +1500,7 @@ class Request
|
|||
*
|
||||
* @param bool $asResource If true, a resource will be returned
|
||||
*
|
||||
* @return string|resource The request body content or a resource to read the body stream.
|
||||
* @return string|resource The request body content or a resource to read the body stream
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
|
@ -1528,7 +1538,7 @@ class Request
|
|||
return stream_get_contents($this->content);
|
||||
}
|
||||
|
||||
if (null === $this->content) {
|
||||
if (null === $this->content || false === $this->content) {
|
||||
$this->content = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
|
@ -1676,7 +1686,7 @@ class Request
|
|||
* It works if your JavaScript library sets an X-Requested-With HTTP header.
|
||||
* It is known to work with common JavaScript frameworks:
|
||||
*
|
||||
* @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
|
||||
* @see http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
|
||||
*
|
||||
* @return bool true if the request is an XMLHttpRequest, false otherwise
|
||||
*/
|
||||
|
@ -1936,4 +1946,35 @@ class Request
|
|||
{
|
||||
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies);
|
||||
}
|
||||
|
||||
private function normalizeAndFilterClientIps(array $clientIps, $ip)
|
||||
{
|
||||
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
|
||||
$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 (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
|
||||
unset($clientIps[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
|
||||
unset($clientIps[$key]);
|
||||
|
||||
// Fallback to this when the client IP falls into the range of trusted proxies
|
||||
if (null === $firstTrustedIp) {
|
||||
$firstTrustedIp = $clientIp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now the IP chain contains only untrusted proxies and the client IP
|
||||
return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,22 +19,22 @@ namespace Symfony\Component\HttpFoundation;
|
|||
class RequestMatcher implements RequestMatcherInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var string[]
|
||||
*/
|
||||
private $methods = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string[]
|
||||
*/
|
||||
private $ips = array();
|
||||
|
||||
|
@ -76,13 +76,13 @@ class RequestMatcher implements RequestMatcherInterface
|
|||
*/
|
||||
public function matchScheme($scheme)
|
||||
{
|
||||
$this->schemes = array_map('strtolower', (array) $scheme);
|
||||
$this->schemes = null !== $scheme ? array_map('strtolower', (array) $scheme) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a check for the URL host name.
|
||||
*
|
||||
* @param string $regexp A Regexp
|
||||
* @param string|null $regexp A Regexp
|
||||
*/
|
||||
public function matchHost($regexp)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ class RequestMatcher implements RequestMatcherInterface
|
|||
/**
|
||||
* Adds a check for the URL path info.
|
||||
*
|
||||
* @param string $regexp A Regexp
|
||||
* @param string|null $regexp A Regexp
|
||||
*/
|
||||
public function matchPath($regexp)
|
||||
{
|
||||
|
@ -112,21 +112,21 @@ class RequestMatcher implements RequestMatcherInterface
|
|||
/**
|
||||
* Adds a check for the client IP.
|
||||
*
|
||||
* @param string|string[] $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24
|
||||
* @param string|string[]|null $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24
|
||||
*/
|
||||
public function matchIps($ips)
|
||||
{
|
||||
$this->ips = (array) $ips;
|
||||
$this->ips = null !== $ips ? (array) $ips : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a check for the HTTP method.
|
||||
*
|
||||
* @param string|string[] $method An HTTP method or an array of HTTP methods
|
||||
* @param string|string[]|null $method An HTTP method or an array of HTTP methods
|
||||
*/
|
||||
public function matchMethod($method)
|
||||
{
|
||||
$this->methods = array_map('strtoupper', (array) $method);
|
||||
$this->methods = null !== $method ? array_map('strtoupper', (array) $method) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,11 +145,11 @@ class RequestMatcher implements RequestMatcherInterface
|
|||
*/
|
||||
public function matches(Request $request)
|
||||
{
|
||||
if ($this->schemes && !in_array($request->getScheme(), $this->schemes)) {
|
||||
if ($this->schemes && !in_array($request->getScheme(), $this->schemes, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->methods && !in_array($request->getMethod(), $this->methods)) {
|
||||
if ($this->methods && !in_array($request->getMethod(), $this->methods, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
54
vendor/symfony/http-foundation/Response.php
vendored
54
vendor/symfony/http-foundation/Response.php
vendored
|
@ -59,6 +59,7 @@ class Response
|
|||
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
const HTTP_EXPECTATION_FAILED = 417;
|
||||
const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
|
||||
const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
|
||||
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
|
||||
const HTTP_LOCKED = 423; // RFC4918
|
||||
const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
|
||||
|
@ -115,7 +116,7 @@ class Response
|
|||
*
|
||||
* The list of codes is complete according to the
|
||||
* {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}
|
||||
* (last updated 2015-05-19).
|
||||
* (last updated 2016-03-01).
|
||||
*
|
||||
* Unless otherwise noted, the status code is defined in RFC2616.
|
||||
*
|
||||
|
@ -162,6 +163,7 @@ class Response
|
|||
416 => 'Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot', // RFC2324
|
||||
421 => 'Misdirected Request', // RFC7540
|
||||
422 => 'Unprocessable Entity', // RFC4918
|
||||
423 => 'Locked', // RFC4918
|
||||
424 => 'Failed Dependency', // RFC4918
|
||||
|
@ -213,7 +215,7 @@ class Response
|
|||
* @param int $status The response status code
|
||||
* @param array $headers An array of response headers
|
||||
*
|
||||
* @return Response
|
||||
* @return static
|
||||
*/
|
||||
public static function create($content = '', $status = 200, $headers = array())
|
||||
{
|
||||
|
@ -256,7 +258,7 @@ class Response
|
|||
*
|
||||
* @param Request $request A Request instance
|
||||
*
|
||||
* @return Response The current response.
|
||||
* @return $this
|
||||
*/
|
||||
public function prepare(Request $request)
|
||||
{
|
||||
|
@ -318,7 +320,7 @@ class Response
|
|||
/**
|
||||
* Sends HTTP headers.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function sendHeaders()
|
||||
{
|
||||
|
@ -352,7 +354,7 @@ class Response
|
|||
/**
|
||||
* Sends content for the current web response.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function sendContent()
|
||||
{
|
||||
|
@ -364,7 +366,7 @@ class Response
|
|||
/**
|
||||
* Sends HTTP headers and content.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
|
@ -387,7 +389,7 @@ class Response
|
|||
*
|
||||
* @param mixed $content Content that can be cast to string
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
|
@ -417,7 +419,7 @@ class Response
|
|||
*
|
||||
* @param string $version The HTTP protocol version
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setProtocolVersion($version)
|
||||
{
|
||||
|
@ -445,7 +447,7 @@ class Response
|
|||
* If the status text is null it will be automatically populated for the known
|
||||
* status codes and left empty otherwise.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException When the HTTP status code is not valid
|
||||
*/
|
||||
|
@ -488,7 +490,7 @@ class Response
|
|||
*
|
||||
* @param string $charset Character set
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setCharset($charset)
|
||||
{
|
||||
|
@ -561,7 +563,7 @@ class Response
|
|||
*
|
||||
* It makes the response ineligible for serving other clients.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setPrivate()
|
||||
{
|
||||
|
@ -576,7 +578,7 @@ class Response
|
|||
*
|
||||
* It makes the response eligible for serving other clients.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setPublic()
|
||||
{
|
||||
|
@ -622,7 +624,7 @@ class Response
|
|||
*
|
||||
* @param \DateTime $date A \DateTime instance
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setDate(\DateTime $date)
|
||||
{
|
||||
|
@ -649,7 +651,7 @@ class Response
|
|||
/**
|
||||
* Marks the response stale by setting the Age header to be equal to the maximum age of the response.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function expire()
|
||||
{
|
||||
|
@ -682,7 +684,7 @@ class Response
|
|||
*
|
||||
* @param \DateTime|null $date A \DateTime instance or null to remove the header
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setExpires(\DateTime $date = null)
|
||||
{
|
||||
|
@ -728,7 +730,7 @@ class Response
|
|||
*
|
||||
* @param int $value Number of seconds
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setMaxAge($value)
|
||||
{
|
||||
|
@ -744,7 +746,7 @@ class Response
|
|||
*
|
||||
* @param int $value Number of seconds
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setSharedMaxAge($value)
|
||||
{
|
||||
|
@ -778,7 +780,7 @@ class Response
|
|||
*
|
||||
* @param int $seconds Number of seconds
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setTtl($seconds)
|
||||
{
|
||||
|
@ -794,7 +796,7 @@ class Response
|
|||
*
|
||||
* @param int $seconds Number of seconds
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setClientTtl($seconds)
|
||||
{
|
||||
|
@ -822,7 +824,7 @@ class Response
|
|||
*
|
||||
* @param \DateTime|null $date A \DateTime instance or null to remove the header
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setLastModified(\DateTime $date = null)
|
||||
{
|
||||
|
@ -853,7 +855,7 @@ class Response
|
|||
* @param string|null $etag The ETag unique identifier or null to remove the header
|
||||
* @param bool $weak Whether you want a weak ETag or not
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setEtag($etag = null, $weak = false)
|
||||
{
|
||||
|
@ -877,7 +879,7 @@ class Response
|
|||
*
|
||||
* @param array $options An array of cache options
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
|
@ -928,7 +930,7 @@ class Response
|
|||
* This sets the status, removes the body, and discards any headers
|
||||
* that MUST NOT be included in 304 responses.
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc2616#section-10.3.5
|
||||
*/
|
||||
|
@ -980,7 +982,7 @@ class Response
|
|||
* @param string|array $headers
|
||||
* @param bool $replace Whether to replace the actual value or not (true by default)
|
||||
*
|
||||
* @return Response
|
||||
* @return $this
|
||||
*/
|
||||
public function setVary($headers, $replace = true)
|
||||
{
|
||||
|
@ -1002,7 +1004,7 @@ class Response
|
|||
*/
|
||||
public function isNotModified(Request $request)
|
||||
{
|
||||
if (!$request->isMethodSafe()) {
|
||||
if (!$request->isMethodCacheable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1165,7 +1167,7 @@ class Response
|
|||
/**
|
||||
* Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9.
|
||||
*
|
||||
* @link http://support.microsoft.com/kb/323308
|
||||
* @see http://support.microsoft.com/kb/323308
|
||||
*/
|
||||
protected function ensureIEOverSSLCompatibility(Request $request)
|
||||
{
|
||||
|
|
|
@ -181,9 +181,9 @@ class ResponseHeaderBag extends HeaderBag
|
|||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @throws \InvalidArgumentException When the $format is invalid
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \InvalidArgumentException When the $format is invalid
|
||||
*/
|
||||
public function getCookies($format = self::COOKIES_FLAT)
|
||||
{
|
||||
|
@ -230,7 +230,7 @@ class ResponseHeaderBag extends HeaderBag
|
|||
* is semantically equivalent to $filename. If the filename is already ASCII,
|
||||
* it can be omitted, or just copied from $filename
|
||||
*
|
||||
* @return string A string suitable for use as a Content-Disposition field-value.
|
||||
* @return string A string suitable for use as a Content-Disposition field-value
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
|
|
|
@ -29,8 +29,8 @@ class NamespacedAttributeBag extends AttributeBag
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $storageKey Session storage key.
|
||||
* @param string $namespaceCharacter Namespace character to use in keys.
|
||||
* @param string $storageKey Session storage key
|
||||
* @param string $namespaceCharacter Namespace character to use in keys
|
||||
*/
|
||||
public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/')
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ class AutoExpireFlashBag implements FlashBagInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $storageKey The key used to store flashes in the session.
|
||||
* @param string $storageKey The key used to store flashes in the session
|
||||
*/
|
||||
public function __construct($storageKey = '_sf2_flashes')
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ class FlashBag implements FlashBagInterface, \IteratorAggregate
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $storageKey The key used to store flashes in the session.
|
||||
* @param string $storageKey The key used to store flashes in the session
|
||||
*/
|
||||
public function __construct($storageKey = '_sf2_flashes')
|
||||
{
|
||||
|
|
|
@ -39,8 +39,8 @@ interface FlashBagInterface extends SessionBagInterface
|
|||
/**
|
||||
* Gets flash messages for a given type.
|
||||
*
|
||||
* @param string $type Message category type.
|
||||
* @param array $default Default value if $type does not exist.
|
||||
* @param string $type Message category type
|
||||
* @param array $default Default value if $type does not exist
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -57,7 +57,7 @@ interface FlashBagInterface extends SessionBagInterface
|
|||
* Gets and clears flash from the stack.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $default Default value if $type does not exist.
|
||||
* @param array $default Default value if $type does not exist
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -72,6 +72,8 @@ interface FlashBagInterface extends SessionBagInterface
|
|||
|
||||
/**
|
||||
* Sets all flash messages.
|
||||
*
|
||||
* @param array $messages
|
||||
*/
|
||||
public function setAll(array $messages);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param SessionStorageInterface $storage A SessionStorageInterface instance.
|
||||
* @param SessionStorageInterface $storage A SessionStorageInterface instance
|
||||
* @param AttributeBagInterface $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag)
|
||||
* @param FlashBagInterface $flashes A FlashBagInterface instance (defaults null for default FlashBag)
|
||||
*/
|
||||
|
|
|
@ -42,7 +42,7 @@ interface SessionBagInterface
|
|||
/**
|
||||
* Clears out data from bag.
|
||||
*
|
||||
* @return mixed Whatever data was contained.
|
||||
* @return mixed Whatever data was contained
|
||||
*/
|
||||
public function clear();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ interface SessionInterface
|
|||
/**
|
||||
* Starts the session storage.
|
||||
*
|
||||
* @return bool True if session started.
|
||||
* @return bool True if session started
|
||||
*
|
||||
* @throws \RuntimeException If session fails to start.
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ interface SessionInterface
|
|||
/**
|
||||
* Returns the session ID.
|
||||
*
|
||||
* @return string The session ID.
|
||||
* @return string The session ID
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
|
@ -46,7 +46,7 @@ interface SessionInterface
|
|||
/**
|
||||
* Returns the session name.
|
||||
*
|
||||
* @return mixed The session name.
|
||||
* @return mixed The session name
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
|
@ -68,7 +68,7 @@ interface SessionInterface
|
|||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool True if session invalidated, false if error.
|
||||
* @return bool True if session invalidated, false if error
|
||||
*/
|
||||
public function invalidate($lifetime = null);
|
||||
|
||||
|
@ -76,13 +76,13 @@ interface SessionInterface
|
|||
* Migrates the current session to a new session id while maintaining all
|
||||
* session attributes.
|
||||
*
|
||||
* @param bool $destroy Whether to delete the old session or leave it to garbage collection.
|
||||
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool True if session migrated, false if error.
|
||||
* @return bool True if session migrated, false if error
|
||||
*/
|
||||
public function migrate($destroy = false, $lifetime = null);
|
||||
|
||||
|
@ -108,7 +108,7 @@ interface SessionInterface
|
|||
* Returns an attribute.
|
||||
*
|
||||
* @param string $name The attribute name
|
||||
* @param mixed $default The default value if not found.
|
||||
* @param mixed $default The default value if not found
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
|||
class MemcacheSessionHandler implements \SessionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var \Memcache Memcache driver.
|
||||
* @var \Memcache Memcache driver
|
||||
*/
|
||||
private $memcache;
|
||||
|
||||
|
@ -29,7 +29,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface
|
|||
private $ttl;
|
||||
|
||||
/**
|
||||
* @var string Key prefix for shared environments.
|
||||
* @var string Key prefix for shared environments
|
||||
*/
|
||||
private $prefix;
|
||||
|
||||
|
@ -71,7 +71,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface
|
|||
*/
|
||||
public function close()
|
||||
{
|
||||
return $this->memcache->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
|||
class MemcachedSessionHandler implements \SessionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var \Memcached Memcached driver.
|
||||
* @var \Memcached Memcached driver
|
||||
*/
|
||||
private $memcached;
|
||||
|
||||
|
@ -34,7 +34,7 @@ class MemcachedSessionHandler implements \SessionHandlerInterface
|
|||
private $ttl;
|
||||
|
||||
/**
|
||||
* @var string Key prefix for shared environments.
|
||||
* @var string Key prefix for shared environments
|
||||
*/
|
||||
private $prefix;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
|
|||
class MongoDbSessionHandler implements \SessionHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var \Mongo
|
||||
* @var \Mongo|\MongoClient|\MongoDB\Client
|
||||
*/
|
||||
private $mongo;
|
||||
|
||||
|
@ -61,15 +61,15 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
* If you use such an index, you can drop `gc_probability` to 0 since
|
||||
* no garbage-collection is required.
|
||||
*
|
||||
* @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance
|
||||
* @param array $options An associative array of field options
|
||||
* @param \Mongo|\MongoClient|\MongoDB\Client $mongo A MongoDB\Client, MongoClient or Mongo 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)
|
||||
{
|
||||
if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
|
||||
if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
|
||||
throw new \InvalidArgumentException('MongoClient or Mongo instance required');
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,9 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
*/
|
||||
public function destroy($sessionId)
|
||||
{
|
||||
$this->getCollection()->remove(array(
|
||||
$methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
|
||||
|
||||
$this->getCollection()->$methodName(array(
|
||||
$this->options['id_field'] => $sessionId,
|
||||
));
|
||||
|
||||
|
@ -120,8 +122,10 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
$this->getCollection()->remove(array(
|
||||
$this->options['expiry_field'] => array('$lt' => new \MongoDate()),
|
||||
$methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
|
||||
|
||||
$this->getCollection()->$methodName(array(
|
||||
$this->options['expiry_field'] => array('$lt' => $this->createDateTime()),
|
||||
));
|
||||
|
||||
return true;
|
||||
|
@ -132,18 +136,28 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
*/
|
||||
public function write($sessionId, $data)
|
||||
{
|
||||
$expiry = new \MongoDate(time() + (int) ini_get('session.gc_maxlifetime'));
|
||||
$expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime'));
|
||||
|
||||
$fields = array(
|
||||
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
|
||||
$this->options['time_field'] => new \MongoDate(),
|
||||
$this->options['time_field'] => $this->createDateTime(),
|
||||
$this->options['expiry_field'] => $expiry,
|
||||
);
|
||||
|
||||
$this->getCollection()->update(
|
||||
$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(
|
||||
array($this->options['id_field'] => $sessionId),
|
||||
array('$set' => $fields),
|
||||
array('upsert' => true, 'multiple' => false)
|
||||
$options
|
||||
);
|
||||
|
||||
return true;
|
||||
|
@ -156,10 +170,18 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
{
|
||||
$dbData = $this->getCollection()->findOne(array(
|
||||
$this->options['id_field'] => $sessionId,
|
||||
$this->options['expiry_field'] => array('$gte' => new \MongoDate()),
|
||||
$this->options['expiry_field'] => array('$gte' => $this->createDateTime()),
|
||||
));
|
||||
|
||||
return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,10 +201,32 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||
/**
|
||||
* Return a Mongo instance.
|
||||
*
|
||||
* @return \Mongo
|
||||
* @return \Mongo|\MongoClient|\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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class NativeFileSessionHandler extends NativeSessionHandler
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $savePath Path of directory to save session files.
|
||||
* @param string $savePath Path of directory to save session files
|
||||
* Default null will leave setting as defined by PHP.
|
||||
* '/path', 'N;/path', or 'N;octal-mode;/path
|
||||
*
|
||||
|
|
|
@ -325,14 +325,8 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||
|
||||
try {
|
||||
// We use a single MERGE SQL query when supported by the database.
|
||||
$mergeSql = $this->getMergeSql();
|
||||
|
||||
if (null !== $mergeSql) {
|
||||
$mergeStmt = $this->pdo->prepare($mergeSql);
|
||||
$mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
||||
$mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
||||
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
$mergeStmt = $this->getMergeStatement($sessionId, $data, $maxlifetime);
|
||||
if (null !== $mergeStmt) {
|
||||
$mergeStmt->execute();
|
||||
|
||||
return true;
|
||||
|
@ -347,7 +341,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||
$updateStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
$updateStmt->execute();
|
||||
|
||||
// When MERGE is not supported, like in Postgres, we have to use this approach that can result in
|
||||
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
|
||||
// duplicate key errors when the same session is written simultaneously (given the LOCK_NONE behavior).
|
||||
// We can just catch such an error and re-execute the update. This is similar to a serializable
|
||||
// transaction with retry logic on serialization failures but without the overhead and without possible
|
||||
|
@ -510,54 +504,51 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||
$selectSql = $this->getSelectSql();
|
||||
$selectStmt = $this->pdo->prepare($selectSql);
|
||||
$selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$selectStmt->execute();
|
||||
|
||||
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
|
||||
do {
|
||||
$selectStmt->execute();
|
||||
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
|
||||
|
||||
if ($sessionRows) {
|
||||
if ($sessionRows[0][1] + $sessionRows[0][2] < time()) {
|
||||
$this->sessionExpired = true;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
|
||||
}
|
||||
|
||||
if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
|
||||
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
|
||||
// until other connections to the session are committed.
|
||||
try {
|
||||
$insertStmt = $this->pdo->prepare(
|
||||
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"
|
||||
);
|
||||
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$insertStmt->bindValue(':data', '', \PDO::PARAM_LOB);
|
||||
$insertStmt->bindValue(':lifetime', 0, \PDO::PARAM_INT);
|
||||
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
$insertStmt->execute();
|
||||
} catch (\PDOException $e) {
|
||||
// Catch duplicate key error because other connection created the session already.
|
||||
// It would only not be the case when the other connection destroyed the session.
|
||||
if (0 === strpos($e->getCode(), '23')) {
|
||||
// Retrieve finished session data written by concurrent connection. SELECT
|
||||
// FOR UPDATE is necessary to avoid deadlock of connection that starts reading
|
||||
// before we write (transform intention to real lock).
|
||||
$selectStmt->execute();
|
||||
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
|
||||
|
||||
if ($sessionRows) {
|
||||
return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
|
||||
}
|
||||
if ($sessionRows) {
|
||||
if ($sessionRows[0][1] + $sessionRows[0][2] < time()) {
|
||||
$this->sessionExpired = true;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
throw $e;
|
||||
return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
|
||||
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
|
||||
// until other connections to the session are committed.
|
||||
try {
|
||||
$insertStmt = $this->pdo->prepare(
|
||||
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"
|
||||
);
|
||||
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$insertStmt->bindValue(':data', '', \PDO::PARAM_LOB);
|
||||
$insertStmt->bindValue(':lifetime', 0, \PDO::PARAM_INT);
|
||||
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
$insertStmt->execute();
|
||||
} catch (\PDOException $e) {
|
||||
// Catch duplicate key error because other connection created the session already.
|
||||
// It would only not be the case when the other connection destroyed the session.
|
||||
if (0 === strpos($e->getCode(), '23')) {
|
||||
// Retrieve finished session data written by concurrent connection by restarting the loop.
|
||||
// We have to start a new transaction as a failed query will mark the current transaction as
|
||||
// aborted in PostgreSQL and disallow further queries within it.
|
||||
$this->rollback();
|
||||
$this->beginTransaction();
|
||||
continue;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,29 +644,64 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database for writing session data.
|
||||
* Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data.
|
||||
*
|
||||
* @return string|null The SQL string or null when not supported
|
||||
* @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 getMergeSql()
|
||||
private function getMergeStatement($sessionId, $data, $maxlifetime)
|
||||
{
|
||||
switch ($this->driver) {
|
||||
case 'mysql':
|
||||
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||
$mergeSql = null;
|
||||
switch (true) {
|
||||
case 'mysql' === $this->driver:
|
||||
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)";
|
||||
case 'oci':
|
||||
break;
|
||||
case 'oci' === $this->driver:
|
||||
// DUAL is Oracle specific dummy table
|
||||
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ".
|
||||
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time";
|
||||
$mergeSql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ".
|
||||
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
|
||||
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?";
|
||||
break;
|
||||
case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='):
|
||||
// MERGE is only available since SQL Server 2008 and must be terminated by semicolon
|
||||
// It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx
|
||||
return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ".
|
||||
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time;";
|
||||
case 'sqlite':
|
||||
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
|
||||
$mergeSql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ".
|
||||
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ".
|
||||
"WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;";
|
||||
break;
|
||||
case 'sqlite' === $this->driver:
|
||||
$mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
|
||||
break;
|
||||
case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='):
|
||||
$mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ".
|
||||
"ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)";
|
||||
break;
|
||||
}
|
||||
|
||||
if (null !== $mergeSql) {
|
||||
$mergeStmt = $this->pdo->prepare($mergeSql);
|
||||
|
||||
if ('sqlsrv' === $this->driver || 'oci' === $this->driver) {
|
||||
$mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR);
|
||||
$mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR);
|
||||
$mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB);
|
||||
$mergeStmt->bindParam(4, $maxlifetime, \PDO::PARAM_INT);
|
||||
$mergeStmt->bindValue(5, time(), \PDO::PARAM_INT);
|
||||
$mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB);
|
||||
$mergeStmt->bindParam(7, $maxlifetime, \PDO::PARAM_INT);
|
||||
$mergeStmt->bindValue(8, time(), \PDO::PARAM_INT);
|
||||
} else {
|
||||
$mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||
$mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
|
||||
$mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT);
|
||||
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||
}
|
||||
|
||||
return $mergeStmt;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class MetadataBag implements SessionBagInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $storageKey The key used to store bag in the session.
|
||||
* @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)
|
||||
|
|
|
@ -66,7 +66,7 @@ class MockArraySessionStorage implements SessionStorageInterface
|
|||
* Constructor.
|
||||
*
|
||||
* @param string $name Session name
|
||||
* @param MetadataBag $metaBag MetadataBag instance.
|
||||
* @param MetadataBag $metaBag MetadataBag instance
|
||||
*/
|
||||
public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null)
|
||||
{
|
||||
|
|
|
@ -32,9 +32,9 @@ class MockFileSessionStorage extends MockArraySessionStorage
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $savePath Path of directory to save session files.
|
||||
* @param string $name Session name.
|
||||
* @param MetadataBag $metaBag MetadataBag instance.
|
||||
* @param string $savePath Path of directory to save session files
|
||||
* @param string $name Session name
|
||||
* @param MetadataBag $metaBag MetadataBag instance
|
||||
*/
|
||||
public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null)
|
||||
{
|
||||
|
|
|
@ -92,9 +92,9 @@ class NativeSessionStorage implements SessionStorageInterface
|
|||
* upload_progress.min-freq, "1"
|
||||
* url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
|
||||
*
|
||||
* @param array $options Session configuration options.
|
||||
* @param array $options Session configuration options
|
||||
* @param AbstractProxy|NativeSessionHandler|\SessionHandlerInterface|null $handler
|
||||
* @param MetadataBag $metaBag MetadataBag.
|
||||
* @param MetadataBag $metaBag MetadataBag
|
||||
*/
|
||||
public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null)
|
||||
{
|
||||
|
@ -319,7 +319,7 @@ class NativeSessionStorage implements SessionStorageInterface
|
|||
* For convenience we omit 'session.' from the beginning of the keys.
|
||||
* Explicitly ignores other ini keys.
|
||||
*
|
||||
* @param array $options Session ini directives array(key => value).
|
||||
* @param array $options Session ini directives array(key => value)
|
||||
*
|
||||
* @see http://php.net/session.configuration
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ class NativeProxy extends AbstractProxy
|
|||
/**
|
||||
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
|
||||
*
|
||||
* @return bool False.
|
||||
* @return bool False
|
||||
*/
|
||||
public function isWrapper()
|
||||
{
|
||||
|
|
|
@ -24,23 +24,23 @@ interface SessionStorageInterface
|
|||
/**
|
||||
* Starts the session.
|
||||
*
|
||||
* @throws \RuntimeException If something goes wrong starting the session.
|
||||
* @return bool True if started
|
||||
*
|
||||
* @return bool True if started.
|
||||
* @throws \RuntimeException If something goes wrong starting the session.
|
||||
*/
|
||||
public function start();
|
||||
|
||||
/**
|
||||
* Checks if the session is started.
|
||||
*
|
||||
* @return bool True if started, false otherwise.
|
||||
* @return bool True if started, false otherwise
|
||||
*/
|
||||
public function isStarted();
|
||||
|
||||
/**
|
||||
* Returns the session ID.
|
||||
*
|
||||
* @return string The session ID or empty.
|
||||
* @return string The session ID or empty
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
|
@ -54,7 +54,7 @@ interface SessionStorageInterface
|
|||
/**
|
||||
* Returns the session name.
|
||||
*
|
||||
* @return mixed The session name.
|
||||
* @return mixed The session name
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class StreamedResponse extends Response
|
|||
{
|
||||
protected $callback;
|
||||
protected $streamed;
|
||||
private $headersSent;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -44,6 +45,7 @@ class StreamedResponse extends Response
|
|||
$this->setCallback($callback);
|
||||
}
|
||||
$this->streamed = false;
|
||||
$this->headersSent = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,7 +55,7 @@ class StreamedResponse extends Response
|
|||
* @param int $status The response status code
|
||||
* @param array $headers An array of response headers
|
||||
*
|
||||
* @return StreamedResponse
|
||||
* @return static
|
||||
*/
|
||||
public static function create($callback = null, $status = 200, $headers = array())
|
||||
{
|
||||
|
@ -75,6 +77,22 @@ class StreamedResponse extends Response
|
|||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* This method only sends the headers once.
|
||||
*/
|
||||
public function sendHeaders()
|
||||
{
|
||||
if ($this->headersSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->headersSent = true;
|
||||
|
||||
parent::sendHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
|
Reference in a new issue