git-svn-id: https://msi/svn/firstRepo/Service/branches/Slim3@39 0f545695-f87b-41b6-9a03-7f16563b5454
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* Slim Framework (http://slimframework.com)
|
||||
*
|
||||
* @link https://github.com/slimphp/Slim
|
||||
* @copyright Copyright (c) 2011-2015 Josh Lockhart
|
||||
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
|
||||
*/
|
||||
namespace Slim\Http;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Slim\Interfaces\Http\CookiesInterface;
|
||||
|
||||
/**
|
||||
* Cookie helper
|
||||
*/
|
||||
class Cookies implements CookiesInterface
|
||||
{
|
||||
/**
|
||||
* Cookies from HTTP request
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requestCookies = [];
|
||||
|
||||
/**
|
||||
* Cookies for HTTP response
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $responseCookies = [];
|
||||
|
||||
/**
|
||||
* Default cookie properties
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaults = [
|
||||
'value' => '',
|
||||
'domain' => null,
|
||||
'path' => null,
|
||||
'expires' => null,
|
||||
'secure' => false,
|
||||
'httponly' => false
|
||||
];
|
||||
|
||||
/**
|
||||
* Create new cookies helper
|
||||
*
|
||||
* @param array $cookies
|
||||
*/
|
||||
public function __construct(array $cookies = [])
|
||||
{
|
||||
$this->requestCookies = $cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default cookie properties
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function setDefaults(array $settings)
|
||||
{
|
||||
$this->defaults = array_replace($this->defaults, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request cookie
|
||||
*
|
||||
* @param string $name Cookie name
|
||||
* @param mixed $default Cookie default value
|
||||
*
|
||||
* @return mixed Cookie value if present, else default
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
{
|
||||
return isset($this->requestCookies[$name]) ? $this->requestCookies[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set response cookie
|
||||
*
|
||||
* @param string $name Cookie name
|
||||
* @param string|array $value Cookie value, or cookie properties
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$value = ['value' => (string)$value];
|
||||
}
|
||||
$this->responseCookies[$name] = array_replace($this->defaults, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to `Set-Cookie` headers
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function toHeaders()
|
||||
{
|
||||
$headers = [];
|
||||
foreach ($this->responseCookies as $name => $properties) {
|
||||
$headers[] = $this->toHeader($name, $properties);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to `Set-Cookie` header
|
||||
*
|
||||
* @param string $name Cookie name
|
||||
* @param array $properties Cookie properties
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function toHeader($name, array $properties)
|
||||
{
|
||||
$result = urlencode($name) . '=' . urlencode($properties['value']);
|
||||
|
||||
if (isset($properties['domain'])) {
|
||||
$result .= '; domain=' . $properties['domain'];
|
||||
}
|
||||
|
||||
if (isset($properties['path'])) {
|
||||
$result .= '; path=' . $properties['path'];
|
||||
}
|
||||
|
||||
if (isset($properties['expires'])) {
|
||||
if (is_string($properties['expires'])) {
|
||||
$timestamp = strtotime($properties['expires']);
|
||||
} else {
|
||||
$timestamp = (int)$properties['expires'];
|
||||
}
|
||||
if ($timestamp !== 0) {
|
||||
$result .= '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($properties['secure']) && $properties['secure']) {
|
||||
$result .= '; secure';
|
||||
}
|
||||
|
||||
if (isset($properties['httponly']) && $properties['httponly']) {
|
||||
$result .= '; HttpOnly';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse HTTP request `Cookie:` header and extract
|
||||
* into a PHP associative array.
|
||||
*
|
||||
* @param string $header The raw HTTP request `Cookie:` header
|
||||
*
|
||||
* @return array Associative array of cookie names and values
|
||||
*
|
||||
* @throws InvalidArgumentException if the cookie data cannot be parsed
|
||||
*/
|
||||
public static function parseHeader($header)
|
||||
{
|
||||
if (is_array($header) === true) {
|
||||
$header = isset($header[0]) ? $header[0] : '';
|
||||
}
|
||||
|
||||
if (is_string($header) === false) {
|
||||
throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.');
|
||||
}
|
||||
|
||||
$header = rtrim($header, "\r\n");
|
||||
$pieces = preg_split('@\s*[;,]\s*@', $header);
|
||||
$cookies = [];
|
||||
|
||||
foreach ($pieces as $cookie) {
|
||||
$cookie = explode('=', $cookie, 2);
|
||||
|
||||
if (count($cookie) === 2) {
|
||||
$key = urldecode($cookie[0]);
|
||||
$value = urldecode($cookie[1]);
|
||||
|
||||
if (!isset($cookies[$key])) {
|
||||
$cookies[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cookies;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* Slim Framework (http://slimframework.com)
|
||||
*
|
||||
* @link https://github.com/slimphp/Slim
|
||||
* @copyright Copyright (c) 2011-2015 Josh Lockhart
|
||||
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
|
||||
*/
|
||||
namespace Slim\Http;
|
||||
|
||||
use Slim\Collection;
|
||||
use Slim\Interfaces\Http\HeadersInterface;
|
||||
|
||||
/**
|
||||
* Headers
|
||||
*
|
||||
* This class represents a collection of HTTP headers
|
||||
* that is used in both the HTTP request and response objects.
|
||||
* It also enables header name case-insensitivity when
|
||||
* getting or setting a header value.
|
||||
*
|
||||
* Each HTTP header can have multiple values. This class
|
||||
* stores values into an array for each header name. When
|
||||
* you request a header value, you receive an array of values
|
||||
* for that header.
|
||||
*/
|
||||
class Headers extends Collection implements HeadersInterface
|
||||
{
|
||||
/**
|
||||
* Special HTTP headers that do not have the "HTTP_" prefix
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $special = [
|
||||
'CONTENT_TYPE' => 1,
|
||||
'CONTENT_LENGTH' => 1,
|
||||
'PHP_AUTH_USER' => 1,
|
||||
'PHP_AUTH_PW' => 1,
|
||||
'PHP_AUTH_DIGEST' => 1,
|
||||
'AUTH_TYPE' => 1,
|
||||
];
|
||||
|
||||
/**
|
||||
* Create new headers collection with data extracted from
|
||||
* the application Environment object
|
||||
*
|
||||
* @param Environment $environment The Slim application Environment
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function createFromEnvironment(Environment $environment)
|
||||
{
|
||||
$data = [];
|
||||
foreach ($environment as $key => $value) {
|
||||
$key = strtoupper($key);
|
||||
if (isset(static::$special[$key]) || strpos($key, 'HTTP_') === 0) {
|
||||
if ($key !== 'HTTP_CONTENT_LENGTH') {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new static($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of HTTP header names and values.
|
||||
* This method returns the _original_ header name
|
||||
* as specified by the end user.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
$all = parent::all();
|
||||
$out = [];
|
||||
foreach ($all as $key => $props) {
|
||||
$out[$props['originalKey']] = $props['value'];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP header value
|
||||
*
|
||||
* This method sets a header value. It replaces
|
||||
* any values that may already exist for the header name.
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
* @param string $value The header value
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
parent::set($this->normalizeKey($key), [
|
||||
'value' => $value,
|
||||
'originalKey' => $key
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTTP header value
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
* @param mixed $default The default value if key does not exist
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
if ($this->has($key)) {
|
||||
return parent::get($this->normalizeKey($key))['value'];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTTP header key as originally specified
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
* @param mixed $default The default value if key does not exist
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOriginalKey($key, $default = null)
|
||||
{
|
||||
if ($this->has($key)) {
|
||||
return parent::get($this->normalizeKey($key))['originalKey'];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add HTTP header value
|
||||
*
|
||||
* This method appends a header value. Unlike the set() method,
|
||||
* this method _appends_ this new value to any values
|
||||
* that already exist for this header name.
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
* @param array|string $value The new header value(s)
|
||||
*/
|
||||
public function add($key, $value)
|
||||
{
|
||||
$oldValues = $this->get($key, []);
|
||||
$newValues = is_array($value) ? $value : [$value];
|
||||
$this->set($key, array_merge($oldValues, array_values($newValues)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this collection have a given header?
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return parent::has($this->normalizeKey($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove header from collection
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
parent::remove($this->normalizeKey($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize header name
|
||||
*
|
||||
* This method transforms header names into a
|
||||
* normalized form. This is how we enable case-insensitive
|
||||
* header names in the other methods in this class.
|
||||
*
|
||||
* @param string $key The case-insensitive header name
|
||||
*
|
||||
* @return string Normalized header name
|
||||
*/
|
||||
public function normalizeKey($key)
|
||||
{
|
||||
$key = strtr(strtolower($key), '_', '-');
|
||||
if (strpos($key, 'http-') === 0) {
|
||||
$key = substr($key, 5);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,450 @@
|
||||
<?php
|
||||
/**
|
||||
* Slim Framework (http://slimframework.com)
|
||||
*
|
||||
* @link https://github.com/slimphp/Slim
|
||||
* @copyright Copyright (c) 2011-2015 Josh Lockhart
|
||||
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
|
||||
*/
|
||||
namespace Slim\Http;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Slim\Interfaces\Http\HeadersInterface;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*
|
||||
* This class represents an HTTP response. It manages
|
||||
* the response status, headers, and body
|
||||
* according to the PSR-7 standard.
|
||||
*
|
||||
* @link https://github.com/php-fig/http-message/blob/master/src/MessageInterface.php
|
||||
* @link https://github.com/php-fig/http-message/blob/master/src/ResponseInterface.php
|
||||
*/
|
||||
class Response extends Message implements ResponseInterface
|
||||
{
|
||||
/**
|
||||
* Status code
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $status = 200;
|
||||
|
||||
/**
|
||||
* Reason phrase
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $reasonPhrase = '';
|
||||
|
||||
/**
|
||||
* Status codes and reason phrases
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $messages = [
|
||||
//Informational 1xx
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
102 => 'Processing',
|
||||
//Successful 2xx
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
207 => 'Multi-Status',
|
||||
208 => 'Already Reported',
|
||||
226 => 'IM Used',
|
||||
//Redirection 3xx
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
306 => '(Unused)',
|
||||
307 => 'Temporary Redirect',
|
||||
308 => 'Permanent Redirect',
|
||||
//Client Error 4xx
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot',
|
||||
422 => 'Unprocessable Entity',
|
||||
423 => 'Locked',
|
||||
424 => 'Failed Dependency',
|
||||
426 => 'Upgrade Required',
|
||||
428 => 'Precondition Required',
|
||||
429 => 'Too Many Requests',
|
||||
431 => 'Request Header Fields Too Large',
|
||||
//Server Error 5xx
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported',
|
||||
506 => 'Variant Also Negotiates',
|
||||
507 => 'Insufficient Storage',
|
||||
508 => 'Loop Detected',
|
||||
510 => 'Not Extended',
|
||||
511 => 'Network Authentication Required',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create new HTTP response.
|
||||
*
|
||||
* @param int $status The response status code.
|
||||
* @param HeadersInterface|null $headers The response headers.
|
||||
* @param StreamInterface|null $body The response body.
|
||||
*/
|
||||
public function __construct($status = 200, HeadersInterface $headers = null, StreamInterface $body = null)
|
||||
{
|
||||
$this->status = $this->filterStatus($status);
|
||||
$this->headers = $headers ? $headers : new Headers();
|
||||
$this->body = $body ? $body : new Body(fopen('php://temp', 'r+'));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is applied to the cloned object
|
||||
* after PHP performs an initial shallow-copy. This
|
||||
* method completes a deep-copy by creating new objects
|
||||
* for the cloned object's internal reference pointers.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->headers = clone $this->headers;
|
||||
$this->body = clone $this->body;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Status
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Gets the response status code.
|
||||
*
|
||||
* The status code is a 3-digit integer result code of the server's attempt
|
||||
* to understand and satisfy the request.
|
||||
*
|
||||
* @return int Status code.
|
||||
*/
|
||||
public function getStatusCode()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the specified status code and, optionally, reason phrase.
|
||||
*
|
||||
* If no reason phrase is specified, implementations MAY choose to default
|
||||
* to the RFC 7231 or IANA recommended reason phrase for the response's
|
||||
* status code.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* updated status and reason phrase.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7231#section-6
|
||||
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
* @param int $code The 3-digit integer result code to set.
|
||||
* @param string $reasonPhrase The reason phrase to use with the
|
||||
* provided status code; if none is provided, implementations MAY
|
||||
* use the defaults as suggested in the HTTP specification.
|
||||
* @return self
|
||||
* @throws \InvalidArgumentException For invalid status code arguments.
|
||||
*/
|
||||
public function withStatus($code, $reasonPhrase = '')
|
||||
{
|
||||
$code = $this->filterStatus($code);
|
||||
|
||||
if (!is_string($reasonPhrase) && !method_exists($reasonPhrase, '__toString')) {
|
||||
throw new InvalidArgumentException('ReasonPhrase must be a string');
|
||||
}
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->status = $code;
|
||||
if ($reasonPhrase === '' && isset(static::$messages[$code])) {
|
||||
$reasonPhrase = static::$messages[$code];
|
||||
}
|
||||
|
||||
if ($reasonPhrase === '') {
|
||||
throw new InvalidArgumentException('ReasonPhrase must be supplied for this code');
|
||||
}
|
||||
|
||||
$clone->reasonPhrase = $reasonPhrase;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter HTTP status code.
|
||||
*
|
||||
* @param int $status HTTP status code.
|
||||
* @return int
|
||||
* @throws \InvalidArgumentException If an invalid HTTP status code is provided.
|
||||
*/
|
||||
protected function filterStatus($status)
|
||||
{
|
||||
if (!is_integer($status) || $status<100 || $status>599) {
|
||||
throw new InvalidArgumentException('Invalid HTTP status code');
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response reason phrase associated with the status code.
|
||||
*
|
||||
* Because a reason phrase is not a required element in a response
|
||||
* status line, the reason phrase value MAY be null. Implementations MAY
|
||||
* choose to return the default RFC 7231 recommended reason phrase (or those
|
||||
* listed in the IANA HTTP Status Code Registry) for the response's
|
||||
* status code.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7231#section-6
|
||||
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||
* @return string Reason phrase; must return an empty string if none present.
|
||||
*/
|
||||
public function getReasonPhrase()
|
||||
{
|
||||
if ($this->reasonPhrase) {
|
||||
return $this->reasonPhrase;
|
||||
}
|
||||
if (isset(static::$messages[$this->status])) {
|
||||
return static::$messages[$this->status];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Body
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Write data to the response body.
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* Proxies to the underlying stream and writes the provided data to it.
|
||||
*
|
||||
* @param string $data
|
||||
* @return self
|
||||
*/
|
||||
public function write($data)
|
||||
{
|
||||
$this->getBody()->write($data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Response Helpers
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Redirect.
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* This method prepares the response object to return an HTTP Redirect
|
||||
* response to the client.
|
||||
*
|
||||
* @param string|UriInterface $url The redirect destination.
|
||||
* @param int $status The redirect HTTP status code.
|
||||
* @return self
|
||||
*/
|
||||
public function withRedirect($url, $status = 302)
|
||||
{
|
||||
return $this->withStatus($status)->withHeader('Location', (string)$url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Json.
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* This method prepares the response object to return an HTTP Json
|
||||
* response to the client.
|
||||
*
|
||||
* @param mixed $data The data
|
||||
* @param int $status The HTTP status code.
|
||||
* @param int $encodingOptions Json encoding options
|
||||
* @return self
|
||||
*/
|
||||
public function withJson($data, $status = 200, $encodingOptions = 0)
|
||||
{
|
||||
$body = $this->getBody();
|
||||
$body->rewind();
|
||||
$body->write(json_encode($data, $encodingOptions));
|
||||
|
||||
return $this->withStatus($status)->withHeader('Content-Type', 'application/json;charset=utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response empty?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return in_array($this->getStatusCode(), [204, 205, 304]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response informational?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInformational()
|
||||
{
|
||||
return $this->getStatusCode() >= 100 && $this->getStatusCode() < 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response OK?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOk()
|
||||
{
|
||||
return $this->getStatusCode() === 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response successful?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuccessful()
|
||||
{
|
||||
return $this->getStatusCode() >= 200 && $this->getStatusCode() < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response a redirect?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRedirect()
|
||||
{
|
||||
return in_array($this->getStatusCode(), [301, 302, 303, 307]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response a redirection?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRedirection()
|
||||
{
|
||||
return $this->getStatusCode() >= 300 && $this->getStatusCode() < 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response forbidden?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
* @api
|
||||
*/
|
||||
public function isForbidden()
|
||||
{
|
||||
return $this->getStatusCode() === 403;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response not Found?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isNotFound()
|
||||
{
|
||||
return $this->getStatusCode() === 404;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response a client error?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClientError()
|
||||
{
|
||||
return $this->getStatusCode() >= 400 && $this->getStatusCode() < 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this response a server error?
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isServerError()
|
||||
{
|
||||
return $this->getStatusCode() >= 500 && $this->getStatusCode() < 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert response to string.
|
||||
*
|
||||
* Note: This method is not part of the PSR-7 standard.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$output = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$this->getProtocolVersion(),
|
||||
$this->getStatusCode(),
|
||||
$this->getReasonPhrase()
|
||||
);
|
||||
$output .= PHP_EOL;
|
||||
foreach ($this->getHeaders() as $name => $values) {
|
||||
$output .= sprintf('%s: %s', $name, $this->getHeaderLine($name)) . PHP_EOL;
|
||||
}
|
||||
$output .= PHP_EOL;
|
||||
$output .= (string)$this->getBody();
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
/**
|
||||
* Slim - a micro PHP 5 framework
|
||||
*
|
||||
* @author Josh Lockhart <[email protected]>
|
||||
* @copyright 2011 Josh Lockhart
|
||||
* @link http://www.slimframework.com
|
||||
* @license http://www.slimframework.com/license
|
||||
* @version 2.4.2
|
||||
* @package Slim
|
||||
*
|
||||
* MIT LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
namespace Slim\Http;
|
||||
|
||||
/**
|
||||
* Slim HTTP Utilities
|
||||
*
|
||||
* This class provides useful methods for handling HTTP requests.
|
||||
*
|
||||
* @package Slim
|
||||
* @author Josh Lockhart
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* Strip slashes from string or array
|
||||
*
|
||||
* This method strips slashes from its input. By default, this method will only
|
||||
* strip slashes from its input if magic quotes are enabled. Otherwise, you may
|
||||
* override the magic quotes setting with either TRUE or FALSE as the send argument
|
||||
* to force this method to strip or not strip slashes from its input.
|
||||
*
|
||||
* @param array|string $rawData
|
||||
* @param bool $overrideStripSlashes
|
||||
* @return array|string
|
||||
*/
|
||||
public static function stripSlashesIfMagicQuotes($rawData, $overrideStripSlashes = null)
|
||||
{
|
||||
$strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes;
|
||||
if ($strip) {
|
||||
return self::stripSlashes($rawData);
|
||||
} else {
|
||||
return $rawData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip slashes from string or array
|
||||
* @param array|string $rawData
|
||||
* @return array|string
|
||||
*/
|
||||
protected static function stripSlashes($rawData)
|
||||
{
|
||||
return is_array($rawData) ? array_map(array('self', 'stripSlashes'), $rawData) : stripslashes($rawData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data
|
||||
*
|
||||
* This method will encrypt data using a given key, vector, and cipher.
|
||||
* By default, this will encrypt data using the RIJNDAEL/AES 256 bit cipher. You
|
||||
* may override the default cipher and cipher mode by passing your own desired
|
||||
* cipher and cipher mode as the final key-value array argument.
|
||||
*
|
||||
* @param string $data The unencrypted data
|
||||
* @param string $key The encryption key
|
||||
* @param string $iv The encryption initialization vector
|
||||
* @param array $settings Optional key-value array with custom algorithm and mode
|
||||
* @return string
|
||||
*/
|
||||
public static function encrypt($data, $key, $iv, $settings = array())
|
||||
{
|
||||
if ($data === '' || !extension_loaded('mcrypt')) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
//Merge settings with defaults
|
||||
$defaults = array(
|
||||
'algorithm' => MCRYPT_RIJNDAEL_256,
|
||||
'mode' => MCRYPT_MODE_CBC
|
||||
);
|
||||
$settings = array_merge($defaults, $settings);
|
||||
|
||||
//Get module
|
||||
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
|
||||
|
||||
//Validate IV
|
||||
$ivSize = mcrypt_enc_get_iv_size($module);
|
||||
if (strlen($iv) > $ivSize) {
|
||||
$iv = substr($iv, 0, $ivSize);
|
||||
}
|
||||
|
||||
//Validate key
|
||||
$keySize = mcrypt_enc_get_key_size($module);
|
||||
if (strlen($key) > $keySize) {
|
||||
$key = substr($key, 0, $keySize);
|
||||
}
|
||||
|
||||
//Encrypt value
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$res = @mcrypt_generic($module, $data);
|
||||
mcrypt_generic_deinit($module);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data
|
||||
*
|
||||
* This method will decrypt data using a given key, vector, and cipher.
|
||||
* By default, this will decrypt data using the RIJNDAEL/AES 256 bit cipher. You
|
||||
* may override the default cipher and cipher mode by passing your own desired
|
||||
* cipher and cipher mode as the final key-value array argument.
|
||||
*
|
||||
* @param string $data The encrypted data
|
||||
* @param string $key The encryption key
|
||||
* @param string $iv The encryption initialization vector
|
||||
* @param array $settings Optional key-value array with custom algorithm and mode
|
||||
* @return string
|
||||
*/
|
||||
public static function decrypt($data, $key, $iv, $settings = array())
|
||||
{
|
||||
if ($data === '' || !extension_loaded('mcrypt')) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
//Merge settings with defaults
|
||||
$defaults = array(
|
||||
'algorithm' => MCRYPT_RIJNDAEL_256,
|
||||
'mode' => MCRYPT_MODE_CBC
|
||||
);
|
||||
$settings = array_merge($defaults, $settings);
|
||||
|
||||
//Get module
|
||||
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
|
||||
|
||||
//Validate IV
|
||||
$ivSize = mcrypt_enc_get_iv_size($module);
|
||||
if (strlen($iv) > $ivSize) {
|
||||
$iv = substr($iv, 0, $ivSize);
|
||||
}
|
||||
|
||||
//Validate key
|
||||
$keySize = mcrypt_enc_get_key_size($module);
|
||||
if (strlen($key) > $keySize) {
|
||||
$key = substr($key, 0, $keySize);
|
||||
}
|
||||
|
||||
//Decrypt value
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$decryptedData = @mdecrypt_generic($module, $data);
|
||||
$res = rtrim($decryptedData, "\0");
|
||||
mcrypt_generic_deinit($module);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize Response cookies into raw HTTP header
|
||||
* @param \Slim\Http\Headers $headers The Response headers
|
||||
* @param \Slim\Http\Cookies $cookies The Response cookies
|
||||
* @param array $config The Slim app settings
|
||||
*/
|
||||
public static function serializeCookies(\Slim\Http\Headers &$headers, \Slim\Http\Cookies $cookies, array $config)
|
||||
{
|
||||
if ($config['cookies.encrypt']) {
|
||||
foreach ($cookies as $name => $settings) {
|
||||
if (is_string($settings['expires'])) {
|
||||
$expires = strtotime($settings['expires']);
|
||||
} else {
|
||||
$expires = (int) $settings['expires'];
|
||||
}
|
||||
|
||||
$settings['value'] = static::encodeSecureCookie(
|
||||
$settings['value'],
|
||||
$expires,
|
||||
$config['cookies.secret_key'],
|
||||
$config['cookies.cipher'],
|
||||
$config['cookies.cipher_mode']
|
||||
);
|
||||
static::setCookieHeader($headers, $name, $settings);
|
||||
}
|
||||
} else {
|
||||
foreach ($cookies as $name => $settings) {
|
||||
static::setCookieHeader($headers, $name, $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode secure cookie value
|
||||
*
|
||||
* This method will create the secure value of an HTTP cookie. The
|
||||
* cookie value is encrypted and hashed so that its value is
|
||||
* secure and checked for integrity when read in subsequent requests.
|
||||
*
|
||||
* @param string $value The insecure HTTP cookie value
|
||||
* @param int $expires The UNIX timestamp at which this cookie will expire
|
||||
* @param string $secret The secret key used to hash the cookie value
|
||||
* @param int $algorithm The algorithm to use for encryption
|
||||
* @param int $mode The algorithm mode to use for encryption
|
||||
* @return string
|
||||
*/
|
||||
public static function encodeSecureCookie($value, $expires, $secret, $algorithm, $mode)
|
||||
{
|
||||
$key = hash_hmac('sha1', (string) $expires, $secret);
|
||||
$iv = self::getIv($expires, $secret);
|
||||
$secureString = base64_encode(
|
||||
self::encrypt(
|
||||
$value,
|
||||
$key,
|
||||
$iv,
|
||||
array(
|
||||
'algorithm' => $algorithm,
|
||||
'mode' => $mode
|
||||
)
|
||||
)
|
||||
);
|
||||
$verificationString = hash_hmac('sha1', $expires . $value, $key);
|
||||
|
||||
return implode('|', array($expires, $secureString, $verificationString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode secure cookie value
|
||||
*
|
||||
* This method will decode the secure value of an HTTP cookie. The
|
||||
* cookie value is encrypted and hashed so that its value is
|
||||
* secure and checked for integrity when read in subsequent requests.
|
||||
*
|
||||
* @param string $value The secure HTTP cookie value
|
||||
* @param string $secret The secret key used to hash the cookie value
|
||||
* @param int $algorithm The algorithm to use for encryption
|
||||
* @param int $mode The algorithm mode to use for encryption
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function decodeSecureCookie($value, $secret, $algorithm, $mode)
|
||||
{
|
||||
if ($value) {
|
||||
$value = explode('|', $value);
|
||||
if (count($value) === 3 && ((int) $value[0] === 0 || (int) $value[0] > time())) {
|
||||
$key = hash_hmac('sha1', $value[0], $secret);
|
||||
$iv = self::getIv($value[0], $secret);
|
||||
$data = self::decrypt(
|
||||
base64_decode($value[1]),
|
||||
$key,
|
||||
$iv,
|
||||
array(
|
||||
'algorithm' => $algorithm,
|
||||
'mode' => $mode
|
||||
)
|
||||
);
|
||||
$verificationString = hash_hmac('sha1', $value[0] . $data, $key);
|
||||
if ($verificationString === $value[2]) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP cookie header
|
||||
*
|
||||
* This method will construct and set the HTTP `Set-Cookie` header. Slim
|
||||
* uses this method instead of PHP's native `setcookie` method. This allows
|
||||
* more control of the HTTP header irrespective of the native implementation's
|
||||
* dependency on PHP versions.
|
||||
*
|
||||
* This method accepts the Slim_Http_Headers object by reference as its
|
||||
* first argument; this method directly modifies this object instead of
|
||||
* returning a value.
|
||||
*
|
||||
* @param array $header
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public static function setCookieHeader(&$header, $name, $value)
|
||||
{
|
||||
//Build cookie header
|
||||
if (is_array($value)) {
|
||||
$domain = '';
|
||||
$path = '';
|
||||
$expires = '';
|
||||
$secure = '';
|
||||
$httponly = '';
|
||||
if (isset($value['domain']) && $value['domain']) {
|
||||
$domain = '; domain=' . $value['domain'];
|
||||
}
|
||||
if (isset($value['path']) && $value['path']) {
|
||||
$path = '; path=' . $value['path'];
|
||||
}
|
||||
if (isset($value['expires'])) {
|
||||
if (is_string($value['expires'])) {
|
||||
$timestamp = strtotime($value['expires']);
|
||||
} else {
|
||||
$timestamp = (int) $value['expires'];
|
||||
}
|
||||
if ($timestamp !== 0) {
|
||||
$expires = '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);
|
||||
}
|
||||
}
|
||||
if (isset($value['secure']) && $value['secure']) {
|
||||
$secure = '; secure';
|
||||
}
|
||||
if (isset($value['httponly']) && $value['httponly']) {
|
||||
$httponly = '; HttpOnly';
|
||||
}
|
||||
$cookie = sprintf('%s=%s%s', urlencode($name), urlencode((string) $value['value']), $domain . $path . $expires . $secure . $httponly);
|
||||
} else {
|
||||
$cookie = sprintf('%s=%s', urlencode($name), urlencode((string) $value));
|
||||
}
|
||||
|
||||
//Set cookie header
|
||||
if (!isset($header['Set-Cookie']) || $header['Set-Cookie'] === '') {
|
||||
$header['Set-Cookie'] = $cookie;
|
||||
} else {
|
||||
$header['Set-Cookie'] = implode("\n", array($header['Set-Cookie'], $cookie));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete HTTP cookie header
|
||||
*
|
||||
* This method will construct and set the HTTP `Set-Cookie` header to invalidate
|
||||
* a client-side HTTP cookie. If a cookie with the same name (and, optionally, domain)
|
||||
* is already set in the HTTP response, it will also be removed. Slim uses this method
|
||||
* instead of PHP's native `setcookie` method. This allows more control of the HTTP header
|
||||
* irrespective of PHP's native implementation's dependency on PHP versions.
|
||||
*
|
||||
* This method accepts the Slim_Http_Headers object by reference as its
|
||||
* first argument; this method directly modifies this object instead of
|
||||
* returning a value.
|
||||
*
|
||||
* @param array $header
|
||||
* @param string $name
|
||||
* @param array $value
|
||||
*/
|
||||
public static function deleteCookieHeader(&$header, $name, $value = array())
|
||||
{
|
||||
//Remove affected cookies from current response header
|
||||
$cookiesOld = array();
|
||||
$cookiesNew = array();
|
||||
if (isset($header['Set-Cookie'])) {
|
||||
$cookiesOld = explode("\n", $header['Set-Cookie']);
|
||||
}
|
||||
foreach ($cookiesOld as $c) {
|
||||
if (isset($value['domain']) && $value['domain']) {
|
||||
$regex = sprintf('@%s=.*domain=%s@', urlencode($name), preg_quote($value['domain']));
|
||||
} else {
|
||||
$regex = sprintf('@%s=@', urlencode($name));
|
||||
}
|
||||
if (preg_match($regex, $c) === 0) {
|
||||
$cookiesNew[] = $c;
|
||||
}
|
||||
}
|
||||
if ($cookiesNew) {
|
||||
$header['Set-Cookie'] = implode("\n", $cookiesNew);
|
||||
} else {
|
||||
unset($header['Set-Cookie']);
|
||||
}
|
||||
|
||||
//Set invalidating cookie to clear client-side cookie
|
||||
self::setCookieHeader($header, $name, array_merge(array('value' => '', 'path' => null, 'domain' => null, 'expires' => time() - 100), $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse cookie header
|
||||
*
|
||||
* This method will parse the HTTP request's `Cookie` header
|
||||
* and extract cookies into an associative array.
|
||||
*
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public static function parseCookieHeader($header)
|
||||
{
|
||||
$cookies = array();
|
||||
$header = rtrim($header, "\r\n");
|
||||
$headerPieces = preg_split('@\s*[;,]\s*@', $header);
|
||||
foreach ($headerPieces as $c) {
|
||||
$cParts = explode('=', $c, 2);
|
||||
if (count($cParts) === 2) {
|
||||
$key = urldecode($cParts[0]);
|
||||
$value = urldecode($cParts[1]);
|
||||
if (!isset($cookies[$key])) {
|
||||
$cookies[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random IV
|
||||
*
|
||||
* This method will generate a non-predictable IV for use with
|
||||
* the cookie encryption
|
||||
*
|
||||
* @param int $expires The UNIX timestamp at which this cookie will expire
|
||||
* @param string $secret The secret key used to hash the cookie value
|
||||
* @return string Hash
|
||||
*/
|
||||
private static function getIv($expires, $secret)
|
||||
{
|
||||
$data1 = hash_hmac('sha1', 'a'.$expires.'b', $secret);
|
||||
$data2 = hash_hmac('sha1', 'z'.$expires.'y', $secret);
|
||||
|
||||
return pack("h*", $data1.$data2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user