git-svn-id: https://msi/svn/firstRepo/Service/branches/Slim3@39 0f545695-f87b-41b6-9a03-7f16563b5454

This commit is contained in:
2016-01-05 21:40:12 +00:00
51 changed files with 11657 additions and 0 deletions
+224
View File
@@ -0,0 +1,224 @@
<?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;
/**
* Environment
*
* This class creates and returns a key/value array of common
* environment variables for the current HTTP request.
*
* This is a singleton class; derived environment variables will
* be common across multiple Slim applications.
*
* This class matches the Rack (Ruby) specification as closely
* as possible. More information available below.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Environment implements \ArrayAccess, \IteratorAggregate
{
/**
* @var array
*/
protected $properties;
/**
* @var \Slim\Environment
*/
protected static $environment;
/**
* Get environment instance (singleton)
*
* This creates and/or returns an environment instance (singleton)
* derived from $_SERVER variables. You may override the global server
* variables by using `\Slim\Environment::mock()` instead.
*
* @param bool $refresh Refresh properties using global server variables?
* @return \Slim\Environment
*/
public static function getInstance($refresh = false)
{
if (is_null(self::$environment) || $refresh) {
self::$environment = new self();
}
return self::$environment;
}
/**
* Get mock environment instance
*
* @param array $userSettings
* @return \Slim\Environment
*/
public static function mock($userSettings = array())
{
$defaults = array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '',
'PATH_INFO' => '',
'QUERY_STRING' => '',
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
'ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'USER_AGENT' => 'Slim Framework',
'REMOTE_ADDR' => '127.0.0.1',
'slim.url_scheme' => 'http',
'slim.input' => '',
'slim.errors' => @fopen('php://stderr', 'w')
);
self::$environment = new self(array_merge($defaults, $userSettings));
return self::$environment;
}
/**
* Constructor (private access)
*
* @param array|null $settings If present, these are used instead of global server variables
*/
private function __construct($settings = null)
{
if ($settings) {
$this->properties = $settings;
} else {
$env = array();
//The HTTP request method
$env['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD'];
//The IP
$env['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
// Server params
$scriptName = $_SERVER['SCRIPT_NAME']; // <-- "/foo/index.php"
$requestUri = $_SERVER['REQUEST_URI']; // <-- "/foo/bar?test=abc" or "/foo/index.php/bar?test=abc"
$queryString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; // <-- "test=abc" or ""
// Physical path
if (strpos($requestUri, $scriptName) !== false) {
$physicalPath = $scriptName; // <-- Without rewriting
} else {
$physicalPath = str_replace('\\', '', dirname($scriptName)); // <-- With rewriting
}
$env['SCRIPT_NAME'] = rtrim($physicalPath, '/'); // <-- Remove trailing slashes
// Virtual path
$env['PATH_INFO'] = substr_replace($requestUri, '', 0, strlen($physicalPath)); // <-- Remove physical path
$env['PATH_INFO'] = str_replace('?' . $queryString, '', $env['PATH_INFO']); // <-- Remove query string
$env['PATH_INFO'] = '/' . ltrim($env['PATH_INFO'], '/'); // <-- Ensure leading slash
// Query string (without leading "?")
$env['QUERY_STRING'] = $queryString;
//Name of server host that is running the script
$env['SERVER_NAME'] = $_SERVER['SERVER_NAME'];
//Number of server port that is running the script
$env['SERVER_PORT'] = $_SERVER['SERVER_PORT'];
//HTTP request headers (retains HTTP_ prefix to match $_SERVER)
$headers = \Slim\Http\Headers::extract($_SERVER);
foreach ($headers as $key => $value) {
$env[$key] = $value;
}
//Is the application running under HTTPS or HTTP protocol?
$env['slim.url_scheme'] = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https';
//Input stream (readable one time only; not available for multipart/form-data requests)
$rawInput = @file_get_contents('php://input');
if (!$rawInput) {
$rawInput = '';
}
$env['slim.input'] = $rawInput;
//Error stream
$env['slim.errors'] = @fopen('php://stderr', 'w');
$this->properties = $env;
}
}
/**
* Array Access: Offset Exists
*/
public function offsetExists($offset)
{
return isset($this->properties[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet($offset)
{
if (isset($this->properties[$offset])) {
return $this->properties[$offset];
} else {
return null;
}
}
/**
* Array Access: Offset Set
*/
public function offsetSet($offset, $value)
{
$this->properties[$offset] = $value;
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset($offset)
{
unset($this->properties[$offset]);
}
/**
* IteratorAggregate
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->properties);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?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\Exception;
/**
* Pass Exception
*
* This Exception will cause the Router::dispatch method
* to skip the current matching route and continue to the next
* matching route. If no subsequent routes are found, a
* HTTP 404 Not Found response will be sent to the client.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Pass extends \Exception
{
}
+47
View File
@@ -0,0 +1,47 @@
<?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\Exception;
/**
* Stop Exception
*
* This Exception is thrown when the Slim application needs to abort
* processing and return control flow to the outer PHP script.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Stop extends \Exception
{
}
+246
View File
@@ -0,0 +1,246 @@
<?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\Helper;
class Set implements \ArrayAccess, \Countable, \IteratorAggregate
{
/**
* Key-value array of arbitrary data
* @var array
*/
protected $data = array();
/**
* Constructor
* @param array $items Pre-populate set with this key-value array
*/
public function __construct($items = array())
{
$this->replace($items);
}
/**
* Normalize data key
*
* Used to transform data key into the necessary
* key format for this set. Used in subclasses
* like \Slim\Http\Headers.
*
* @param string $key The data key
* @return mixed The transformed/normalized data key
*/
protected function normalizeKey($key)
{
return $key;
}
/**
* Set data key to value
* @param string $key The data key
* @param mixed $value The data value
*/
public function set($key, $value)
{
$this->data[$this->normalizeKey($key)] = $value;
}
/**
* Get data value with key
* @param string $key The data key
* @param mixed $default The value to return if data key does not exist
* @return mixed The data value, or the default value
*/
public function get($key, $default = null)
{
if ($this->has($key)) {
$isInvokable = is_object($this->data[$this->normalizeKey($key)]) && method_exists($this->data[$this->normalizeKey($key)], '__invoke');
return $isInvokable ? $this->data[$this->normalizeKey($key)]($this) : $this->data[$this->normalizeKey($key)];
}
return $default;
}
/**
* Add data to set
* @param array $items Key-value array of data to append to this set
*/
public function replace($items)
{
foreach ($items as $key => $value) {
$this->set($key, $value); // Ensure keys are normalized
}
}
/**
* Fetch set data
* @return array This set's key-value data array
*/
public function all()
{
return $this->data;
}
/**
* Fetch set data keys
* @return array This set's key-value data array keys
*/
public function keys()
{
return array_keys($this->data);
}
/**
* Does this set contain a key?
* @param string $key The data key
* @return boolean
*/
public function has($key)
{
return array_key_exists($this->normalizeKey($key), $this->data);
}
/**
* Remove value with key from this set
* @param string $key The data key
*/
public function remove($key)
{
unset($this->data[$this->normalizeKey($key)]);
}
/**
* Property Overloading
*/
public function __get($key)
{
return $this->get($key);
}
public function __set($key, $value)
{
$this->set($key, $value);
}
public function __isset($key)
{
return $this->has($key);
}
public function __unset($key)
{
return $this->remove($key);
}
/**
* Clear all values
*/
public function clear()
{
$this->data = array();
}
/**
* Array Access
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
public function offsetGet($offset)
{
return $this->get($offset);
}
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
public function offsetUnset($offset)
{
$this->remove($offset);
}
/**
* Countable
*/
public function count()
{
return count($this->data);
}
/**
* IteratorAggregate
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
/**
* Ensure a value or object will remain globally unique
* @param string $key The value or object name
* @param Closure The closure that defines the object
* @return mixed
*/
public function singleton($key, $value)
{
$this->set($key, function ($c) use ($value) {
static $object;
if (null === $object) {
$object = $value($c);
}
return $object;
});
}
/**
* Protect closure from being directly invoked
* @param Closure $callable A closure to keep from being invoked and evaluated
* @return Closure
*/
public function protect(\Closure $callable)
{
return function () use ($callable) {
return $callable;
};
}
}
+190
View File
@@ -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;
}
}
+197
View File
@@ -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
+450
View File
@@ -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;
}
}
+434
View File
@@ -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);
}
}
+349
View File
@@ -0,0 +1,349 @@
<?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;
/**
* Log
*
* This is the primary logger for a Slim application. You may provide
* a Log Writer in conjunction with this Log to write to various output
* destinations (e.g. a file). This class provides this interface:
*
* debug( mixed $object, array $context )
* info( mixed $object, array $context )
* notice( mixed $object, array $context )
* warning( mixed $object, array $context )
* error( mixed $object, array $context )
* critical( mixed $object, array $context )
* alert( mixed $object, array $context )
* emergency( mixed $object, array $context )
* log( mixed $level, mixed $object, array $context )
*
* This class assumes only that your Log Writer has a public `write()` method
* that accepts any object as its one and only argument. The Log Writer
* class may write or send its argument anywhere: a file, STDERR,
* a remote web API, etc. The possibilities are endless.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Log
{
const EMERGENCY = 1;
const ALERT = 2;
const CRITICAL = 3;
const FATAL = 3; //DEPRECATED replace with CRITICAL
const ERROR = 4;
const WARN = 5;
const NOTICE = 6;
const INFO = 7;
const DEBUG = 8;
/**
* @var array
*/
protected static $levels = array(
self::EMERGENCY => 'EMERGENCY',
self::ALERT => 'ALERT',
self::CRITICAL => 'CRITICAL',
self::ERROR => 'ERROR',
self::WARN => 'WARNING',
self::NOTICE => 'NOTICE',
self::INFO => 'INFO',
self::DEBUG => 'DEBUG'
);
/**
* @var mixed
*/
protected $writer;
/**
* @var bool
*/
protected $enabled;
/**
* @var int
*/
protected $level;
/**
* Constructor
* @param mixed $writer
*/
public function __construct($writer)
{
$this->writer = $writer;
$this->enabled = true;
$this->level = self::DEBUG;
}
/**
* Is logging enabled?
* @return bool
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Enable or disable logging
* @param bool $enabled
*/
public function setEnabled($enabled)
{
if ($enabled) {
$this->enabled = true;
} else {
$this->enabled = false;
}
}
/**
* Set level
* @param int $level
* @throws \InvalidArgumentException If invalid log level specified
*/
public function setLevel($level)
{
if (!isset(self::$levels[$level])) {
throw new \InvalidArgumentException('Invalid log level');
}
$this->level = $level;
}
/**
* Get level
* @return int
*/
public function getLevel()
{
return $this->level;
}
/**
* Set writer
* @param mixed $writer
*/
public function setWriter($writer)
{
$this->writer = $writer;
}
/**
* Get writer
* @return mixed
*/
public function getWriter()
{
return $this->writer;
}
/**
* Is logging enabled?
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Log debug message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function debug($object, $context = array())
{
return $this->log(self::DEBUG, $object, $context);
}
/**
* Log info message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function info($object, $context = array())
{
return $this->log(self::INFO, $object, $context);
}
/**
* Log notice message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function notice($object, $context = array())
{
return $this->log(self::NOTICE, $object, $context);
}
/**
* Log warning message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function warning($object, $context = array())
{
return $this->log(self::WARN, $object, $context);
}
/**
* DEPRECATED for function warning
* Log warning message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function warn($object, $context = array())
{
return $this->log(self::WARN, $object, $context);
}
/**
* Log error message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function error($object, $context = array())
{
return $this->log(self::ERROR, $object, $context);
}
/**
* Log critical message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function critical($object, $context = array())
{
return $this->log(self::CRITICAL, $object, $context);
}
/**
* DEPRECATED for function critical
* Log fatal message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function fatal($object, $context = array())
{
return $this->log(self::CRITICAL, $object, $context);
}
/**
* Log alert message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function alert($object, $context = array())
{
return $this->log(self::ALERT, $object, $context);
}
/**
* Log emergency message
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
public function emergency($object, $context = array())
{
return $this->log(self::EMERGENCY, $object, $context);
}
/**
* Log message
* @param mixed $level
* @param mixed $object
* @param array $context
* @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
* @throws \InvalidArgumentException If invalid log level
*/
public function log($level, $object, $context = array())
{
if (!isset(self::$levels[$level])) {
throw new \InvalidArgumentException('Invalid log level supplied to function');
} else if ($this->enabled && $this->writer && $level <= $this->level) {
$message = (string)$object;
if (count($context) > 0) {
if (isset($context['exception']) && $context['exception'] instanceof \Exception) {
$message .= ' - ' . $context['exception'];
unset($context['exception']);
}
$message = $this->interpolate($message, $context);
}
return $this->writer->write($message, $level);
} else {
return false;
}
}
/**
* DEPRECATED for function log
* Log message
* @param mixed $object The object to log
* @param int $level The message level
* @return int|bool
*/
protected function write($object, $level)
{
return $this->log($level, $object);
}
/**
* Interpolate log message
* @param mixed $message The log message
* @param array $context An array of placeholder values
* @return string The processed string
*/
protected function interpolate($message, $context = array())
{
$replace = array();
foreach ($context as $key => $value) {
$replace['{' . $key . '}'] = $value;
}
return strtr($message, $replace);
}
}
+75
View File
@@ -0,0 +1,75 @@
<?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;
/**
* Log Writer
*
* This class is used by Slim_Log to write log messages to a valid, writable
* resource handle (e.g. a file or STDERR).
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class LogWriter
{
/**
* @var resource
*/
protected $resource;
/**
* Constructor
* @param resource $resource
* @throws \InvalidArgumentException If invalid resource
*/
public function __construct($resource)
{
if (!is_resource($resource)) {
throw new \InvalidArgumentException('Cannot create LogWriter. Invalid resource handle.');
}
$this->resource = $resource;
}
/**
* Write message
* @param mixed $message
* @param int $level
* @return int|bool
*/
public function write($message, $level = null)
{
return fwrite($this->resource, (string) $message . PHP_EOL);
}
}
+114
View File
@@ -0,0 +1,114 @@
<?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;
/**
* Middleware
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
abstract class Middleware
{
/**
* @var \Slim\Slim Reference to the primary application instance
*/
protected $app;
/**
* @var mixed Reference to the next downstream middleware
*/
protected $next;
/**
* Set application
*
* This method injects the primary Slim application instance into
* this middleware.
*
* @param \Slim\Slim $application
*/
final public function setApplication($application)
{
$this->app = $application;
}
/**
* Get application
*
* This method retrieves the application previously injected
* into this middleware.
*
* @return \Slim\Slim
*/
final public function getApplication()
{
return $this->app;
}
/**
* Set next middleware
*
* This method injects the next downstream middleware into
* this middleware so that it may optionally be called
* when appropriate.
*
* @param \Slim|\Slim\Middleware
*/
final public function setNextMiddleware($nextMiddleware)
{
$this->next = $nextMiddleware;
}
/**
* Get next middleware
*
* This method retrieves the next downstream middleware
* previously injected into this middleware.
*
* @return \Slim\Slim|\Slim\Middleware
*/
final public function getNextMiddleware()
{
return $this->next;
}
/**
* Call
*
* Perform actions specific to this middleware and optionally
* call the next downstream middleware.
*/
abstract public function call();
}
+174
View File
@@ -0,0 +1,174 @@
<?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\Middleware;
/**
* Content Types
*
* This is middleware for a Slim application that intercepts
* the HTTP request body and parses it into the appropriate
* PHP data structure if possible; else it returns the HTTP
* request body unchanged. This is particularly useful
* for preparing the HTTP request body for an XML or JSON API.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class ContentTypes extends \Slim\Middleware
{
/**
* @var array
*/
protected $contentTypes;
/**
* Constructor
* @param array $settings
*/
public function __construct($settings = array())
{
$defaults = array(
'application/json' => array($this, 'parseJson'),
'application/xml' => array($this, 'parseXml'),
'text/xml' => array($this, 'parseXml'),
'text/csv' => array($this, 'parseCsv')
);
$this->contentTypes = array_merge($defaults, $settings);
}
/**
* Call
*/
public function call()
{
$mediaType = $this->app->request()->getMediaType();
if ($mediaType) {
$env = $this->app->environment();
$env['slim.input_original'] = $env['slim.input'];
$env['slim.input'] = $this->parse($env['slim.input'], $mediaType);
}
$this->next->call();
}
/**
* Parse input
*
* This method will attempt to parse the request body
* based on its content type if available.
*
* @param string $input
* @param string $contentType
* @return mixed
*/
protected function parse ($input, $contentType)
{
if (isset($this->contentTypes[$contentType]) && is_callable($this->contentTypes[$contentType])) {
$result = call_user_func($this->contentTypes[$contentType], $input);
if ($result) {
return $result;
}
}
return $input;
}
/**
* Parse JSON
*
* This method converts the raw JSON input
* into an associative array.
*
* @param string $input
* @return array|string
*/
protected function parseJson($input)
{
if (function_exists('json_decode')) {
$result = json_decode($input, true);
if ($result) {
return $result;
}
}
}
/**
* Parse XML
*
* This method creates a SimpleXMLElement
* based upon the XML input. If the SimpleXML
* extension is not available, the raw input
* will be returned unchanged.
*
* @param string $input
* @return \SimpleXMLElement|string
*/
protected function parseXml($input)
{
if (class_exists('SimpleXMLElement')) {
try {
$backup = libxml_disable_entity_loader(true);
$result = new \SimpleXMLElement($input);
libxml_disable_entity_loader($backup);
return $result;
} catch (\Exception $e) {
// Do nothing
}
}
return $input;
}
/**
* Parse CSV
*
* This method parses CSV content into a numeric array
* containing an array of data for each CSV line.
*
* @param string $input
* @return array
*/
protected function parseCsv($input)
{
$temp = fopen('php://memory', 'rw');
fwrite($temp, $input);
fseek($temp, 0);
$res = array();
while (($data = fgetcsv($temp)) !== false) {
$res[] = $data;
}
fclose($temp);
return $res;
}
}
+212
View File
@@ -0,0 +1,212 @@
<?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\Middleware;
/**
* Flash
*
* This is middleware for a Slim application that enables
* Flash messaging between HTTP requests. This allows you
* set Flash messages for the current request, for the next request,
* or to retain messages from the previous request through to
* the next request.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Flash extends \Slim\Middleware implements \ArrayAccess, \IteratorAggregate, \Countable
{
/**
* @var array
*/
protected $settings;
/**
* @var array
*/
protected $messages;
/**
* Constructor
* @param array $settings
*/
public function __construct($settings = array())
{
$this->settings = array_merge(array('key' => 'slim.flash'), $settings);
$this->messages = array(
'prev' => array(), //flash messages from prev request (loaded when middleware called)
'next' => array(), //flash messages for next request
'now' => array() //flash messages for current request
);
}
/**
* Call
*/
public function call()
{
//Read flash messaging from previous request if available
$this->loadMessages();
//Prepare flash messaging for current request
$env = $this->app->environment();
$env['slim.flash'] = $this;
$this->next->call();
$this->save();
}
/**
* Now
*
* Specify a flash message for a given key to be shown for the current request
*
* @param string $key
* @param string $value
*/
public function now($key, $value)
{
$this->messages['now'][(string) $key] = $value;
}
/**
* Set
*
* Specify a flash message for a given key to be shown for the next request
*
* @param string $key
* @param string $value
*/
public function set($key, $value)
{
$this->messages['next'][(string) $key] = $value;
}
/**
* Keep
*
* Retain flash messages from the previous request for the next request
*/
public function keep()
{
foreach ($this->messages['prev'] as $key => $val) {
$this->messages['next'][$key] = $val;
}
}
/**
* Save
*/
public function save()
{
$_SESSION[$this->settings['key']] = $this->messages['next'];
}
/**
* Load messages from previous request if available
*/
public function loadMessages()
{
if (isset($_SESSION[$this->settings['key']])) {
$this->messages['prev'] = $_SESSION[$this->settings['key']];
}
}
/**
* Return array of flash messages to be shown for the current request
*
* @return array
*/
public function getMessages()
{
return array_merge($this->messages['prev'], $this->messages['now']);
}
/**
* Array Access: Offset Exists
*/
public function offsetExists($offset)
{
$messages = $this->getMessages();
return isset($messages[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet($offset)
{
$messages = $this->getMessages();
return isset($messages[$offset]) ? $messages[$offset] : null;
}
/**
* Array Access: Offset Set
*/
public function offsetSet($offset, $value)
{
$this->now($offset, $value);
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset($offset)
{
unset($this->messages['prev'][$offset], $this->messages['now'][$offset]);
}
/**
* Iterator Aggregate: Get Iterator
* @return \ArrayIterator
*/
public function getIterator()
{
$messages = $this->getMessages();
return new \ArrayIterator($messages);
}
/**
* Countable: Count
*/
public function count()
{
return count($this->getMessages());
}
}
+94
View File
@@ -0,0 +1,94 @@
<?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\Middleware;
/**
* HTTP Method Override
*
* This is middleware for a Slim application that allows traditional
* desktop browsers to submit pseudo PUT and DELETE requests by relying
* on a pre-determined request parameter. Without this middleware,
* desktop browsers are only able to submit GET and POST requests.
*
* This middleware is included automatically!
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class MethodOverride extends \Slim\Middleware
{
/**
* @var array
*/
protected $settings;
/**
* Constructor
* @param array $settings
*/
public function __construct($settings = array())
{
$this->settings = array_merge(array('key' => '_METHOD'), $settings);
}
/**
* Call
*
* Implements Slim middleware interface. This method is invoked and passed
* an array of environment variables. This middleware inspects the environment
* variables for the HTTP method override parameter; if found, this middleware
* modifies the environment settings so downstream middleware and/or the Slim
* application will treat the request with the desired HTTP method.
*
* @return array[status, header, body]
*/
public function call()
{
$env = $this->app->environment();
if (isset($env['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
// Header commonly used by Backbone.js and others
$env['slim.method_override.original_method'] = $env['REQUEST_METHOD'];
$env['REQUEST_METHOD'] = strtoupper($env['HTTP_X_HTTP_METHOD_OVERRIDE']);
} elseif (isset($env['REQUEST_METHOD']) && $env['REQUEST_METHOD'] === 'POST') {
// HTML Form Override
$req = new \Slim\Http\Request($env);
$method = $req->post($this->settings['key']);
if ($method) {
$env['slim.method_override.original_method'] = $env['REQUEST_METHOD'];
$env['REQUEST_METHOD'] = strtoupper($method);
}
}
$this->next->call();
}
}
+116
View File
@@ -0,0 +1,116 @@
<?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\Middleware;
/**
* Pretty Exceptions
*
* This middleware catches any Exception thrown by the surrounded
* application and displays a developer-friendly diagnostic screen.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class PrettyExceptions extends \Slim\Middleware
{
/**
* @var array
*/
protected $settings;
/**
* Constructor
* @param array $settings
*/
public function __construct($settings = array())
{
$this->settings = $settings;
}
/**
* Call
*/
public function call()
{
try {
$this->next->call();
} catch (\Exception $e) {
$log = $this->app->getLog(); // Force Slim to append log to env if not already
$env = $this->app->environment();
$env['slim.log'] = $log;
$env['slim.log']->error($e);
$this->app->contentType('text/html');
$this->app->response()->status(500);
$this->app->response()->body($this->renderBody($env, $e));
}
}
/**
* Render response body
* @param array $env
* @param \Exception $exception
* @return string
*/
protected function renderBody(&$env, $exception)
{
$title = 'Slim Application Error';
$code = $exception->getCode();
$message = $exception->getMessage();
$file = $exception->getFile();
$line = $exception->getLine();
$trace = str_replace(array('#', '\n'), array('<div>#', '</div>'), $exception->getTraceAsString());
$html = sprintf('<h1>%s</h1>', $title);
$html .= '<p>The application could not run because of the following error:</p>';
$html .= '<h2>Details</h2>';
$html .= sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
if ($code) {
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
}
if ($message) {
$html .= sprintf('<div><strong>Message:</strong> %s</div>', $message);
}
if ($file) {
$html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
}
if ($line) {
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
}
if ($trace) {
$html .= '<h2>Trace</h2>';
$html .= sprintf('<pre>%s</pre>', $trace);
}
return sprintf("<html><head><title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}</style></head><body>%s</body></html>", $title, $html);
}
}
+210
View File
@@ -0,0 +1,210 @@
<?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\Middleware;
/**
* Session Cookie
*
* This class provides an HTTP cookie storage mechanism
* for session data. This class avoids using a PHP session
* and instead serializes/unserializes the $_SESSION global
* variable to/from an HTTP cookie.
*
* You should NEVER store sensitive data in a client-side cookie
* in any format, encrypted (with cookies.encrypt) or not. If you
* need to store sensitive user information in a session, you should
* rely on PHP's native session implementation, or use other middleware
* to store session data in a database or alternative server-side cache.
*
* Because this class stores serialized session data in an HTTP cookie,
* you are inherently limited to 4 Kb. If you attempt to store
* more than this amount, serialization will fail.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class SessionCookie extends \Slim\Middleware
{
/**
* @var array
*/
protected $settings;
/**
* Constructor
*
* @param array $settings
*/
public function __construct($settings = array())
{
$defaults = array(
'expires' => '20 minutes',
'path' => '/',
'domain' => null,
'secure' => false,
'httponly' => false,
'name' => 'slim_session',
);
$this->settings = array_merge($defaults, $settings);
if (is_string($this->settings['expires'])) {
$this->settings['expires'] = strtotime($this->settings['expires']);
}
/**
* Session
*
* We must start a native PHP session to initialize the $_SESSION superglobal.
* However, we won't be using the native session store for persistence, so we
* disable the session cookie and cache limiter. We also set the session
* handler to this class instance to avoid PHP's native session file locking.
*/
ini_set('session.use_cookies', 0);
session_cache_limiter(false);
session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
}
/**
* Call
*/
public function call()
{
$this->loadSession();
$this->next->call();
$this->saveSession();
}
/**
* Load session
*/
protected function loadSession()
{
if (session_id() === '') {
session_start();
}
$value = $this->app->getCookie($this->settings['name']);
if ($value) {
try {
$_SESSION = unserialize($value);
} catch (\Exception $e) {
$this->app->getLog()->error('Error unserializing session cookie value! ' . $e->getMessage());
}
} else {
$_SESSION = array();
}
}
/**
* Save session
*/
protected function saveSession()
{
$value = serialize($_SESSION);
if (strlen($value) > 4096) {
$this->app->getLog()->error('WARNING! Slim\Middleware\SessionCookie data size is larger than 4KB. Content save failed.');
} else {
$this->app->setCookie(
$this->settings['name'],
$value,
$this->settings['expires'],
$this->settings['path'],
$this->settings['domain'],
$this->settings['secure'],
$this->settings['httponly']
);
}
// session_destroy();
}
/********************************************************************************
* Session Handler
*******************************************************************************/
/**
* @codeCoverageIgnore
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* @codeCoverageIgnore
*/
public function close()
{
return true;
}
/**
* @codeCoverageIgnore
*/
public function read($id)
{
return '';
}
/**
* @codeCoverageIgnore
*/
public function write($id, $data)
{
return true;
}
/**
* @codeCoverageIgnore
*/
public function destroy($id)
{
return true;
}
/**
* @codeCoverageIgnore
*/
public function gc($maxlifetime)
{
return true;
}
}
+357
View File
@@ -0,0 +1,357 @@
<?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;
use Exception;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Handlers\Strategies\RequestResponse;
use Slim\Interfaces\InvocationStrategyInterface;
use Slim\Interfaces\RouteInterface;
/**
* Route
*/
class Route extends Routable implements RouteInterface
{
use MiddlewareAwareTrait;
/**
* HTTP methods supported by this route
*
* @var string[]
*/
protected $methods = [];
/**
* Route identifier
*
* @var string
*/
protected $identifier;
/**
* Route name
*
* @var null|string
*/
protected $name;
/**
* Parent route groups
*
* @var RouteGroup[]
*/
protected $groups;
private $finalized = false;
/**
* Output buffering mode
*
* One of: false, 'prepend' or 'append'
*
* @var boolean|string
*/
protected $outputBuffering = 'append';
/**
* Route parameters
*
* @var array
*/
protected $arguments = [];
/**
* Create new route
*
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable $callable The route callable
* @param int $identifier The route identifier
* @param RouteGroup[] $groups The parent route groups
*/
public function __construct($methods, $pattern, $callable, $groups = [], $identifier = 0)
{
$this->methods = $methods;
$this->pattern = $pattern;
$this->callable = $callable;
$this->groups = $groups;
$this->identifier = 'route' . $identifier;
}
/**
* Finalize the route in preparation for dispatching
*/
public function finalize()
{
if ($this->finalized) {
return;
}
$groupMiddleware = [];
foreach ($this->getGroups() as $group) {
$groupMiddleware = array_merge($group->getMiddleware(), $groupMiddleware);
}
$this->middleware = array_merge($this->middleware, $groupMiddleware);
foreach ($this->getMiddleware() as $middleware) {
$this->addMiddleware($middleware);
}
$this->finalized = true;
}
/**
* Get route callable
*
* @return callable
*/
public function getCallable()
{
return $this->callable;
}
/**
* Get route methods
*
* @return string[]
*/
public function getMethods()
{
return $this->methods;
}
/**
* Get parent route groups
*
* @return RouteGroup[]
*/
public function getGroups()
{
return $this->groups;
}
/**
* Get route name
*
* @return null|string
*/
public function getName()
{
return $this->name;
}
/**
* Get route identifier
*
* @return string
*/
public function getIdentifier()
{
return $this->identifier;
}
/**
* Get output buffering mode
*
* @return boolean|string
*/
public function getOutputBuffering()
{
return $this->outputBuffering;
}
/**
* Set output buffering mode
*
* One of: false, 'prepend' or 'append'
*
* @param boolean|string $mode
*
* @throws InvalidArgumentException If an unknown buffering mode is specified
*/
public function setOutputBuffering($mode)
{
if (!in_array($mode, [false, 'prepend', 'append'], true)) {
throw new InvalidArgumentException('Unknown output buffering mode');
}
$this->outputBuffering = $mode;
}
/**
* Set route name
*
* @param string $name
*
* @return self
*
* @throws InvalidArgumentException if the route name is not a string
*/
public function setName($name)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Route name must be a string');
}
$this->name = $name;
return $this;
}
/**
* Set a route argument
*
* @param string $name
* @param string $value
*
* @return self
*/
public function setArgument($name, $value)
{
$this->arguments[$name] = $value;
return $this;
}
/**
* Replace route arguments
*
* @param array $arguments
*
* @return self
*/
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
return $this;
}
/**
* Retrieve route arguments
*
* @return array
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Retrieve a specific route argument
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function getArgument($name, $default = null)
{
if (array_key_exists($name, $this->arguments)) {
return $this->arguments[$name];
}
return $default;
}
/********************************************************************************
* Route Runner
*******************************************************************************/
/**
* Prepare the route for use
*
* @param ServerRequestInterface $request
* @param array $arguments
*/
public function prepare(ServerRequestInterface $request, array $arguments)
{
// Add the arguments
foreach ($arguments as $k => $v) {
$this->setArgument($k, $v);
}
}
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
*
* @return ResponseInterface
*/
public function run(ServerRequestInterface $request, ResponseInterface $response)
{
// Finalise route now that we are about to run it
$this->finalize();
// Traverse middleware stack and fetch updated response
return $this->callMiddlewareStack($request, $response);
}
/**
* Dispatch route callable against current Request and Response objects
*
* This method invokes the route object's callable. If middleware is
* registered for the route, each callable middleware is invoked in
* the order specified.
*
* @param ServerRequestInterface $request The current Request object
* @param ResponseInterface $response The current Response object
* @return \Psr\Http\Message\ResponseInterface
* @throws \Exception if the route callable throws an exception
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
{
$this->callable = $this->resolveCallable($this->callable);
/** @var InvocationStrategyInterface $handler */
$handler = isset($this->container) ? $this->container->get('foundHandler') : new RequestResponse();
// invoke route callable
if ($this->outputBuffering === false) {
$newResponse = $handler($this->callable, $request, $response, $this->arguments);
} else {
try {
ob_start();
$newResponse = $handler($this->callable, $request, $response, $this->arguments);
$output = ob_get_clean();
} catch (Exception $e) {
ob_end_clean();
throw $e;
}
}
if ($newResponse instanceof ResponseInterface) {
// if route callback returns a ResponseInterface, then use it
$response = $newResponse;
} elseif (is_string($newResponse)) {
// if route callback returns a string, then append it to the response
if ($response->getBody()->isWritable()) {
$response->getBody()->write($newResponse);
}
}
if (!empty($output) && $response->getBody()->isWritable()) {
if ($this->outputBuffering === 'prepend') {
// prepend output buffer content
$body = new Http\Body(fopen('php://temp', 'r+'));
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($this->outputBuffering === 'append') {
// append output buffer content
$response->getBody()->write($output);
}
}
return $response;
}
}
+383
View File
@@ -0,0 +1,383 @@
<?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;
use FastRoute\Dispatcher;
use InvalidArgumentException;
use RuntimeException;
use Psr\Http\Message\ServerRequestInterface;
use FastRoute\RouteCollector;
use FastRoute\RouteParser;
use FastRoute\RouteParser\Std as StdParser;
use FastRoute\DataGenerator;
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouterInterface;
use Slim\Interfaces\RouteInterface;
/**
* Router
*
* This class organizes Slim application route objects. It is responsible
* for registering route objects, assigning names to route objects,
* finding routes that match the current HTTP request, and creating
* URLs for a named route.
*/
class Router implements RouterInterface
{
/**
* Parser
*
* @var \FastRoute\RouteParser
*/
protected $routeParser;
/**
* Base path used in pathFor()
*
* @var string
*/
protected $basePath = '';
/**
* Routes
*
* @var Route[]
*/
protected $routes = [];
/**
* Route counter incrementer
* @var int
*/
protected $routeCounter = 0;
/**
* Named routes
*
* @var null|Route[]
*/
protected $namedRoutes;
/**
* Route groups
*
* @var RouteGroup[]
*/
protected $routeGroups = [];
/**
* @var \FastRoute\Dispatcher
*/
protected $dispatcher;
/**
* Create new router
*
* @param RouteParser $parser
*/
public function __construct(RouteParser $parser = null)
{
$this->routeParser = $parser ?: new StdParser;
}
/**
* Set the base path used in pathFor()
*
* @param string $basePath
*
* @return self
*/
public function setBasePath($basePath)
{
if (!is_string($basePath)) {
throw new InvalidArgumentException('Router basePath must be a string');
}
$this->basePath = $basePath;
return $this;
}
/**
* Add route
*
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable $handler The route callable
*
* @return RouteInterface
*
* @throws InvalidArgumentException if the route pattern isn't a string
*/
public function map($methods, $pattern, $handler)
{
if (!is_string($pattern)) {
throw new InvalidArgumentException('Route pattern must be a string');
}
// Prepend parent group pattern(s)
if ($this->routeGroups) {
$pattern = $this->processGroups() . $pattern;
}
// According to RFC methods are defined in uppercase (See RFC 7231)
$methods = array_map("strtoupper", $methods);
// Add route
$route = new Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter);
$this->routes[$route->getIdentifier()] = $route;
$this->routeCounter++;
return $route;
}
/**
* Dispatch router for HTTP request
*
* @param ServerRequestInterface $request The current HTTP request object
*
* @return array
*
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
*/
public function dispatch(ServerRequestInterface $request)
{
$uri = '/' . ltrim($request->getUri()->getPath(), '/');
return $this->createDispatcher()->dispatch(
$request->getMethod(),
$uri
);
}
/**
* @return \FastRoute\Dispatcher
*/
protected function createDispatcher()
{
return $this->dispatcher ?: \FastRoute\simpleDispatcher(function (RouteCollector $r) {
foreach ($this->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
}, [
'routeParser' => $this->routeParser
]);
}
/**
* @param \FastRoute\Dispatcher $dispatcher
*/
public function setDispatcher(Dispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Get route objects
*
* @return Route[]
*/
public function getRoutes()
{
return $this->routes;
}
/**
* Get named route object
*
* @param string $name Route name
*
* @return Route
*
* @throws RuntimeException If named route does not exist
*/
public function getNamedRoute($name)
{
if (is_null($this->namedRoutes)) {
$this->buildNameIndex();
}
if (!isset($this->namedRoutes[$name])) {
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
return $this->namedRoutes[$name];
}
/**
* Process route groups
*
* @return string A group pattern to prefix routes with
*/
protected function processGroups()
{
$pattern = "";
foreach ($this->routeGroups as $group) {
$pattern .= $group->getPattern();
}
return $pattern;
}
/**
* Add a route group to the array
*
* @param string $pattern
* @param callable $callable
*
* @return RouteGroupInterface
*/
public function pushGroup($pattern, $callable)
{
$group = new RouteGroup($pattern, $callable);
array_push($this->routeGroups, $group);
return $group;
}
/**
* Removes the last route group from the array
*
* @return RouteGroup|bool The RouteGroup if successful, else False
*/
public function popGroup()
{
$group = array_pop($this->routeGroups);
return $group instanceof RouteGroup ? $group : false;
}
/**
* @param $identifier
* @return \Slim\Interfaces\RouteInterface
*/
public function lookupRoute($identifier)
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* Build the path for a named route excluding the base path
*
* @param string $name Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @return string
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativePathFor($name, array $data = [], array $queryParams = [])
{
$route = $this->getNamedRoute($name);
$pattern = $route->getPattern();
$routeDatas = $this->routeParser->parse($pattern);
// $routeDatas is an array of all possible routes that can be made. There is
// one routedata for each optional parameter plus one for no optional parameters.
//
// The most specific is last, so we look for that first.
$routeDatas = array_reverse($routeDatas);
$segments = [];
foreach ($routeDatas as $routeData) {
foreach ($routeData as $item) {
if (is_string($item)) {
// this segment is a static string
$segments[] = $item;
continue;
}
// This segment has a parameter: first element is the name
if (!array_key_exists($item[0], $data)) {
// we don't have a data element for this segment: cancel
// testing this routeData item, so that we can try a less
// specific routeData item.
$segments = [];
$segmentName = $item[0];
break;
}
$segments[] = $data[$item[0]];
}
if (!empty($segments)) {
// we found all the parameters for this route data, no need to check
// less specific ones
break;
}
}
if (empty($segments)) {
throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
}
$url = implode('', $segments);
if ($queryParams) {
$url .= '?' . http_build_query($queryParams);
}
return $url;
}
/**
* Build the path for a named route including the base path
*
* @param string $name Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @return string
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function pathFor($name, array $data = [], array $queryParams = [])
{
$url = $this->relativePathFor($name, $data, $queryParams);
if ($this->basePath) {
$url = $this->basePath . $url;
}
return $url;
}
/**
* Build the path for a named route.
*
* This method is deprecated. Use pathFor() from now on.
*
* @param string $name Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @return string
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function urlFor($name, array $data = [], array $queryParams = [])
{
trigger_error('urlFor() is deprecated. Use pathFor() instead.', E_USER_DEPRECATED);
return $this->pathFor($name, $data, $queryParams);
}
/**
* Build index of named routes
*/
protected function buildNameIndex()
{
$this->namedRoutes = [];
foreach ($this->routes as $route) {
$name = $route->getName();
if ($name) {
$this->namedRoutes[$name] = $route;
}
}
}
}
+1412
View File
File diff suppressed because it is too large Load Diff
+282
View File
@@ -0,0 +1,282 @@
<?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;
/**
* View
*
* The view is responsible for rendering a template. The view
* should subclass \Slim\View and implement this interface:
*
* public render(string $template);
*
* This method should render the specified template and return
* the resultant string.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class View
{
/**
* Data available to the view templates
* @var \Slim\Helper\Set
*/
protected $data;
/**
* Path to templates base directory (without trailing slash)
* @var string
*/
protected $templatesDirectory;
/**
* Constructor
*/
public function __construct()
{
$this->data = new \Slim\Helper\Set();
}
/********************************************************************************
* Data methods
*******************************************************************************/
/**
* Does view data have value with key?
* @param string $key
* @return boolean
*/
public function has($key)
{
return $this->data->has($key);
}
/**
* Return view data value with key
* @param string $key
* @return mixed
*/
public function get($key)
{
return $this->data->get($key);
}
/**
* Set view data value with key
* @param string $key
* @param mixed $value
*/
public function set($key, $value)
{
$this->data->set($key, $value);
}
/**
* Set view data value as Closure with key
* @param string $key
* @param mixed $value
*/
public function keep($key, Closure $value)
{
$this->data->keep($key, $value);
}
/**
* Return view data
* @return array
*/
public function all()
{
return $this->data->all();
}
/**
* Replace view data
* @param array $data
*/
public function replace(array $data)
{
$this->data->replace($data);
}
/**
* Clear view data
*/
public function clear()
{
$this->data->clear();
}
/********************************************************************************
* Legacy data methods
*******************************************************************************/
/**
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* Get data from view
*/
public function getData($key = null)
{
if (!is_null($key)) {
return isset($this->data[$key]) ? $this->data[$key] : null;
} else {
return $this->data->all();
}
}
/**
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* Set data for view
*/
public function setData()
{
$args = func_get_args();
if (count($args) === 1 && is_array($args[0])) {
$this->data->replace($args[0]);
} elseif (count($args) === 2) {
// Ensure original behavior is maintained. DO NOT invoke stored Closures.
if (is_object($args[1]) && method_exists($args[1], '__invoke')) {
$this->data->set($args[0], $this->data->protect($args[1]));
} else {
$this->data->set($args[0], $args[1]);
}
} else {
throw new \InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`');
}
}
/**
* DEPRECATION WARNING! This method will be removed in the next major point release
*
* Append data to view
* @param array $data
*/
public function appendData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
$this->data->replace($data);
}
/********************************************************************************
* Resolve template paths
*******************************************************************************/
/**
* Set the base directory that contains view templates
* @param string $directory
* @throws \InvalidArgumentException If directory is not a directory
*/
public function setTemplatesDirectory($directory)
{
$this->templatesDirectory = rtrim($directory, DIRECTORY_SEPARATOR);
}
/**
* Get templates base directory
* @return string
*/
public function getTemplatesDirectory()
{
return $this->templatesDirectory;
}
/**
* Get fully qualified path to template file using templates base directory
* @param string $file The template file pathname relative to templates base directory
* @return string
*/
public function getTemplatePathname($file)
{
return $this->templatesDirectory . DIRECTORY_SEPARATOR . ltrim($file, DIRECTORY_SEPARATOR);
}
/********************************************************************************
* Rendering
*******************************************************************************/
/**
* Display template
*
* This method echoes the rendered template to the current output buffer
*
* @param string $template Pathname of template file relative to templates directory
* @param array $data Any additonal data to be passed to the template.
*/
public function display($template, $data = null)
{
echo $this->fetch($template, $data);
}
/**
* Return the contents of a rendered template file
*
* @param string $template The template pathname, relative to the template base directory
* @param array $data Any additonal data to be passed to the template.
* @return string The rendered template
*/
public function fetch($template, $data = null)
{
return $this->render($template, $data);
}
/**
* Render a template file
*
* NOTE: This method should be overridden by custom view subclasses
*
* @param string $template The template pathname, relative to the template base directory
* @param array $data Any additonal data to be passed to the template.
* @return string The rendered template
* @throws \RuntimeException If resolved template pathname is not a valid file
*/
protected function render($template, $data = null)
{
$templatePathname = $this->getTemplatePathname($template);
if (!is_file($templatePathname)) {
throw new \RuntimeException("View cannot render `$template` because the template does not exist");
}
$data = array_merge($this->data->all(), (array) $data);
extract($data);
ob_start();
require $templatePathname;
return ob_get_clean();
}
}