Upgrade to latest Symfony HttpFoundation tag. Closes #1865.
This commit is contained in:
parent
92f602edbf
commit
b9cf8dfb71
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an Accept-* header.
|
||||||
|
*
|
||||||
|
* An accept header is compound with a list of items,
|
||||||
|
* sorted by descending quality.
|
||||||
|
*
|
||||||
|
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||||
|
*/
|
||||||
|
class AcceptHeader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var AcceptHeaderItem[]
|
||||||
|
*/
|
||||||
|
private $items = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $sorted = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param AcceptHeaderItem[] $items
|
||||||
|
*/
|
||||||
|
public function __construct(array $items)
|
||||||
|
{
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$this->add($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an AcceptHeader instance from a string.
|
||||||
|
*
|
||||||
|
* @param string $headerValue
|
||||||
|
*
|
||||||
|
* @return AcceptHeader
|
||||||
|
*/
|
||||||
|
public static function fromString($headerValue)
|
||||||
|
{
|
||||||
|
$index = 0;
|
||||||
|
|
||||||
|
return new self(array_map(function ($itemValue) use (&$index) {
|
||||||
|
$item = AcceptHeaderItem::fromString($itemValue);
|
||||||
|
$item->setIndex($index++);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header value's string representation.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return implode(',', $this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if header has given value.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public function has($value)
|
||||||
|
{
|
||||||
|
return isset($this->items[$value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns given value's item, if exists.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem|null
|
||||||
|
*/
|
||||||
|
public function get($value)
|
||||||
|
{
|
||||||
|
return isset($this->items[$value]) ? $this->items[$value] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an item.
|
||||||
|
*
|
||||||
|
* @param AcceptHeaderItem $item
|
||||||
|
*
|
||||||
|
* @return AcceptHeader
|
||||||
|
*/
|
||||||
|
public function add(AcceptHeaderItem $item)
|
||||||
|
{
|
||||||
|
$this->items[$item->getValue()] = $item;
|
||||||
|
$this->sorted = false;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all items.
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem[]
|
||||||
|
*/
|
||||||
|
public function all()
|
||||||
|
{
|
||||||
|
$this->sort();
|
||||||
|
|
||||||
|
return $this->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters items on their value using given regex.
|
||||||
|
*
|
||||||
|
* @param string $pattern
|
||||||
|
*
|
||||||
|
* @return AcceptHeader
|
||||||
|
*/
|
||||||
|
public function filter($pattern)
|
||||||
|
{
|
||||||
|
return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
|
||||||
|
return preg_match($pattern, $item->getValue());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first item.
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem|null
|
||||||
|
*/
|
||||||
|
public function first()
|
||||||
|
{
|
||||||
|
$this->sort();
|
||||||
|
|
||||||
|
return !empty($this->items) ? reset($this->items) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts items by descending quality
|
||||||
|
*/
|
||||||
|
private function sort()
|
||||||
|
{
|
||||||
|
if (!$this->sorted) {
|
||||||
|
uasort($this->items, function ($a, $b) {
|
||||||
|
$qA = $a->getQuality();
|
||||||
|
$qB = $b->getQuality();
|
||||||
|
|
||||||
|
if ($qA === $qB) {
|
||||||
|
return $a->getIndex() > $b->getIndex() ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qA > $qB ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->sorted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an Accept-* header item.
|
||||||
|
*
|
||||||
|
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||||
|
*/
|
||||||
|
class AcceptHeaderItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $quality = 1.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $index = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $attributes = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @param array $attributes
|
||||||
|
*/
|
||||||
|
public function __construct($value, array $attributes = array())
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
foreach ($attributes as $name => $value) {
|
||||||
|
$this->setAttribute($name, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an AcceptHeaderInstance instance from a string.
|
||||||
|
*
|
||||||
|
* @param string $itemValue
|
||||||
|
*
|
||||||
|
* @return 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();
|
||||||
|
|
||||||
|
$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] : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header value's string representation.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item value.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem
|
||||||
|
*/
|
||||||
|
public function setValue($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item quality.
|
||||||
|
*
|
||||||
|
* @param float $quality
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem
|
||||||
|
*/
|
||||||
|
public function setQuality($quality)
|
||||||
|
{
|
||||||
|
$this->quality = $quality;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item quality.
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public function getQuality()
|
||||||
|
{
|
||||||
|
return $this->quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the item index.
|
||||||
|
*
|
||||||
|
* @param int $index
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem
|
||||||
|
*/
|
||||||
|
public function setIndex($index)
|
||||||
|
{
|
||||||
|
$this->index = $index;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item index.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getIndex()
|
||||||
|
{
|
||||||
|
return $this->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if an attribute exists.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return Boolean
|
||||||
|
*/
|
||||||
|
public function hasAttribute($name)
|
||||||
|
{
|
||||||
|
return isset($this->attributes[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an attribute by its name.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $default
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getAttribute($name, $default = null)
|
||||||
|
{
|
||||||
|
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all attributes.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an attribute.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return AcceptHeaderItem
|
||||||
|
*/
|
||||||
|
public function setAttribute($name, $value)
|
||||||
|
{
|
||||||
|
if ('q' === $name) {
|
||||||
|
$this->quality = (float) $value;
|
||||||
|
} else {
|
||||||
|
$this->attributes[$name] = (string) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\File\File;
|
||||||
|
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BinaryFileResponse represents an HTTP response delivering a file.
|
||||||
|
*
|
||||||
|
* @author Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
|
||||||
|
* @author stealth35 <stealth35-php@live.fr>
|
||||||
|
* @author Igor Wiedler <igor@wiedler.ch>
|
||||||
|
* @author Jordan Alliot <jordan.alliot@gmail.com>
|
||||||
|
* @author Sergey Linnik <linniksa@gmail.com>
|
||||||
|
*/
|
||||||
|
class BinaryFileResponse extends Response
|
||||||
|
{
|
||||||
|
protected static $trustXSendfileTypeHeader = false;
|
||||||
|
|
||||||
|
protected $file;
|
||||||
|
protected $offset;
|
||||||
|
protected $maxlen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param SplFileInfo|string $file The file to stream
|
||||||
|
* @param integer $status The response status code
|
||||||
|
* @param array $headers An array of response headers
|
||||||
|
* @param boolean $public Files are public by default
|
||||||
|
* @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename
|
||||||
|
* @param boolean $autoEtag Whether the ETag header should be automatically set
|
||||||
|
* @param boolean $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)
|
||||||
|
{
|
||||||
|
parent::__construct(null, $status, $headers);
|
||||||
|
|
||||||
|
$this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
|
||||||
|
|
||||||
|
if ($public) {
|
||||||
|
$this->setPublic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
|
||||||
|
{
|
||||||
|
return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the file to stream.
|
||||||
|
*
|
||||||
|
* @param SplFileInfo|string $file The file to stream
|
||||||
|
* @param string $contentDisposition
|
||||||
|
* @param Boolean $autoEtag
|
||||||
|
* @param Boolean $autoLastModified
|
||||||
|
*
|
||||||
|
* @return BinaryFileResponse
|
||||||
|
*
|
||||||
|
* @throws FileException
|
||||||
|
*/
|
||||||
|
public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
|
||||||
|
{
|
||||||
|
$file = new File((string) $file);
|
||||||
|
|
||||||
|
if (!$file->isReadable()) {
|
||||||
|
throw new FileException('File must be readable.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->file = $file;
|
||||||
|
|
||||||
|
if ($autoEtag) {
|
||||||
|
$this->setAutoEtag();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($autoLastModified) {
|
||||||
|
$this->setAutoLastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($contentDisposition) {
|
||||||
|
$this->setContentDisposition($contentDisposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the file.
|
||||||
|
*
|
||||||
|
* @return File The file to stream
|
||||||
|
*/
|
||||||
|
public function getFile()
|
||||||
|
{
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically sets the Last-Modified header according the file modification date.
|
||||||
|
*/
|
||||||
|
public function setAutoLastModified()
|
||||||
|
{
|
||||||
|
$this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically sets the ETag header according to the checksum of the file.
|
||||||
|
*/
|
||||||
|
public function setAutoEtag()
|
||||||
|
{
|
||||||
|
$this->setEtag(sha1_file($this->file->getPathname()));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Content-Disposition header with the given filename.
|
||||||
|
*
|
||||||
|
* @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
public function setContentDisposition($disposition, $filename = '', $filenameFallback = '')
|
||||||
|
{
|
||||||
|
if ($filename === '') {
|
||||||
|
$filename = $this->file->getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
$dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
|
||||||
|
$this->headers->set('Content-Disposition', $dispositionHeader);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function prepare(Request $request)
|
||||||
|
{
|
||||||
|
$this->headers->set('Content-Length', $this->file->getSize());
|
||||||
|
$this->headers->set('Accept-Ranges', 'bytes');
|
||||||
|
$this->headers->set('Content-Transfer-Encoding', 'binary');
|
||||||
|
|
||||||
|
if (!$this->headers->has('Content-Type')) {
|
||||||
|
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) {
|
||||||
|
$this->setProtocolVersion('1.1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->offset = 0;
|
||||||
|
$this->maxlen = -1;
|
||||||
|
|
||||||
|
if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
|
||||||
|
// Use X-Sendfile, do not send any content.
|
||||||
|
$type = $request->headers->get('X-Sendfile-Type');
|
||||||
|
$path = $this->file->getRealPath();
|
||||||
|
if (strtolower($type) == 'x-accel-redirect') {
|
||||||
|
// Do X-Accel-Mapping substitutions.
|
||||||
|
foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
|
||||||
|
$mapping = explode('=', $mapping, 2);
|
||||||
|
|
||||||
|
if (2 == count($mapping)) {
|
||||||
|
$location = trim($mapping[0]);
|
||||||
|
$pathPrefix = trim($mapping[1]);
|
||||||
|
|
||||||
|
if (substr($path, 0, strlen($pathPrefix)) == $pathPrefix) {
|
||||||
|
$path = $location . substr($path, strlen($pathPrefix));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->headers->set($type, $path);
|
||||||
|
$this->maxlen = 0;
|
||||||
|
} elseif ($request->headers->has('Range')) {
|
||||||
|
// Process the range headers.
|
||||||
|
if (!$request->headers->has('If-Range') || $this->getEtag() == $request->headers->get('If-Range')) {
|
||||||
|
$range = $request->headers->get('Range');
|
||||||
|
$fileSize = $this->file->getSize();
|
||||||
|
|
||||||
|
list($start, $end) = explode('-', substr($range, 6), 2) + array(0);
|
||||||
|
|
||||||
|
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
|
||||||
|
|
||||||
|
if ('' === $start) {
|
||||||
|
$start = $fileSize - $end;
|
||||||
|
$end = $fileSize - 1;
|
||||||
|
} else {
|
||||||
|
$start = (int) $start;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = max($start, 0);
|
||||||
|
$end = min($end, $fileSize - 1);
|
||||||
|
|
||||||
|
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
|
||||||
|
$this->offset = $start;
|
||||||
|
|
||||||
|
$this->setStatusCode(206);
|
||||||
|
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the file.
|
||||||
|
*/
|
||||||
|
public function sendContent()
|
||||||
|
{
|
||||||
|
if (!$this->isSuccessful()) {
|
||||||
|
parent::sendContent();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === $this->maxlen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = fopen('php://output', 'wb');
|
||||||
|
$file = fopen($this->file->getPathname(), 'rb');
|
||||||
|
|
||||||
|
stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
|
||||||
|
|
||||||
|
fclose($out);
|
||||||
|
fclose($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @throws \LogicException when the content is not null
|
||||||
|
*/
|
||||||
|
public function setContent($content)
|
||||||
|
{
|
||||||
|
if (null !== $content) {
|
||||||
|
throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trust X-Sendfile-Type header.
|
||||||
|
*/
|
||||||
|
public static function trustXSendfileTypeHeader()
|
||||||
|
{
|
||||||
|
self::$trustXSendfileTypeHeader = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,20 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
2.2.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* fixed the Request::create() precedence (URI information always take precedence now)
|
||||||
|
* added Request::getTrustedProxies()
|
||||||
|
* deprecated Request::isProxyTrusted()
|
||||||
|
* [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects
|
||||||
|
* added a IpUtils class to check if an IP belongs to a CIDR
|
||||||
|
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
|
||||||
|
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to
|
||||||
|
enable it, and Request::getHttpMethodParameterOverride() to check if it is supported)
|
||||||
|
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
|
||||||
|
* Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3
|
||||||
|
|
||||||
2.1.0
|
2.1.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@ class Cookie
|
||||||
* @param Boolean $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
|
* @param Boolean $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
|
||||||
* @param Boolean $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
|
* @param Boolean $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)
|
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)
|
||||||
|
|
|
@ -45,7 +45,7 @@ public function __construct($cmd = 'file -b --mime %s 2>/dev/null')
|
||||||
*/
|
*/
|
||||||
public static function isSupported()
|
public static function isSupported()
|
||||||
{
|
{
|
||||||
return !defined('PHP_WINDOWS_VERSION_BUILD');
|
return !defined('PHP_WINDOWS_VERSION_BUILD') && function_exists('passthru') && function_exists('escapeshellarg');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +77,7 @@ public function guess($path)
|
||||||
|
|
||||||
$type = trim(ob_get_clean());
|
$type = trim(ob_get_clean());
|
||||||
|
|
||||||
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-]+)#i', $type, $match)) {
|
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
|
||||||
// it's not a type, but an error message
|
// it's not a type, but an error message
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
namespace Symfony\Component\HttpFoundation\File\MimeType;
|
namespace Symfony\Component\HttpFoundation\File\MimeType;
|
||||||
|
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
|
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
|
||||||
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
|
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
|
||||||
|
|
||||||
|
@ -99,7 +98,9 @@ public function register(MimeTypeGuesserInterface $guesser)
|
||||||
*
|
*
|
||||||
* @return string The mime type or NULL, if none could be guessed
|
* @return string The mime type or NULL, if none could be guessed
|
||||||
*
|
*
|
||||||
* @throws FileException If the file does not exist
|
* @throws \LogicException
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* @throws AccessDeniedException
|
||||||
*/
|
*/
|
||||||
public function guess($path)
|
public function guess($path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -118,6 +118,19 @@ public function getClientOriginalName()
|
||||||
return $this->originalName;
|
return $this->originalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original file extension
|
||||||
|
*
|
||||||
|
* It is extracted from the original file name that was uploaded.
|
||||||
|
* Then is should not be considered as a safe value.
|
||||||
|
*
|
||||||
|
* @return string The extension
|
||||||
|
*/
|
||||||
|
public function getClientOriginalExtension()
|
||||||
|
{
|
||||||
|
return pathinfo($this->originalName, PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file mime type.
|
* Returns the file mime type.
|
||||||
*
|
*
|
||||||
|
|
|
@ -149,7 +149,7 @@ public function get($key, $default = null, $first = true)
|
||||||
*
|
*
|
||||||
* @param string $key The key
|
* @param string $key The key
|
||||||
* @param string|array $values The value or an array of values
|
* @param string|array $values The value or an array of values
|
||||||
* @param Boolean $replace Whether to replace the actual value of not (true by default)
|
* @param Boolean $replace Whether to replace the actual value or not (true by default)
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
@ -223,7 +223,7 @@ public function remove($key)
|
||||||
* @param string $key The parameter key
|
* @param string $key The parameter key
|
||||||
* @param \DateTime $default The default value
|
* @param \DateTime $default The default value
|
||||||
*
|
*
|
||||||
* @return null|\DateTime The filtered value
|
* @return null|\DateTime The parsed DateTime or the default value if the header does not exist
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException When the HTTP header is not parseable
|
* @throws \RuntimeException When the HTTP header is not parseable
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?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 utility functions.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class IpUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This class should not be instantiated
|
||||||
|
*/
|
||||||
|
private function __construct() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates an IPv4 or IPv6 address.
|
||||||
|
*
|
||||||
|
* @param string $requestIp
|
||||||
|
* @param string $ip
|
||||||
|
*
|
||||||
|
* @return boolean Whether the IP is valid
|
||||||
|
*/
|
||||||
|
public static function checkIp($requestIp, $ip)
|
||||||
|
{
|
||||||
|
if (false !== strpos($requestIp, ':')) {
|
||||||
|
return self::checkIp6($requestIp, $ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::checkIp4($requestIp, $ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates an IPv4 address.
|
||||||
|
*
|
||||||
|
* @param string $requestIp
|
||||||
|
* @param string $ip
|
||||||
|
*
|
||||||
|
* @return boolean Whether the IP is valid
|
||||||
|
*/
|
||||||
|
public static function checkIp4($requestIp, $ip)
|
||||||
|
{
|
||||||
|
if (false !== strpos($ip, '/')) {
|
||||||
|
list($address, $netmask) = explode('/', $ip, 2);
|
||||||
|
|
||||||
|
if ($netmask < 1 || $netmask > 32) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$address = $ip;
|
||||||
|
$netmask = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates an IPv6 address.
|
||||||
|
*
|
||||||
|
* @author David Soria Parra <dsp at php dot net>
|
||||||
|
* @see https://github.com/dsp/v6tools
|
||||||
|
*
|
||||||
|
* @param string $requestIp
|
||||||
|
* @param string $ip
|
||||||
|
*
|
||||||
|
* @return boolean Whether the IP is valid
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException When IPV6 support is not enabled
|
||||||
|
*/
|
||||||
|
public static function checkIp6($requestIp, $ip)
|
||||||
|
{
|
||||||
|
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".');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== strpos($ip, '/')) {
|
||||||
|
list($address, $netmask) = explode('/', $ip, 2);
|
||||||
|
|
||||||
|
if ($netmask < 1 || $netmask > 128) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$address = $ip;
|
||||||
|
$netmask = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytesAddr = unpack("n*", inet_pton($address));
|
||||||
|
$bytesTest = unpack("n*", inet_pton($requestIp));
|
||||||
|
|
||||||
|
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
|
||||||
|
$left = $netmask - 16 * ($i-1);
|
||||||
|
$left = ($left <= 16) ? $left : 16;
|
||||||
|
$mask = ~(0xffff >> $left) & 0xffff;
|
||||||
|
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,17 +28,20 @@ class JsonResponse extends Response
|
||||||
* @param integer $status The response status code
|
* @param integer $status The response status code
|
||||||
* @param array $headers An array of response headers
|
* @param array $headers An array of response headers
|
||||||
*/
|
*/
|
||||||
public function __construct($data = array(), $status = 200, $headers = array())
|
public function __construct($data = null, $status = 200, $headers = array())
|
||||||
{
|
{
|
||||||
parent::__construct('', $status, $headers);
|
parent::__construct('', $status, $headers);
|
||||||
|
|
||||||
|
if (null === $data) {
|
||||||
|
$data = new \ArrayObject();
|
||||||
|
}
|
||||||
$this->setData($data);
|
$this->setData($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public static function create($data = array(), $status = 200, $headers = array())
|
public static function create($data = null, $status = 200, $headers = array())
|
||||||
{
|
{
|
||||||
return new static($data, $status, $headers);
|
return new static($data, $status, $headers);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +52,8 @@ public static function create($data = array(), $status = 200, $headers = array()
|
||||||
* @param string $callback
|
* @param string $callback
|
||||||
*
|
*
|
||||||
* @return JsonResponse
|
* @return JsonResponse
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function setCallback($callback = null)
|
public function setCallback($callback = null)
|
||||||
{
|
{
|
||||||
|
@ -77,11 +82,6 @@ public function setCallback($callback = null)
|
||||||
*/
|
*/
|
||||||
public function setData($data = array())
|
public function setData($data = array())
|
||||||
{
|
{
|
||||||
// root should be JSON object, not array
|
|
||||||
if (is_array($data) && 0 === count($data)) {
|
|
||||||
$data = new \ArrayObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
|
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
|
||||||
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
|
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2004-2012 Fabien Potencier
|
Copyright (c) 2004-2013 Fabien Potencier
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -96,6 +96,8 @@ public function add(array $parameters = array())
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function get($path, $default = null, $deep = false)
|
public function get($path, $default = null, $deep = false)
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
Loading
|
Loading
|
||||||
-------
|
-------
|
||||||
|
|
||||||
If you are using PHP 5.3.x you must add the following to your autoloader:
|
If you are not using Composer but are using PHP 5.3.x, you must add the following to your autoloader:
|
||||||
|
|
||||||
// SessionHandlerInterface
|
// SessionHandlerInterface
|
||||||
if (!interface_exists('SessionHandlerInterface')) {
|
if (!interface_exists('SessionHandlerInterface')) {
|
||||||
|
@ -43,4 +43,6 @@
|
||||||
|
|
||||||
You can run the unit tests with the following command:
|
You can run the unit tests with the following command:
|
||||||
|
|
||||||
phpunit
|
$ cd path/to/Symfony/Component/HttpFoundation/
|
||||||
|
$ composer.phar install --dev
|
||||||
|
$ phpunit
|
||||||
|
|
|
@ -29,6 +29,8 @@ class RedirectResponse extends Response
|
||||||
* @param integer $status The status code (302 by default)
|
* @param integer $status The status code (302 by default)
|
||||||
* @param array $headers The headers (Location is always set to the given url)
|
* @param array $headers The headers (Location is always set to the given url)
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
* @see http://tools.ietf.org/html/rfc2616#section-10.3
|
* @see http://tools.ietf.org/html/rfc2616#section-10.3
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
|
@ -72,6 +74,8 @@ public function getTargetUrl()
|
||||||
* @param string $url The URL to redirect to
|
* @param string $url The URL to redirect to
|
||||||
*
|
*
|
||||||
* @return RedirectResponse The current response.
|
* @return RedirectResponse The current response.
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function setTargetUrl($url)
|
public function setTargetUrl($url)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,10 +30,10 @@
|
||||||
*/
|
*/
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
const HEADER_CLIENT_IP = 'client_ip';
|
const HEADER_CLIENT_IP = 'client_ip';
|
||||||
const HEADER_CLIENT_HOST = 'client_host';
|
const HEADER_CLIENT_HOST = 'client_host';
|
||||||
const HEADER_CLIENT_PROTO = 'client_proto';
|
const HEADER_CLIENT_PROTO = 'client_proto';
|
||||||
const HEADER_CLIENT_PORT = 'client_port';
|
const HEADER_CLIENT_PORT = 'client_port';
|
||||||
|
|
||||||
protected static $trustProxy = false;
|
protected static $trustProxy = false;
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ class Request
|
||||||
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
|
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected static $httpMethodParameterOverride = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Symfony\Component\HttpFoundation\ParameterBag
|
* @var \Symfony\Component\HttpFoundation\ParameterBag
|
||||||
*
|
*
|
||||||
|
@ -251,6 +253,9 @@ public static function createFromGlobals()
|
||||||
/**
|
/**
|
||||||
* Creates a Request based on a given URI and configuration.
|
* Creates a Request based on a given URI and configuration.
|
||||||
*
|
*
|
||||||
|
* The information contained in the URI always take precedence
|
||||||
|
* over the other information (server and parameters).
|
||||||
|
*
|
||||||
* @param string $uri The URI
|
* @param string $uri The URI
|
||||||
* @param string $method The HTTP method
|
* @param string $method The HTTP method
|
||||||
* @param array $parameters The query (GET) or request (POST) parameters
|
* @param array $parameters The query (GET) or request (POST) parameters
|
||||||
|
@ -265,7 +270,7 @@ public static function createFromGlobals()
|
||||||
*/
|
*/
|
||||||
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
|
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
|
||||||
{
|
{
|
||||||
$defaults = array(
|
$server = array_replace(array(
|
||||||
'SERVER_NAME' => 'localhost',
|
'SERVER_NAME' => 'localhost',
|
||||||
'SERVER_PORT' => 80,
|
'SERVER_PORT' => 80,
|
||||||
'HTTP_HOST' => 'localhost',
|
'HTTP_HOST' => 'localhost',
|
||||||
|
@ -278,32 +283,38 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
|
||||||
'SCRIPT_FILENAME' => '',
|
'SCRIPT_FILENAME' => '',
|
||||||
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
||||||
'REQUEST_TIME' => time(),
|
'REQUEST_TIME' => time(),
|
||||||
);
|
), $server);
|
||||||
|
|
||||||
|
$server['PATH_INFO'] = '';
|
||||||
|
$server['REQUEST_METHOD'] = strtoupper($method);
|
||||||
|
|
||||||
$components = parse_url($uri);
|
$components = parse_url($uri);
|
||||||
if (isset($components['host'])) {
|
if (isset($components['host'])) {
|
||||||
$defaults['SERVER_NAME'] = $components['host'];
|
$server['SERVER_NAME'] = $components['host'];
|
||||||
$defaults['HTTP_HOST'] = $components['host'];
|
$server['HTTP_HOST'] = $components['host'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($components['scheme'])) {
|
if (isset($components['scheme'])) {
|
||||||
if ('https' === $components['scheme']) {
|
if ('https' === $components['scheme']) {
|
||||||
$defaults['HTTPS'] = 'on';
|
$server['HTTPS'] = 'on';
|
||||||
$defaults['SERVER_PORT'] = 443;
|
$server['SERVER_PORT'] = 443;
|
||||||
|
} else {
|
||||||
|
unset($server['HTTPS']);
|
||||||
|
$server['SERVER_PORT'] = 80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($components['port'])) {
|
if (isset($components['port'])) {
|
||||||
$defaults['SERVER_PORT'] = $components['port'];
|
$server['SERVER_PORT'] = $components['port'];
|
||||||
$defaults['HTTP_HOST'] = $defaults['HTTP_HOST'].':'.$components['port'];
|
$server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$components['port'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($components['user'])) {
|
if (isset($components['user'])) {
|
||||||
$defaults['PHP_AUTH_USER'] = $components['user'];
|
$server['PHP_AUTH_USER'] = $components['user'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($components['pass'])) {
|
if (isset($components['pass'])) {
|
||||||
$defaults['PHP_AUTH_PW'] = $components['pass'];
|
$server['PHP_AUTH_PW'] = $components['pass'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($components['path'])) {
|
if (!isset($components['path'])) {
|
||||||
|
@ -314,7 +325,9 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
|
||||||
case 'POST':
|
case 'POST':
|
||||||
case 'PUT':
|
case 'PUT':
|
||||||
case 'DELETE':
|
case 'DELETE':
|
||||||
$defaults['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
|
if (!isset($server['CONTENT_TYPE'])) {
|
||||||
|
$server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
|
||||||
|
}
|
||||||
case 'PATCH':
|
case 'PATCH':
|
||||||
$request = $parameters;
|
$request = $parameters;
|
||||||
$query = array();
|
$query = array();
|
||||||
|
@ -331,14 +344,8 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
|
||||||
}
|
}
|
||||||
$queryString = http_build_query($query, '', '&');
|
$queryString = http_build_query($query, '', '&');
|
||||||
|
|
||||||
$uri = $components['path'].('' !== $queryString ? '?'.$queryString : '');
|
$server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
|
||||||
|
$server['QUERY_STRING'] = $queryString;
|
||||||
$server = array_replace($defaults, $server, array(
|
|
||||||
'REQUEST_METHOD' => strtoupper($method),
|
|
||||||
'PATH_INFO' => '',
|
|
||||||
'REQUEST_URI' => $uri,
|
|
||||||
'QUERY_STRING' => $queryString,
|
|
||||||
));
|
|
||||||
|
|
||||||
return new static($query, $request, array(), $cookies, $files, $server, $content);
|
return new static($query, $request, array(), $cookies, $files, $server, $content);
|
||||||
}
|
}
|
||||||
|
@ -464,6 +471,8 @@ public function overrideGlobals()
|
||||||
*/
|
*/
|
||||||
public static function trustProxyData()
|
public static function trustProxyData()
|
||||||
{
|
{
|
||||||
|
trigger_error('trustProxyData() is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies() instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
self::$trustProxy = true;
|
self::$trustProxy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,6 +491,16 @@ public static function setTrustedProxies(array $proxies)
|
||||||
self::$trustProxy = $proxies ? true : false;
|
self::$trustProxy = $proxies ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of trusted proxies.
|
||||||
|
*
|
||||||
|
* @return array An array of trusted proxies.
|
||||||
|
*/
|
||||||
|
public static function getTrustedProxies()
|
||||||
|
{
|
||||||
|
return self::$trustedProxies;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name for trusted headers.
|
* Sets the name for trusted headers.
|
||||||
*
|
*
|
||||||
|
@ -496,6 +515,8 @@ public static function setTrustedProxies(array $proxies)
|
||||||
*
|
*
|
||||||
* @param string $key The header key
|
* @param string $key The header key
|
||||||
* @param string $value The header name
|
* @param string $value The header name
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public static function setTrustedHeaderName($key, $value)
|
public static function setTrustedHeaderName($key, $value)
|
||||||
{
|
{
|
||||||
|
@ -511,6 +532,8 @@ public static function setTrustedHeaderName($key, $value)
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.2, to be removed in 2.3. Use getTrustedProxies instead.
|
||||||
*/
|
*/
|
||||||
public static function isProxyTrusted()
|
public static function isProxyTrusted()
|
||||||
{
|
{
|
||||||
|
@ -560,6 +583,29 @@ public static function normalizeQueryString($qs)
|
||||||
return implode('&', $parts);
|
return implode('&', $parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables support for the _method request parameter to determine the intended HTTP method.
|
||||||
|
*
|
||||||
|
* Be warned that enabling this feature might lead to CSRF issues in your code.
|
||||||
|
* Check that you are using CSRF tokens when required.
|
||||||
|
*
|
||||||
|
* The HTTP method can only be overridden when the real HTTP method is POST.
|
||||||
|
*/
|
||||||
|
public static function enableHttpMethodParameterOverride()
|
||||||
|
{
|
||||||
|
self::$httpMethodParameterOverride = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether support for the _method request parameter is enabled.
|
||||||
|
*
|
||||||
|
* @return Boolean True when the _method request parameter is enabled, false otherwise
|
||||||
|
*/
|
||||||
|
public static function getHttpMethodParameterOverride()
|
||||||
|
{
|
||||||
|
return self::$httpMethodParameterOverride;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a "parameter" value.
|
* Gets a "parameter" value.
|
||||||
*
|
*
|
||||||
|
@ -657,8 +703,6 @@ public function setSession(SessionInterface $session)
|
||||||
*
|
*
|
||||||
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
|
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
|
||||||
*
|
*
|
||||||
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
|
|
||||||
*
|
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function getClientIp()
|
public function getClientIp()
|
||||||
|
@ -703,7 +747,7 @@ public function getScriptName()
|
||||||
*
|
*
|
||||||
* * http://localhost/mysite returns an empty string
|
* * http://localhost/mysite returns an empty string
|
||||||
* * http://localhost/mysite/about returns '/about'
|
* * http://localhost/mysite/about returns '/about'
|
||||||
* * htpp://localhost/mysite/enco%20ded returns '/enco%20ded'
|
* * http://localhost/mysite/enco%20ded returns '/enco%20ded'
|
||||||
* * http://localhost/mysite/about?var=1 returns '/about'
|
* * http://localhost/mysite/about?var=1 returns '/about'
|
||||||
*
|
*
|
||||||
* @return string The raw path (i.e. not urldecoded)
|
* @return string The raw path (i.e. not urldecoded)
|
||||||
|
@ -897,8 +941,7 @@ public function getSchemeAndHttpHost()
|
||||||
*/
|
*/
|
||||||
public function getUri()
|
public function getUri()
|
||||||
{
|
{
|
||||||
$qs = $this->getQueryString();
|
if (null !== $qs = $this->getQueryString()) {
|
||||||
if (null !== $qs) {
|
|
||||||
$qs = '?'.$qs;
|
$qs = '?'.$qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,26 +1060,51 @@ public function setMethod($method)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the request method.
|
* Gets the request "intended" method.
|
||||||
|
*
|
||||||
|
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
|
||||||
|
* then it is used to determine the "real" intended HTTP method.
|
||||||
|
*
|
||||||
|
* The _method request parameter can also be used to determine the HTTP method,
|
||||||
|
* but only if enableHttpMethodParameterOverride() has been called.
|
||||||
*
|
*
|
||||||
* The method is always an uppercased string.
|
* The method is always an uppercased string.
|
||||||
*
|
*
|
||||||
* @return string The request method
|
* @return string The request method
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
|
*
|
||||||
|
* @see getRealMethod
|
||||||
*/
|
*/
|
||||||
public function getMethod()
|
public function getMethod()
|
||||||
{
|
{
|
||||||
if (null === $this->method) {
|
if (null === $this->method) {
|
||||||
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
|
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
|
||||||
|
|
||||||
if ('POST' === $this->method) {
|
if ('POST' === $this->method) {
|
||||||
$this->method = strtoupper($this->headers->get('X-HTTP-METHOD-OVERRIDE', $this->request->get('_method', $this->query->get('_method', 'POST'))));
|
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')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->method;
|
return $this->method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the "real" request method.
|
||||||
|
*
|
||||||
|
* @return string The request method
|
||||||
|
*
|
||||||
|
* @see getMethod
|
||||||
|
*/
|
||||||
|
public function getRealMethod()
|
||||||
|
{
|
||||||
|
return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the mime type associated with the format.
|
* Gets the mime type associated with the format.
|
||||||
*
|
*
|
||||||
|
@ -1216,6 +1284,8 @@ public function isMethodSafe()
|
||||||
* @param Boolean $asResource If true, a resource will be returned
|
* @param Boolean $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
|
||||||
*/
|
*/
|
||||||
public function getContent($asResource = false)
|
public function getContent($asResource = false)
|
||||||
{
|
{
|
||||||
|
@ -1275,7 +1345,18 @@ public function getPreferredLanguage(array $locales = null)
|
||||||
return $locales[0];
|
return $locales[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
$preferredLanguages = array_values(array_intersect($preferredLanguages, $locales));
|
$extendedPreferredLanguages = array();
|
||||||
|
foreach ($preferredLanguages as $language) {
|
||||||
|
$extendedPreferredLanguages[] = $language;
|
||||||
|
if (false !== $position = strpos($language, '_')) {
|
||||||
|
$superLanguage = substr($language, 0, $position);
|
||||||
|
if (!in_array($superLanguage, $preferredLanguages)) {
|
||||||
|
$extendedPreferredLanguages[] = $superLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
|
||||||
|
|
||||||
return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
|
return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
|
||||||
}
|
}
|
||||||
|
@ -1293,9 +1374,9 @@ public function getLanguages()
|
||||||
return $this->languages;
|
return $this->languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
$languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language'));
|
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
|
||||||
$this->languages = array();
|
$this->languages = array();
|
||||||
foreach ($languages as $lang => $q) {
|
foreach (array_keys($languages) as $lang) {
|
||||||
if (strstr($lang, '-')) {
|
if (strstr($lang, '-')) {
|
||||||
$codes = explode('-', $lang);
|
$codes = explode('-', $lang);
|
||||||
if ($codes[0] == 'i') {
|
if ($codes[0] == 'i') {
|
||||||
|
@ -1335,7 +1416,7 @@ public function getCharsets()
|
||||||
return $this->charsets;
|
return $this->charsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->charsets = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept-Charset')));
|
return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1351,14 +1432,15 @@ public function getAcceptableContentTypes()
|
||||||
return $this->acceptableContentTypes;
|
return $this->acceptableContentTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->acceptableContentTypes = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept')));
|
return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the request is a XMLHttpRequest.
|
* Returns true if the request is a XMLHttpRequest.
|
||||||
*
|
*
|
||||||
* It works if your JavaScript library set an X-Requested-With HTTP header.
|
* It works if your JavaScript library set an X-Requested-With HTTP header.
|
||||||
* It is known to work with Prototype, Mootools, jQuery.
|
* It is known to work with common JavaScript frameworks:
|
||||||
|
* @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
|
||||||
*
|
*
|
||||||
* @return Boolean true if the request is an XMLHttpRequest, false otherwise
|
* @return Boolean true if the request is an XMLHttpRequest, false otherwise
|
||||||
*
|
*
|
||||||
|
@ -1375,40 +1457,23 @@ public function isXmlHttpRequest()
|
||||||
* @param string $header Header to split
|
* @param string $header Header to split
|
||||||
*
|
*
|
||||||
* @return array Array indexed by the values of the Accept-* header in preferred order
|
* @return array Array indexed by the values of the Accept-* header in preferred order
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.2, to be removed in 2.3.
|
||||||
*/
|
*/
|
||||||
public function splitHttpAcceptHeader($header)
|
public function splitHttpAcceptHeader($header)
|
||||||
{
|
{
|
||||||
if (!$header) {
|
trigger_error('splitHttpAcceptHeader() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED);
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$values = array();
|
$headers = array();
|
||||||
$groups = array();
|
foreach (AcceptHeader::fromString($header)->all() as $item) {
|
||||||
foreach (array_filter(explode(',', $header)) as $value) {
|
$key = $item->getValue();
|
||||||
// Cut off any q-value that might come after a semi-colon
|
foreach ($item->getAttributes() as $name => $value) {
|
||||||
if (preg_match('/;\s*(q=.*$)/', $value, $match)) {
|
$key .= sprintf(';%s=%s', $name, $value);
|
||||||
$q = substr(trim($match[1]), 2);
|
|
||||||
$value = trim(substr($value, 0, -strlen($match[0])));
|
|
||||||
} else {
|
|
||||||
$q = 1;
|
|
||||||
}
|
}
|
||||||
|
$headers[$key] = $item->getQuality();
|
||||||
$groups[$q][] = $value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
krsort($groups);
|
return $headers;
|
||||||
|
|
||||||
foreach ($groups as $q => $items) {
|
|
||||||
$q = (float) $q;
|
|
||||||
|
|
||||||
if (0 < $q) {
|
|
||||||
foreach ($items as $value) {
|
|
||||||
$values[trim($value)] = $q;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1426,12 +1491,16 @@ protected function prepareRequestUri()
|
||||||
if ($this->headers->has('X_ORIGINAL_URL') && false !== stripos(PHP_OS, 'WIN')) {
|
if ($this->headers->has('X_ORIGINAL_URL') && false !== stripos(PHP_OS, 'WIN')) {
|
||||||
// IIS with Microsoft Rewrite Module
|
// IIS with Microsoft Rewrite Module
|
||||||
$requestUri = $this->headers->get('X_ORIGINAL_URL');
|
$requestUri = $this->headers->get('X_ORIGINAL_URL');
|
||||||
|
$this->headers->remove('X_ORIGINAL_URL');
|
||||||
} elseif ($this->headers->has('X_REWRITE_URL') && false !== stripos(PHP_OS, 'WIN')) {
|
} elseif ($this->headers->has('X_REWRITE_URL') && false !== stripos(PHP_OS, 'WIN')) {
|
||||||
// IIS with ISAPI_Rewrite
|
// IIS with ISAPI_Rewrite
|
||||||
$requestUri = $this->headers->get('X_REWRITE_URL');
|
$requestUri = $this->headers->get('X_REWRITE_URL');
|
||||||
|
$this->headers->remove('X_REWRITE_URL');
|
||||||
} elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
|
} elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
|
||||||
// IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
|
// IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
|
||||||
$requestUri = $this->server->get('UNENCODED_URL');
|
$requestUri = $this->server->get('UNENCODED_URL');
|
||||||
|
$this->server->remove('UNENCODED_URL');
|
||||||
|
$this->server->remove('IIS_WasUrlRewritten');
|
||||||
} elseif ($this->server->has('REQUEST_URI')) {
|
} elseif ($this->server->has('REQUEST_URI')) {
|
||||||
$requestUri = $this->server->get('REQUEST_URI');
|
$requestUri = $this->server->get('REQUEST_URI');
|
||||||
// HTTP proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
|
// HTTP proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
|
||||||
|
@ -1445,8 +1514,12 @@ protected function prepareRequestUri()
|
||||||
if ('' != $this->server->get('QUERY_STRING')) {
|
if ('' != $this->server->get('QUERY_STRING')) {
|
||||||
$requestUri .= '?'.$this->server->get('QUERY_STRING');
|
$requestUri .= '?'.$this->server->get('QUERY_STRING');
|
||||||
}
|
}
|
||||||
|
$this->server->remove('ORIG_PATH_INFO');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalize the request URI to ease creating sub-requests from this request
|
||||||
|
$this->server->set('REQUEST_URI', $requestUri);
|
||||||
|
|
||||||
return $requestUri;
|
return $requestUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,95 +143,10 @@ public function matches(Request $request)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $this->ip && !$this->checkIp($request->getClientIp(), $this->ip)) {
|
if (null !== $this->ip && !IpUtils::checkIp($request->getClientIp(), $this->ip)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates an IP address.
|
|
||||||
*
|
|
||||||
* @param string $requestIp
|
|
||||||
* @param string $ip
|
|
||||||
*
|
|
||||||
* @return boolean True valid, false if not.
|
|
||||||
*/
|
|
||||||
protected function checkIp($requestIp, $ip)
|
|
||||||
{
|
|
||||||
// IPv6 address
|
|
||||||
if (false !== strpos($requestIp, ':')) {
|
|
||||||
return $this->checkIp6($requestIp, $ip);
|
|
||||||
} else {
|
|
||||||
return $this->checkIp4($requestIp, $ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates an IPv4 address.
|
|
||||||
*
|
|
||||||
* @param string $requestIp
|
|
||||||
* @param string $ip
|
|
||||||
*
|
|
||||||
* @return boolean True valid, false if not.
|
|
||||||
*/
|
|
||||||
protected function checkIp4($requestIp, $ip)
|
|
||||||
{
|
|
||||||
if (false !== strpos($ip, '/')) {
|
|
||||||
list($address, $netmask) = explode('/', $ip, 2);
|
|
||||||
|
|
||||||
if ($netmask < 1 || $netmask > 32) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$address = $ip;
|
|
||||||
$netmask = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates an IPv6 address.
|
|
||||||
*
|
|
||||||
* @author David Soria Parra <dsp at php dot net>
|
|
||||||
* @see https://github.com/dsp/v6tools
|
|
||||||
*
|
|
||||||
* @param string $requestIp
|
|
||||||
* @param string $ip
|
|
||||||
*
|
|
||||||
* @return boolean True valid, false if not.
|
|
||||||
*/
|
|
||||||
protected function checkIp6($requestIp, $ip)
|
|
||||||
{
|
|
||||||
if (!((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".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== strpos($ip, '/')) {
|
|
||||||
list($address, $netmask) = explode('/', $ip, 2);
|
|
||||||
|
|
||||||
if ($netmask < 1 || $netmask > 128) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$address = $ip;
|
|
||||||
$netmask = 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytesAddr = unpack("n*", inet_pton($address));
|
|
||||||
$bytesTest = unpack("n*", inet_pton($requestIp));
|
|
||||||
|
|
||||||
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
|
|
||||||
$left = $netmask - 16 * ($i-1);
|
|
||||||
$left = ($left <= 16) ? $left : 16;
|
|
||||||
$mask = ~(0xffff >> $left) & 0xffff;
|
|
||||||
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,8 @@ class Response
|
||||||
* @param integer $status The response status code
|
* @param integer $status The response status code
|
||||||
* @param array $headers An array of response headers
|
* @param array $headers An array of response headers
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException When the HTTP status code is not valid
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function __construct($content = '', $status = 200, $headers = array())
|
public function __construct($content = '', $status = 200, $headers = array())
|
||||||
|
@ -231,7 +233,7 @@ public function prepare(Request $request)
|
||||||
$headers->remove('Content-Length');
|
$headers->remove('Content-Length');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('HEAD' === $request->getMethod()) {
|
if ($request->isMethod('HEAD')) {
|
||||||
// cf. RFC2616 14.13
|
// cf. RFC2616 14.13
|
||||||
$length = $headers->get('Content-Length');
|
$length = $headers->get('Content-Length');
|
||||||
$this->setContent(null);
|
$this->setContent(null);
|
||||||
|
@ -251,6 +253,16 @@ public function prepare(Request $request)
|
||||||
$this->headers->set('expires', -1);
|
$this->headers->set('expires', -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we need to remove Cache-Control for ssl encrypted downloads when using IE < 9
|
||||||
|
* @link http://support.microsoft.com/kb/323308
|
||||||
|
*/
|
||||||
|
if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) == 1 && true === $request->isSecure()) {
|
||||||
|
if (intval(preg_replace("/(MSIE )(.*?);/", "$2", $match[0])) < 9) {
|
||||||
|
$this->headers->remove('Cache-Control');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +282,7 @@ public function sendHeaders()
|
||||||
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
|
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
|
||||||
|
|
||||||
// headers
|
// headers
|
||||||
foreach ($this->headers->all() as $name => $values) {
|
foreach ($this->headers->allPreserveCase() as $name => $values) {
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
header($name.': '.$value, false);
|
header($name.': '.$value, false);
|
||||||
}
|
}
|
||||||
|
@ -336,6 +348,8 @@ public function send()
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*
|
*
|
||||||
|
* @throws \UnexpectedValueException
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function setContent($content)
|
public function setContent($content)
|
||||||
|
@ -431,7 +445,7 @@ public function setStatusCode($code, $text = null)
|
||||||
/**
|
/**
|
||||||
* Retrieves the status code for the current web response.
|
* Retrieves the status code for the current web response.
|
||||||
*
|
*
|
||||||
* @return string Status code
|
* @return integer Status code
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
@ -499,7 +513,7 @@ public function isCacheable()
|
||||||
*
|
*
|
||||||
* Fresh responses may be served from cache without any interaction with the
|
* Fresh responses may be served from cache without any interaction with the
|
||||||
* origin. A response is considered fresh when it includes a Cache-Control/max-age
|
* origin. A response is considered fresh when it includes a Cache-Control/max-age
|
||||||
* indicator or Expiration header and the calculated age is less than the freshness lifetime.
|
* indicator or Expires header and the calculated age is less than the freshness lifetime.
|
||||||
*
|
*
|
||||||
* @return Boolean true if the response is fresh, false otherwise
|
* @return Boolean true if the response is fresh, false otherwise
|
||||||
*
|
*
|
||||||
|
@ -612,8 +626,8 @@ public function setDate(\DateTime $date)
|
||||||
*/
|
*/
|
||||||
public function getAge()
|
public function getAge()
|
||||||
{
|
{
|
||||||
if ($age = $this->headers->get('Age')) {
|
if (null !== $age = $this->headers->get('Age')) {
|
||||||
return $age;
|
return (int) $age;
|
||||||
}
|
}
|
||||||
|
|
||||||
return max(time() - $this->getDate()->format('U'), 0);
|
return max(time() - $this->getDate()->format('U'), 0);
|
||||||
|
@ -638,21 +652,26 @@ public function expire()
|
||||||
/**
|
/**
|
||||||
* Returns the value of the Expires header as a DateTime instance.
|
* Returns the value of the Expires header as a DateTime instance.
|
||||||
*
|
*
|
||||||
* @return \DateTime A DateTime instance
|
* @return \DateTime|null A DateTime instance or null if the header does not exist
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function getExpires()
|
public function getExpires()
|
||||||
{
|
{
|
||||||
return $this->headers->getDate('Expires');
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the Expires HTTP header with a DateTime instance.
|
* Sets the Expires HTTP header with a DateTime instance.
|
||||||
*
|
*
|
||||||
* If passed a null value, it removes the header.
|
* Passing null as value will remove the header.
|
||||||
*
|
*
|
||||||
* @param \DateTime $date A \DateTime instance
|
* @param \DateTime|null $date A \DateTime instance or null to remove the header
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*
|
*
|
||||||
|
@ -672,7 +691,7 @@ public function setExpires(\DateTime $date = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of seconds after the time specified in the response's Date
|
* Returns the number of seconds after the time specified in the response's Date
|
||||||
* header when the the response should no longer be considered fresh.
|
* header when the the response should no longer be considered fresh.
|
||||||
*
|
*
|
||||||
* First, it checks for a s-maxage directive, then a max-age directive, and then it falls
|
* First, it checks for a s-maxage directive, then a max-age directive, and then it falls
|
||||||
|
@ -684,12 +703,12 @@ public function setExpires(\DateTime $date = null)
|
||||||
*/
|
*/
|
||||||
public function getMaxAge()
|
public function getMaxAge()
|
||||||
{
|
{
|
||||||
if ($age = $this->headers->getCacheControlDirective('s-maxage')) {
|
if ($this->headers->hasCacheControlDirective('s-maxage')) {
|
||||||
return $age;
|
return (int) $this->headers->getCacheControlDirective('s-maxage');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($age = $this->headers->getCacheControlDirective('max-age')) {
|
if ($this->headers->hasCacheControlDirective('max-age')) {
|
||||||
return $age;
|
return (int) $this->headers->getCacheControlDirective('max-age');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $this->getExpires()) {
|
if (null !== $this->getExpires()) {
|
||||||
|
@ -750,7 +769,7 @@ public function setSharedMaxAge($value)
|
||||||
*/
|
*/
|
||||||
public function getTtl()
|
public function getTtl()
|
||||||
{
|
{
|
||||||
if ($maxAge = $this->getMaxAge()) {
|
if (null !== $maxAge = $this->getMaxAge()) {
|
||||||
return $maxAge - $this->getAge();
|
return $maxAge - $this->getAge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,7 +815,9 @@ public function setClientTtl($seconds)
|
||||||
/**
|
/**
|
||||||
* Returns the Last-Modified HTTP header as a DateTime instance.
|
* Returns the Last-Modified HTTP header as a DateTime instance.
|
||||||
*
|
*
|
||||||
* @return \DateTime 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
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
@ -808,9 +829,9 @@ public function getLastModified()
|
||||||
/**
|
/**
|
||||||
* Sets the Last-Modified HTTP header with a DateTime instance.
|
* Sets the Last-Modified HTTP header with a DateTime instance.
|
||||||
*
|
*
|
||||||
* If passed a null value, it removes the header.
|
* Passing null as value will remove the header.
|
||||||
*
|
*
|
||||||
* @param \DateTime $date A \DateTime instance
|
* @param \DateTime|null $date A \DateTime instance or null to remove the header
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*
|
*
|
||||||
|
@ -832,7 +853,7 @@ public function setLastModified(\DateTime $date = null)
|
||||||
/**
|
/**
|
||||||
* Returns the literal value of the ETag HTTP header.
|
* Returns the literal value of the ETag HTTP header.
|
||||||
*
|
*
|
||||||
* @return string The ETag HTTP header
|
* @return string|null The ETag HTTP header or null if it does not exist
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
@ -844,8 +865,8 @@ public function getEtag()
|
||||||
/**
|
/**
|
||||||
* Sets the ETag value.
|
* Sets the ETag value.
|
||||||
*
|
*
|
||||||
* @param string $etag The ETag unique identifier
|
* @param string|null $etag The ETag unique identifier or null to remove the header
|
||||||
* @param Boolean $weak Whether you want a weak ETag or not
|
* @param Boolean $weak Whether you want a weak ETag or not
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*
|
*
|
||||||
|
@ -875,6 +896,8 @@ public function setEtag($etag = null, $weak = false)
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function setCache(array $options)
|
public function setCache(array $options)
|
||||||
|
@ -952,7 +975,7 @@ public function setNotModified()
|
||||||
*/
|
*/
|
||||||
public function hasVary()
|
public function hasVary()
|
||||||
{
|
{
|
||||||
return (Boolean) $this->headers->get('Vary');
|
return null !== $this->headers->get('Vary');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1108,7 +1131,7 @@ public function isOk()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the reponse forbidden?
|
* Is the response forbidden?
|
||||||
*
|
*
|
||||||
* @return Boolean
|
* @return Boolean
|
||||||
*
|
*
|
||||||
|
|
|
@ -36,6 +36,11 @@ class ResponseHeaderBag extends HeaderBag
|
||||||
*/
|
*/
|
||||||
protected $cookies = array();
|
protected $cookies = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $headerNames = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -48,7 +53,7 @@ public function __construct(array $headers = array())
|
||||||
parent::__construct($headers);
|
parent::__construct($headers);
|
||||||
|
|
||||||
if (!isset($this->headers['cache-control'])) {
|
if (!isset($this->headers['cache-control'])) {
|
||||||
$this->set('cache-control', '');
|
$this->set('Cache-Control', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +67,21 @@ public function __toString()
|
||||||
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
|
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ksort($this->headerNames);
|
||||||
|
|
||||||
return parent::__toString().$cookies;
|
return parent::__toString().$cookies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers, with original capitalizations.
|
||||||
|
*
|
||||||
|
* @return array An array of headers
|
||||||
|
*/
|
||||||
|
public function allPreserveCase()
|
||||||
|
{
|
||||||
|
return array_combine($this->headerNames, $this->headers);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
|
@ -72,10 +89,12 @@ public function __toString()
|
||||||
*/
|
*/
|
||||||
public function replace(array $headers = array())
|
public function replace(array $headers = array())
|
||||||
{
|
{
|
||||||
|
$this->headerNames = array();
|
||||||
|
|
||||||
parent::replace($headers);
|
parent::replace($headers);
|
||||||
|
|
||||||
if (!isset($this->headers['cache-control'])) {
|
if (!isset($this->headers['cache-control'])) {
|
||||||
$this->set('cache-control', '');
|
$this->set('Cache-Control', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,10 +107,14 @@ public function set($key, $values, $replace = true)
|
||||||
{
|
{
|
||||||
parent::set($key, $values, $replace);
|
parent::set($key, $values, $replace);
|
||||||
|
|
||||||
|
$uniqueKey = strtr(strtolower($key), '_', '-');
|
||||||
|
$this->headerNames[$uniqueKey] = $key;
|
||||||
|
|
||||||
// ensure the cache-control header has sensible defaults
|
// ensure the cache-control header has sensible defaults
|
||||||
if (in_array(strtr(strtolower($key), '_', '-'), array('cache-control', 'etag', 'last-modified', 'expires'))) {
|
if (in_array($uniqueKey, array('cache-control', 'etag', 'last-modified', 'expires'))) {
|
||||||
$computed = $this->computeCacheControlValue();
|
$computed = $this->computeCacheControlValue();
|
||||||
$this->headers['cache-control'] = array($computed);
|
$this->headers['cache-control'] = array($computed);
|
||||||
|
$this->headerNames['cache-control'] = 'Cache-Control';
|
||||||
$this->computedCacheControl = $this->parseCacheControl($computed);
|
$this->computedCacheControl = $this->parseCacheControl($computed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +128,10 @@ public function remove($key)
|
||||||
{
|
{
|
||||||
parent::remove($key);
|
parent::remove($key);
|
||||||
|
|
||||||
if ('cache-control' === strtr(strtolower($key), '_', '-')) {
|
$uniqueKey = strtr(strtolower($key), '_', '-');
|
||||||
|
unset($this->headerNames[$uniqueKey]);
|
||||||
|
|
||||||
|
if ('cache-control' === $uniqueKey) {
|
||||||
$this->computedCacheControl = array();
|
$this->computedCacheControl = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param string $storageKey The key used to store flashes in the session.
|
* @param string $storageKey The key used to store attributes in the session.
|
||||||
*/
|
*/
|
||||||
public function __construct($storageKey = '_sf2_attributes')
|
public function __construct($storageKey = '_sf2_attributes')
|
||||||
{
|
{
|
||||||
|
|
|
@ -177,10 +177,17 @@ public function getIterator()
|
||||||
/**
|
/**
|
||||||
* Returns the number of flashes.
|
* Returns the number of flashes.
|
||||||
*
|
*
|
||||||
|
* This method does not work.
|
||||||
|
*
|
||||||
|
* @deprecated in 2.2, removed in 2.3
|
||||||
|
* @see https://github.com/symfony/symfony/issues/6408
|
||||||
|
*
|
||||||
* @return int The number of flashes
|
* @return int The number of flashes
|
||||||
*/
|
*/
|
||||||
public function count()
|
public function count()
|
||||||
{
|
{
|
||||||
|
trigger_error(sprintf('%s() is deprecated since 2.2 and will be removed in 2.3', __METHOD__), E_USER_DEPRECATED);
|
||||||
|
|
||||||
return count($this->flashes);
|
return count($this->flashes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,8 @@ public function getFlashBag()
|
||||||
*/
|
*/
|
||||||
public function getFlashes()
|
public function getFlashes()
|
||||||
{
|
{
|
||||||
|
trigger_error('getFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
$all = $this->getBag($this->flashName)->all();
|
$all = $this->getBag($this->flashName)->all();
|
||||||
|
|
||||||
$return = array();
|
$return = array();
|
||||||
|
@ -282,6 +284,8 @@ public function getFlashes()
|
||||||
*/
|
*/
|
||||||
public function setFlashes($values)
|
public function setFlashes($values)
|
||||||
{
|
{
|
||||||
|
trigger_error('setFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
foreach ($values as $name => $value) {
|
foreach ($values as $name => $value) {
|
||||||
$this->getBag($this->flashName)->set($name, $value);
|
$this->getBag($this->flashName)->set($name, $value);
|
||||||
}
|
}
|
||||||
|
@ -297,6 +301,8 @@ public function setFlashes($values)
|
||||||
*/
|
*/
|
||||||
public function getFlash($name, $default = null)
|
public function getFlash($name, $default = null)
|
||||||
{
|
{
|
||||||
|
trigger_error('getFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
$return = $this->getBag($this->flashName)->get($name);
|
$return = $this->getBag($this->flashName)->get($name);
|
||||||
|
|
||||||
return empty($return) ? $default : reset($return);
|
return empty($return) ? $default : reset($return);
|
||||||
|
@ -310,6 +316,8 @@ public function getFlash($name, $default = null)
|
||||||
*/
|
*/
|
||||||
public function setFlash($name, $value)
|
public function setFlash($name, $value)
|
||||||
{
|
{
|
||||||
|
trigger_error('setFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
$this->getBag($this->flashName)->set($name, $value);
|
$this->getBag($this->flashName)->set($name, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +330,8 @@ public function setFlash($name, $value)
|
||||||
*/
|
*/
|
||||||
public function hasFlash($name)
|
public function hasFlash($name)
|
||||||
{
|
{
|
||||||
|
trigger_error('hasFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
return $this->getBag($this->flashName)->has($name);
|
return $this->getBag($this->flashName)->has($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +342,8 @@ public function hasFlash($name)
|
||||||
*/
|
*/
|
||||||
public function removeFlash($name)
|
public function removeFlash($name)
|
||||||
{
|
{
|
||||||
|
trigger_error('removeFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
$this->getBag($this->flashName)->get($name);
|
$this->getBag($this->flashName)->get($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +354,8 @@ public function removeFlash($name)
|
||||||
*/
|
*/
|
||||||
public function clearFlashes()
|
public function clearFlashes()
|
||||||
{
|
{
|
||||||
|
trigger_error('clearFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
return $this->getBag($this->flashName)->clear();
|
return $this->getBag($this->flashName)->clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,13 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
* List of available options:
|
||||||
|
* * database: The name of the database [required]
|
||||||
|
* * collection: The name of the collection [required]
|
||||||
|
* * id_field: The field name for storing the session id [default: _id]
|
||||||
|
* * data_field: The field name for storing the session data [default: data]
|
||||||
|
* * time_field: The field name for storing the timestamp [default: time]
|
||||||
|
*
|
||||||
* @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance
|
* @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance
|
||||||
* @param array $options An associative array of field options
|
* @param array $options An associative array of field options
|
||||||
*
|
*
|
||||||
|
@ -55,9 +62,9 @@ public function __construct($mongo, array $options)
|
||||||
$this->mongo = $mongo;
|
$this->mongo = $mongo;
|
||||||
|
|
||||||
$this->options = array_merge(array(
|
$this->options = array_merge(array(
|
||||||
'id_field' => 'sess_id',
|
'id_field' => '_id',
|
||||||
'data_field' => 'sess_data',
|
'data_field' => 'data',
|
||||||
'time_field' => 'sess_time',
|
'time_field' => 'time',
|
||||||
), $options);
|
), $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +89,9 @@ public function close()
|
||||||
*/
|
*/
|
||||||
public function destroy($sessionId)
|
public function destroy($sessionId)
|
||||||
{
|
{
|
||||||
$this->getCollection()->remove(
|
$this->getCollection()->remove(array(
|
||||||
array($this->options['id_field'] => $sessionId),
|
$this->options['id_field'] => $sessionId
|
||||||
array('justOne' => true)
|
));
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -95,11 +101,21 @@ public function destroy($sessionId)
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($lifetime)
|
||||||
{
|
{
|
||||||
$time = new \MongoTimestamp(time() - $lifetime);
|
/* Note: MongoDB 2.2+ supports TTL collections, which may be used in
|
||||||
|
* place of this method by indexing the "time_field" field with an
|
||||||
|
* "expireAfterSeconds" option. Regardless of whether TTL collections
|
||||||
|
* are used, consider indexing this field to make the remove query more
|
||||||
|
* efficient.
|
||||||
|
*
|
||||||
|
* See: http://docs.mongodb.org/manual/tutorial/expire-data/
|
||||||
|
*/
|
||||||
|
$time = new \MongoDate(time() - $lifetime);
|
||||||
|
|
||||||
$this->getCollection()->remove(array(
|
$this->getCollection()->remove(array(
|
||||||
$this->options['time_field'] => array('$lt' => $time),
|
$this->options['time_field'] => array('$lt' => $time),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,16 +123,13 @@ public function gc($lifetime)
|
||||||
*/
|
*/
|
||||||
public function write($sessionId, $data)
|
public function write($sessionId, $data)
|
||||||
{
|
{
|
||||||
$data = array(
|
|
||||||
$this->options['id_field'] => $sessionId,
|
|
||||||
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
|
|
||||||
$this->options['time_field'] => new \MongoTimestamp()
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->getCollection()->update(
|
$this->getCollection()->update(
|
||||||
array($this->options['id_field'] => $sessionId),
|
array($this->options['id_field'] => $sessionId),
|
||||||
array('$set' => $data),
|
array('$set' => array(
|
||||||
array('upsert' => true)
|
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
|
||||||
|
$this->options['time_field'] => new \MongoDate(),
|
||||||
|
)),
|
||||||
|
array('upsert' => true, 'multiple' => false)
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -27,17 +27,17 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||||
/**
|
/**
|
||||||
* Array of SessionBagInterface
|
* Array of SessionBagInterface
|
||||||
*
|
*
|
||||||
* @var array
|
* @var SessionBagInterface[]
|
||||||
*/
|
*/
|
||||||
protected $bags;
|
protected $bags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var boolean
|
* @var Boolean
|
||||||
*/
|
*/
|
||||||
protected $started = false;
|
protected $started = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var boolean
|
* @var Boolean
|
||||||
*/
|
*/
|
||||||
protected $closed = false;
|
protected $closed = false;
|
||||||
|
|
||||||
|
@ -332,9 +332,9 @@ public function setOptions(array $options)
|
||||||
* Registers save handler as a PHP session handler.
|
* Registers save handler as a PHP session handler.
|
||||||
*
|
*
|
||||||
* To use internal PHP session save handlers, override this method using ini_set with
|
* To use internal PHP session save handlers, override this method using ini_set with
|
||||||
* session.save_handlers and session.save_path e.g.
|
* session.save_handler and session.save_path e.g.
|
||||||
*
|
*
|
||||||
* ini_set('session.save_handlers', 'files');
|
* ini_set('session.save_handler', 'files');
|
||||||
* ini_set('session.save_path', /tmp');
|
* ini_set('session.save_path', /tmp');
|
||||||
*
|
*
|
||||||
* @see http://php.net/session-set-save-handler
|
* @see http://php.net/session-set-save-handler
|
||||||
|
|
|
@ -99,6 +99,8 @@ public function getId()
|
||||||
* Sets the session ID.
|
* Sets the session ID.
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
*/
|
*/
|
||||||
public function setId($id)
|
public function setId($id)
|
||||||
{
|
{
|
||||||
|
@ -123,6 +125,8 @@ public function getName()
|
||||||
* Sets the session name.
|
* Sets the session name.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
*/
|
*/
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,6 +62,8 @@ public static function create($callback = null, $status = 200, $headers = array(
|
||||||
* Sets the PHP callback associated with this Response.
|
* Sets the PHP callback associated with this Response.
|
||||||
*
|
*
|
||||||
* @param mixed $callback A valid PHP callback
|
* @param mixed $callback A valid PHP callback
|
||||||
|
*
|
||||||
|
* @throws \LogicException
|
||||||
*/
|
*/
|
||||||
public function setCallback($callback)
|
public function setCallback($callback)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,11 +19,14 @@
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.3"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-0": { "Symfony\\Component\\HttpFoundation\\": "" },
|
||||||
"Symfony\\Component\\HttpFoundation": "",
|
"classmap": [ "Symfony/Component/HttpFoundation/Resources/stubs" ]
|
||||||
"SessionHandlerInterface": "Symfony/Component/HttpFoundation/Resources/stubs"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"target-dir": "Symfony/Component/HttpFoundation",
|
"target-dir": "Symfony/Component/HttpFoundation",
|
||||||
"minimum-stability": "dev"
|
"minimum-stability": "dev",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.2-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnFailure="false"
|
||||||
|
syntaxCheck="false"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Symfony HttpFoundation Component Test Suite">
|
||||||
|
<directory>./Tests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory>./</directory>
|
||||||
|
<exclude>
|
||||||
|
<directory>./Resources</directory>
|
||||||
|
<directory>./Tests</directory>
|
||||||
|
<directory>./vendor</directory>
|
||||||
|
</exclude>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
Loading…
Reference in New Issue