Added function to generate the passcode

This commit is contained in:
Peter Goodhall 2012-11-22 21:19:06 +00:00
parent 6f14b71386
commit 6f03be8cf6
21 changed files with 2858 additions and 2174 deletions

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,7 +29,6 @@
* 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
@ -41,10 +39,7 @@ namespace Slim\Exception;
* HTTP 404 Not Found response will be sent to the client.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Pass extends \Exception
{
}
class Slim_Exception_Pass extends Exception {}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,7 +29,6 @@
* 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;
/**
* Request Slash Exception
@ -42,10 +40,7 @@ namespace Slim\Exception;
* to the same resource URI with a trailing slash.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class RequestSlash extends \Exception
{
}
class Slim_Exception_RequestSlash extends Exception {}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,7 +29,6 @@
* 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
@ -39,10 +37,7 @@ namespace Slim\Exception;
* processing and return control flow to the outer PHP script.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Stop extends \Exception
{
}
class Slim_Exception_Stop extends Exception {}

222
Slim/Http/Cookie.php Normal file
View File

@ -0,0 +1,222 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.5.0
*
* 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.
*/
/**
* Cookie
*
* Object-oriented representation of a Cookie to be sent in an HTTP response
*
* @package Slim
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Slim_Http_Cookie {
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $value;
/**
* @var int UNIX timestamp
*/
protected $expires;
/**
* @var string
*/
protected $path;
/**
* @var string
*/
protected $domain;
/**
* @var bool
*/
protected $secure;
/**
* @var bool
*/
protected $httponly;
/**
* Constructor
* @param string $name The cookie name
* @param string $value The cookie value
* @param mixed $time The duration of the cookie;
* If integer, should be a UNIX timestamp;
* If string, converted to UNIX timestamp with `strtotime`;
* @param string $path The path on the server in which the cookie will be available on
* @param string $domain The domain that the cookie is available to
* @param bool $secure Indicates that the cookie should only be transmitted over a secure
* HTTPS connection from the client
* @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
* @return void
*/
public function __construct( $name, $value = null, $expires = 0, $path = null, $domain = null, $secure = false, $httponly = false ) {
$this->setName($name);
$this->setValue($value);
$this->setExpires($expires);
$this->setPath($path);
$this->setDomain($domain);
$this->setSecure($secure);
$this->setHttpOnly($httponly);
}
/**
* Get cookie name
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Set cookie name
* @param string $name
* @return void
*/
public function setName( $name ) {
$this->name = (string)$name;
}
/**
* Get cookie value
* @return string
*/
public function getValue() {
return $this->value;
}
/**
* Set cookie value
* @param string $value
* @return void
*/
public function setValue( $value ) {
$this->value = (string)$value;
}
/**
* Get cookie expiration time
* @return int UNIX timestamp
*/
public function getExpires() {
return $this->expires;
}
/**
* Set cookie expiration time
* @param string|int Cookie expiration time
* @return void
*/
public function setExpires( $time ) {
$this->expires = is_string($time) ? strtotime($time) : (int)$time;
}
/**
* Get cookie path
* @return string
*/
public function getPath() {
return $this->path;
}
/**
* Set cookie path
* @param string $path
* @return void
*/
public function setPath( $path ) {
$this->path = (string)$path;
}
/**
* Get cookie domain
* @return string
*/
public function getDomain() {
return $this->domain;
}
/**
* Set cookie domain
* @param string $domain
* @return void
*/
public function setDomain( $domain ) {
$this->domain = (string)$domain;
}
/**
* Is cookie sent only if SSL/HTTPS is used?
* @return bool
*/
public function getSecure() {
return $this->secure;
}
/**
* Set whether cookie is sent only if SSL/HTTPS is used
* @param bool $secure
* @return void
*/
public function setSecure( $secure ) {
$this->secure = (bool)$secure;
}
/**
* Is cookie sent with HTTP protocol only?
* @return bool
*/
public function getHttpOnly() {
return $this->httponly;
}
/**
* Set whether cookie is sent with HTTP protocol only
* @param bool $httponly
* @return void
*/
public function setHttpOnly( $httponly ) {
$this->httponly = (bool)$httponly;
}
}

401
Slim/Http/CookieJar.php Normal file
View File

@ -0,0 +1,401 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.5.0
*
* 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.
*/
/**
* Cooke Jar
*
* Used to manage signed, encrypted Cookies. Provides:
*
* - Cookie integrity and authenticity with HMAC
* - Confidentiality with symmetric encryption
* - Protection from replay attack if using SSL or TLS
* - Protection from interception if using SSL or TLS
*
* This code was originally called "BigOrNot_CookieManager" and written by
* Matthieu Huguet released under "CopyLeft" license. I have cleaned up the
* code formatting to conform with Slim Framework contributor guidelines and
* added additional code where necessary to play nice with Slim Cookie objects.
*
* Requirements:
*
* - libmcrypt > 2.4.x
*
* @author Matthies Huguet <http://bigornot.blogspot.com/2008/06/security-cookies-and-rest.html>
*/
class Slim_Http_CookieJar {
/**
* @var string Server secret key
*/
protected $_secret = '';
/**
* @var int Cryptographic algorithm used to encrypt cookies data
*/
protected $_algorithm = MCRYPT_RIJNDAEL_256;
/**
* @var int Cryptographic mode (CBC, CFB ...)
*/
protected $_mode = MCRYPT_MODE_CBC;
/**
* @var resource mcrypt module resource
*/
protected $_cryptModule = null;
/**
* @var bool Enable high confidentiality for cookie value (symmetric encryption)
*/
protected $_highConfidentiality = true;
/**
* @var bool Enable SSL support
*/
protected $_ssl = false;
/**
* @var array[Cookie] Cookie objects
*/
protected $_cookies = array();
/**
* Constructor
*
* Initialize cookie manager and mcrypt module.
*
* @param string $secret Server's secret key
* @param array $config
* @throws Exception If secret key is empty
* @throws Exception If unable to open mcypt module
*/
public function __construct( $secret, $config = null ) {
if ( empty($secret) ) {
throw new Exception('You must provide a secret key');
}
$this->_secret = $secret;
if ( $config !== null && !is_array($config) ) {
throw new Exception('Config must be an array');
}
if ( is_array($config) ) {
if ( isset($config['high_confidentiality']) ) {
$this->_highConfidentiality = $config['high_confidentiality'];
}
if ( isset($config['mcrypt_algorithm']) ) {
$this->_algorithm = $config['mcrypt_algorithm'];
}
if ( isset($config['mcrypt_mode']) ) {
$this->_mode = $config['mcrypt_mode'];
}
if ( isset($config['enable_ssl']) ) {
$this->_ssl = $config['enable_ssl'];
}
}
if ( extension_loaded('mcrypt') ) {
$this->_cryptModule = mcrypt_module_open($this->_algorithm, '', $this->_mode, '');
if ( $this->_cryptModule === false ) {
throw new Exception('Error while loading mcrypt module');
}
}
}
/**
* Get the high confidentiality mode
*
* @return bool TRUE if cookie data encryption is enabled, or FALSE if it isn't
*/
public function getHighConfidentiality() {
return $this->_highConfidentiality;
}
/**
* Enable or disable cookie data encryption
*
* @param bool $enable TRUE to enable, FALSE to disable
* @return CookieJar
*/
public function setHighConfidentiality( $enable ) {
$this->_highConfidentiality = (bool)$enable;
return $this;
}
/**
* Get the SSL status (enabled or disabled?)
*
* @return bool TRUE if SSL support is enabled, or FALSE if it isn't
*/
public function getSSL() {
return $this->_ssl;
}
/**
* Enable SSL support (not enabled by default)
*
* Pro: Protect against replay attack
* Con: Cookie's lifetime is limited to SSL session's lifetime
*
* @param bool $enable TRUE to enable, FALSE to disable
* @return CookieJar
*/
public function setSSL( $enable ) {
$this->_ssl = (bool)$enable;
return $this;
}
/**
* Get Cookies for Response
*
* @author Josh Lockhart <info@joshlockhart.com>
* @return array[Cookie]
*/
public function getResponseCookies() {
return $this->_cookies;
}
/**
* Get Cookie with name for Response
*
* @author Josh Lockhart <info@joshlockhart.com>
* @param string $cookiename The name of the Cookie
* @return Cookie|null Cookie, or NULL if Cookie with name not found
*/
public function getResponseCookie( $cookiename ) {
return isset($this->_cookies[$cookiename]) ? $this->_cookies[$cookiename] : null;
}
/**
* Set a secure cookie
*
* @param string $name Cookie name
* @param string $value Cookie value
* @param string $username User identifier
* @param integer $expire Expiration time
* @param string $path Cookie path
* @param string $domain Cookie domain
* @param bool $secure When TRUE, send the cookie only on a secure connection
* @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
*/
public function setCookie( $cookiename, $value, $username, $expire = 0, $path = '/', $domain = '', $secure = false, $httponly = null ) {
$secureValue = extension_loaded('mcrypt') ? $this->_secureCookieValue($value, $username, $expire) : $value;
$this->setClassicCookie($cookiename, $secureValue, $expire, $path, $domain, $secure, $httponly);
}
/**
* Delete a cookie
*
* @param string $name Cookie name
* @param string $path Cookie path
* @param string $domain Cookie domain
* @param bool $secure When TRUE, send the cookie only on a secure connection
* @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
*/
public function deleteCookie( $name, $path = '/', $domain = '', $secure = false, $httponly = null ) {
$expire = 315554400; /* 1980-01-01 */
$this->_cookies[$name] = new Slim_Http_Cookie($name, '', $expire, $path, $domain, $secure, $httponly);
//setcookie($name, '', $expire, $path, $domain, $secure, $httponly);
}
/**
* Get a secure cookie value
*
* Verify the integrity of cookie data and decrypt it. If the cookie
* is invalid, it can be automatically destroyed (default behaviour)
*
* @param string $cookiename Cookie name
* @param bool $delete Destroy the cookie if invalid?
* @return string|false The Cookie value, or FALSE if Cookie invalid
*/
public function getCookieValue( $cookiename, $deleteIfInvalid = true ) {
if ( $this->cookieExists($cookiename) ) {
if ( extension_loaded('mcrypt') ) {
$cookieValues = explode('|', $_COOKIE[$cookiename]);
if ( (count($cookieValues) === 4) && ($cookieValues[1] == 0 || $cookieValues[1] >= time()) ) {
$key = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1], $this->_secret);
$cookieData = base64_decode($cookieValues[2]);
if ( $cookieData !== '' && $this->getHighConfidentiality() ) {
$data = $this->_decrypt($cookieData, $key, md5($cookieValues[1]));
} else {
$data = $cookieData;
}
if ( $this->_ssl && isset($_SERVER['SSL_SESSION_ID']) ) {
$verifKey = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1] . $data . $_SERVER['SSL_SESSION_ID'], $key);
} else {
$verifKey = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1] . $data, $key);
}
if ( $verifKey == $cookieValues[3] ) {
return $data;
}
}
} else {
return $_COOKIE[$cookiename];
}
}
if ( $deleteIfInvalid ) {
$this->deleteCookie($cookiename);
}
return false;
}
/**
* Send a classic (unsecure) cookie
*
* @param string $name Cookie name
* @param string $value Cookie value
* @param integer $expire Expiration time
* @param string $path Cookie path
* @param string $domain Cookie domain
* @param bool $secure When TRUE, send the cookie only on a secure connection
* @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
*/
public function setClassicCookie( $cookiename, $value, $expire = 0, $path = '/', $domain = '', $secure = false, $httponly = null ) {
/* httponly option is only available for PHP version >= 5.2 */
if ( $httponly === null ) {
$this->_cookies[$cookiename] = new Slim_Http_Cookie($cookiename, $value, $expire, $path, $domain, $secure);
//setcookie($cookiename, $value, $expire, $path, $domain, $secure);
} else {
$this->_cookies[$cookiename] = new Slim_Http_Cookie($cookiename, $value, $expire, $path, $domain, $secure, $httponly);
//setcookie($cookiename, $value, $expire, $path, $domain, $secure, $httponly);
}
}
/**
* Verify if a cookie exists
*
* @param string $cookiename
* @return bool TRUE if cookie exist, or FALSE if not
*/
public function cookieExists($cookiename) {
return isset($_COOKIE[$cookiename]);
}
/**
* Secure a cookie value
*
* The initial value is transformed with this protocol:
*
* secureValue = username|expire|base64((value)k,expire)|HMAC(user|expire|value,k)
* where k = HMAC(user|expire, sk)
* and sk is server's secret key
* (value)k,md5(expire) is the result an cryptographic function (ex: AES256) on "value" with key k and initialisation vector = md5(expire)
*
* @param string $value Unsecure value
* @param string $username User identifier
* @param integer $expire Expiration time
* @return string Secured value
*/
protected function _secureCookieValue( $value, $username, $expire ) {
if ( is_string($expire) ) {
$expire = strtotime($expire);
}
$key = hash_hmac('sha1', $username . $expire, $this->_secret);
if ( $value !== '' && $this->getHighConfidentiality() ) {
$encryptedValue = base64_encode($this->_encrypt($value, $key, md5($expire)));
} else {
$encryptedValue = base64_encode($value);
}
if ( $this->_ssl && isset($_SERVER['SSL_SESSION_ID']) ) {
$verifKey = hash_hmac('sha1', $username . $expire . $value . $_SERVER['SSL_SESSION_ID'], $key);
} else {
$verifKey = hash_hmac('sha1', $username . $expire . $value, $key);
}
$result = array($username, $expire, $encryptedValue, $verifKey);
return implode('|', $result);
}
/**
* Encrypt a given data with a given key and a given initialisation vector
*
* @param string $data Data to crypt
* @param string $key Secret key
* @param string $iv Initialisation vector
* @return string Encrypted data
*/
protected function _encrypt( $data, $key, $iv ) {
$iv = $this->_validateIv($iv);
$key = $this->_validateKey($key);
mcrypt_generic_init($this->_cryptModule, $key, $iv);
$res = @mcrypt_generic($this->_cryptModule, $data);
mcrypt_generic_deinit($this->_cryptModule);
return $res;
}
/**
* Decrypt a given data with a given key and a given initialisation vector
*
* @param string $data Data to crypt
* @param string $key Secret key
* @param string $iv Initialisation vector
* @return string Encrypted data
*/
protected function _decrypt( $data, $key, $iv ) {
$iv = $this->_validateIv($iv);
$key = $this->_validateKey($key);
mcrypt_generic_init($this->_cryptModule, $key, $iv);
$decryptedData = mdecrypt_generic($this->_cryptModule, $data);
$res = str_replace("\x0", '', $decryptedData);
mcrypt_generic_deinit($this->_cryptModule);
return $res;
}
/**
* Validate Initialization vector
*
* If given IV is too long for the selected mcrypt algorithm, it will be truncated
*
* @param string $iv Initialization vector
* @return string
*/
protected function _validateIv($iv) {
$ivSize = mcrypt_enc_get_iv_size($this->_cryptModule);
if ( strlen($iv) > $ivSize ) {
$iv = substr($iv, 0, $ivSize);
}
return $iv;
}
/**
* Validate key
*
* If given key is too long for the selected mcrypt algorithm, it will be truncated
*
* @param string $key key
* @param string
*/
protected function _validateKey($key) {
$keySize = mcrypt_enc_get_key_size($this->_cryptModule);
if ( strlen($key) > $keySize ) {
$key = substr($key, 0, $keySize);
}
return $key;
}
}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,20 +29,24 @@
* 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 Request
* Request
*
* This class provides a human-friendly interface to the Slim environment variables;
* environment variables are passed by reference and will be modified directly.
* Object-oriented representation of an HTTP request. This class
* is responsible for parsing the raw HTTP request into a format
* usable by the Slim application.
*
* This class will automatically remove slashes from GET, POST, PUT,
* and Cookie data if magic quotes are enabled.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @author Kris Jordan <http://www.github.com/KrisJordan>
* @since Version 1.0
*/
class Request
{
class Slim_Http_Request {
const METHOD_HEAD = 'HEAD';
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
@ -53,533 +56,350 @@ class Request
const METHOD_OVERRIDE = '_METHOD';
/**
* @var array
* @var string Request method (ie. "GET", "POST", "PUT", "DELETE", "HEAD")
*/
protected static $formDataMediaTypes = array('application/x-www-form-urlencoded');
protected $method;
/**
* @var array
* @var array Key-value array of HTTP request headers
*/
protected $env;
protected $headers;
/**
* @var array Names of additional headers to parse from the current
* HTTP request that are not prefixed with "HTTP_"
*/
protected $additionalHeaders = array('content-type', 'content-length', 'php-auth-user', 'php-auth-pw', 'auth-type', 'x-requested-with');
/**
* @var array Key-value array of cookies sent with the
* current HTTP request
*/
protected $cookies;
/**
* @var array Key-value array of HTTP GET parameters
*/
protected $get;
/**
* @var array Key-value array of HTTP POST parameters
*/
protected $post;
/**
* @var array Key-value array of HTTP PUT parameters
*/
protected $put;
/**
* @var string Raw body of HTTP request
*/
protected $body;
/**
* @var string Content type of HTTP request
*/
protected $contentType;
/**
* @var string Resource URI (ie. "/person/1")
*/
protected $resource;
/**
* @var string The root URI of the Slim application without trailing slash.
* This will be "" if the app is installed at the web
* document root. If the app is installed in a
* sub-directory "/foo", this will be "/foo".
*/
protected $root;
/**
* Constructor
* @param array $env
* @see \Slim\Environment
*/
public function __construct($env)
{
$this->env = $env;
}
/**
* Get HTTP method
* @return string
*/
public function getMethod()
{
return $this->env['REQUEST_METHOD'];
public function __construct() {
$this->method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : false;
$this->headers = $this->loadHttpHeaders();
$this->body = @file_get_contents('php://input');
$this->get = self::stripSlashesIfMagicQuotes($_GET);
$this->post = self::stripSlashesIfMagicQuotes($_POST);
$this->put = self::stripSlashesIfMagicQuotes($this->loadPutParameters());
$this->cookies = self::stripSlashesIfMagicQuotes($_COOKIE);
$this->root = Slim_Http_Uri::getBaseUri(true);
$this->resource = Slim_Http_Uri::getUri(true);
$this->checkForHttpMethodOverride();
}
/**
* Is this a GET request?
* @return bool
*/
public function isGet()
{
return $this->getMethod() === self::METHOD_GET;
public function isGet() {
return $this->method === self::METHOD_GET;
}
/**
* Is this a POST request?
* @return bool
*/
public function isPost()
{
return $this->getMethod() === self::METHOD_POST;
public function isPost() {
return $this->method === self::METHOD_POST;
}
/**
* Is this a PUT request?
* @return bool
*/
public function isPut()
{
return $this->getMethod() === self::METHOD_PUT;
public function isPut() {
return $this->method === self::METHOD_PUT;
}
/**
* Is this a DELETE request?
* @return bool
*/
public function isDelete()
{
return $this->getMethod() === self::METHOD_DELETE;
public function isDelete() {
return $this->method === self::METHOD_DELETE;
}
/**
* Is this a HEAD request?
* @return bool
*/
public function isHead()
{
return $this->getMethod() === self::METHOD_HEAD;
public function isHead() {
return $this->method === self::METHOD_HEAD;
}
/**
* Is this a OPTIONS request?
* @return bool
*/
public function isOptions()
{
return $this->getMethod() === self::METHOD_OPTIONS;
public function isOptions() {
return $this->method === self::METHOD_OPTIONS;
}
/**
* Is this an AJAX request?
* Is this a XHR request?
* @return bool
*/
public function isAjax()
{
if ($this->params('isajax')) {
return true;
} elseif (isset($this->env['X_REQUESTED_WITH']) && $this->env['X_REQUESTED_WITH'] === 'XMLHttpRequest') {
return true;
} else {
return false;
}
public function isAjax() {
return ( $this->params('isajax') || $this->headers('X_REQUESTED_WITH') === 'XMLHttpRequest' );
}
/**
* Is this an XHR request? (alias of Slim_Http_Request::isAjax)
* @return bool
* Fetch a PUT|POST|GET parameter value
*
* The preferred method to fetch the value of a
* PUT, POST, or GET parameter (searched in that order).
*
* @param string $key The paramter name
* @return string|null The value of parameter, or NULL if parameter not found
*/
public function isXhr()
{
return $this->isAjax();
public function params( $key ) {
foreach ( array('put', 'post', 'get') as $dataSource ) {
$source = $this->$dataSource;
if ( isset($source[(string)$key]) ) {
return $source[(string)$key];
}
}
/**
* Fetch GET and POST data
*
* This method returns a union of GET and POST data as a key-value array, or the value
* of the array key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|mixed|null
*/
public function params($key = null)
{
$union = array_merge($this->get(), $this->post());
if ($key) {
if (isset($union[$key])) {
return $union[$key];
} else {
return null;
}
} else {
return $union;
}
/**
* Fetch GET parameter(s)
* @param string $key Name of parameter
* @return array|string|null All parameters, parameter value if $key
* and parameter exists, or NULL if $key
* and parameter does not exist.
*/
public function get( $key = null ) {
return $this->arrayOrArrayValue($this->get, $key);
}
/**
* Fetch GET data
*
* This method returns a key-value array of data sent in the HTTP request query string, or
* the value of the array key if requested; if the array key does not exist, NULL is returned.
*
* Fetch POST parameter(s)
* @param string $key Name of parameter
* @return array|string|null All parameters, parameter value if $key
* and parameter exists, or NULL if $key
* and parameter does not exist.
*/
public function post( $key = null ) {
return $this->arrayOrArrayValue($this->post, $key);
}
/**
* Fetch PUT parameter(s)
* @param string $key Name of parameter
* @return array|string|null All parameters, parameter value if $key
* and parameter exists, or NULL if $key
* and parameter does not exist.
*/
public function put( $key = null ) {
return $this->arrayOrArrayValue($this->put, $key);
}
/**
* Fetch COOKIE value(s)
* @param string $key The cookie name
* @return array|string|null All parameters, parameter value if $key
* and parameter exists, or NULL if $key
* and parameter does not exist.
*/
public function cookies( $key = null ) {
return $this->arrayOrArrayValue($this->cookies, $key);
}
/**
* Get HTTP request header
* @param string $key The header name
* @return array|string|null All parameters, parameter value if $key
* and parameter exists, or NULL if $key
* and parameter does not exist.
*/
public function headers( $key = null ) {
return is_null($key) ? $this->headers : $this->arrayOrArrayValue($this->headers, $this->convertHttpHeaderName($key));
}
/**
* Get HTTP request body
* @return string|false String, or FALSE if body could not be read
*/
public function getBody() {
return $this->body;
}
/**
* Get HTTP method
* @return string
*/
public function getMethod() {
return $this->method;
}
/**
* Get HTTP request content type
* @return string
*/
public function getContentType() {
if ( !isset($this->contentType) ) {
$contentType = 'application/x-www-form-urlencoded';
$header = $this->headers('CONTENT_TYPE');
if ( !is_null($header) ) {
$headerParts = preg_split('/\s*;\s*/', $header);
$contentType = $headerParts[0];
}
$this->contentType = $contentType;
}
return $this->contentType;
}
/**
* Get HTTP request resource URI
* @return string
*/
public function getResourceUri() {
return $this->resource;
}
/**
* Get HTTP request root URI
* @return string
*/
public function getRootUri() {
return $this->root;
}
/**
* Fetch array or array value
* @param array $array
* @param string $key
* @return array|mixed|null
* @return array|mixed Array if key is null, else array value
*/
public function get($key = null)
{
if (!isset($this->env['slim.request.query_hash'])) {
$output = array();
if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) {
mb_parse_str($this->env['QUERY_STRING'], $output);
} else {
parse_str($this->env['QUERY_STRING'], $output);
protected function arrayOrArrayValue( array &$array, $key = null ) {
return is_null($key) ? $array : $this->arrayValueForKey($array, $key);
}
$this->env['slim.request.query_hash'] = Util::stripSlashesIfMagicQuotes($output);
/**
* Fetch value from array
* @return mixed|null
*/
protected function arrayValueForKey( array &$array, $key ) {
return isset($array[(string)$key]) ? $array[(string)$key] : null;
}
if ($key) {
if (isset($this->env['slim.request.query_hash'][$key])) {
return $this->env['slim.request.query_hash'][$key];
/**
* Strip slashes from string or array of strings
* @param array|string $rawData
* @return array|string
*/
public static function stripSlashesIfMagicQuotes( $rawData ) {
if ( get_magic_quotes_gpc() ) {
return is_array($rawData) ? array_map(array('self', 'stripSlashesIfMagicQuotes'), $rawData) : stripslashes($rawData);
} else {
return null;
}
} else {
return $this->env['slim.request.query_hash'];
return $rawData;
}
}
/**
* Fetch POST data
*
* This method returns a key-value array of data sent in the HTTP request body, or
* the value of a hash key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|mixed|null
* @throws \RuntimeException If environment input is not available
* Get PUT parameters
* @return array Key-value array of HTTP request PUT parameters
*/
public function post($key = null)
{
if (!isset($this->env['slim.input'])) {
throw new \RuntimeException('Missing slim.input in environment variables');
}
if (!isset($this->env['slim.request.form_hash'])) {
$this->env['slim.request.form_hash'] = array();
if ($this->isFormData() && is_string($this->env['slim.input'])) {
$output = array();
if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) {
mb_parse_str($this->env['slim.input'], $output);
protected function loadPutParameters() {
if ( $this->getContentType() === 'application/x-www-form-urlencoded' ) {
$input = is_string($this->body) ? $this->body : '';
if ( function_exists('mb_parse_str') ) {
mb_parse_str($input, $output);
} else {
parse_str($this->env['slim.input'], $output);
parse_str($input, $output);
}
$this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($output);
return $output;
} else {
$this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($_POST);
}
}
if ($key) {
if (isset($this->env['slim.request.form_hash'][$key])) {
return $this->env['slim.request.form_hash'][$key];
} else {
return null;
}
} else {
return $this->env['slim.request.form_hash'];
return array();
}
}
/**
* Fetch PUT data (alias for \Slim\Http\Request::post)
* @param string $key
* @return array|mixed|null
* Get HTTP request headers
* @return array Key-value array of HTTP request headers
*/
public function put($key = null)
{
return $this->post($key);
}
/**
* Fetch DELETE data (alias for \Slim\Http\Request::post)
* @param string $key
* @return array|mixed|null
*/
public function delete($key = null)
{
return $this->post($key);
}
/**
* Fetch COOKIE data
*
* This method returns a key-value array of Cookie data sent in the HTTP request, or
* the value of a array key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|string|null
*/
public function cookies($key = null)
{
if (!isset($this->env['slim.request.cookie_hash'])) {
$cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : '';
$this->env['slim.request.cookie_hash'] = Util::parseCookieHeader($cookieHeader);
}
if ($key) {
if (isset($this->env['slim.request.cookie_hash'][$key])) {
return $this->env['slim.request.cookie_hash'][$key];
} else {
return null;
}
} else {
return $this->env['slim.request.cookie_hash'];
}
}
/**
* Does the Request body contain parseable form data?
* @return bool
*/
public function isFormData()
{
$method = isset($this->env['slim.method_override.original_method']) ? $this->env['slim.method_override.original_method'] : $this->getMethod();
return ($method === self::METHOD_POST && is_null($this->getContentType())) || in_array($this->getMediaType(), self::$formDataMediaTypes);
}
/**
* Get Headers
*
* This method returns a key-value array of headers sent in the HTTP request, or
* the value of a hash key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @param mixed $default The default value returned if the requested header is not available
* @return mixed
*/
public function headers($key = null, $default = null)
{
if ($key) {
$key = strtoupper($key);
$key = str_replace('-', '_', $key);
$key = preg_replace('@^HTTP_@', '', $key);
if (isset($this->env[$key])) {
return $this->env[$key];
} else {
return $default;
}
} else {
protected function loadHttpHeaders() {
$headers = array();
foreach ($this->env as $key => $value) {
if (strpos($key, 'slim.') !== 0) {
$headers[$key] = $value;
foreach ( $_SERVER as $key => $value ) {
$key = $this->convertHttpHeaderName($key);
if ( strpos($key, 'http-') === 0 || in_array($key, $this->additionalHeaders) ) {
$name = str_replace('http-', '', $key);
$headers[$name] = $value;
}
}
return $headers;
}
}
/**
* Get Body
* Convert HTTP header name
* @return string
*/
public function getBody()
{
return $this->env['slim.input'];
protected function convertHttpHeaderName( $name ) {
return str_replace('_', '-', strtolower($name));
}
/**
* Get Content Type
* @return string
* Check for HTTP request method override
*
* Because traditional web browsers do not support PUT and DELETE
* HTTP methods, we use a hidden form input field to
* mimic PUT and DELETE requests. We check for this override here.
*
* @return void
*/
public function getContentType()
{
if (isset($this->env['CONTENT_TYPE'])) {
return $this->env['CONTENT_TYPE'];
} else {
return null;
protected function checkForHttpMethodOverride() {
if ( isset($this->post[self::METHOD_OVERRIDE]) ) {
$this->method = $this->post[self::METHOD_OVERRIDE];
unset($this->post[self::METHOD_OVERRIDE]);
if ( $this->isPut() ) {
$this->put = $this->post;
}
}
}
/**
* Get Media Type (type/subtype within Content Type header)
* @return string|null
*/
public function getMediaType()
{
$contentType = $this->getContentType();
if ($contentType) {
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
return strtolower($contentTypeParts[0]);
} else {
return null;
}
}
/**
* Get Media Type Params
* @return array
*/
public function getMediaTypeParams()
{
$contentType = $this->getContentType();
$contentTypeParams = array();
if ($contentType) {
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
$contentTypePartsLength = count($contentTypeParts);
for ($i = 1; $i < $contentTypePartsLength; $i++) {
$paramParts = explode('=', $contentTypeParts[$i]);
$contentTypeParams[strtolower($paramParts[0])] = $paramParts[1];
}
}
return $contentTypeParams;
}
/**
* Get Content Charset
* @return string|null
*/
public function getContentCharset()
{
$mediaTypeParams = $this->getMediaTypeParams();
if (isset($mediaTypeParams['charset'])) {
return $mediaTypeParams['charset'];
} else {
return null;
}
}
/**
* Get Content-Length
* @return int
*/
public function getContentLength()
{
if (isset($this->env['CONTENT_LENGTH'])) {
return (int) $this->env['CONTENT_LENGTH'];
} else {
return 0;
}
}
/**
* Get Host
* @return string
*/
public function getHost()
{
if (isset($this->env['HOST'])) {
if (strpos($this->env['HOST'], ':') !== false) {
$hostParts = explode(':', $this->env['HOST']);
return $hostParts[0];
}
return $this->env['HOST'];
} else {
return $this->env['SERVER_NAME'];
}
}
/**
* Get Host with Port
* @return string
*/
public function getHostWithPort()
{
return sprintf('%s:%s', $this->getHost(), $this->getPort());
}
/**
* Get Port
* @return int
*/
public function getPort()
{
return (int) $this->env['SERVER_PORT'];
}
/**
* Get Scheme (https or http)
* @return string
*/
public function getScheme()
{
return $this->env['slim.url_scheme'];
}
/**
* Get Script Name (physical path)
* @return string
*/
public function getScriptName()
{
return $this->env['SCRIPT_NAME'];
}
/**
* LEGACY: Get Root URI (alias for Slim_Http_Request::getScriptName)
* @return string
*/
public function getRootUri()
{
return $this->getScriptName();
}
/**
* Get Path (physical path + virtual path)
* @return string
*/
public function getPath()
{
return $this->getScriptName() . $this->getPathInfo();
}
/**
* Get Path Info (virtual path)
* @return string
*/
public function getPathInfo()
{
return $this->env['PATH_INFO'];
}
/**
* LEGACY: Get Resource URI (alias for Slim_Http_Request::getPathInfo)
* @return string
*/
public function getResourceUri()
{
return $this->getPathInfo();
}
/**
* Get URL (scheme + host [ + port if non-standard ])
* @return string
*/
public function getUrl()
{
$url = $this->getScheme() . '://' . $this->getHost();
if (($this->getScheme() === 'https' && $this->getPort() !== 443) || ($this->getScheme() === 'http' && $this->getPort() !== 80)) {
$url .= sprintf(':%s', $this->getPort());
}
return $url;
}
/**
* Get IP
* @return string
*/
public function getIp()
{
if (isset($this->env['X_FORWARDED_FOR'])) {
return $this->env['X_FORWARDED_FOR'];
} elseif (isset($this->env['CLIENT_IP'])) {
return $this->env['CLIENT_IP'];
}
return $this->env['REMOTE_ADDR'];
}
/**
* Get Referrer
* @return string|null
*/
public function getReferrer()
{
if (isset($this->env['REFERER'])) {
return $this->env['REFERER'];
} else {
return null;
}
}
/**
* Get Referer (for those who can't spell)
* @return string|null
*/
public function getReferer()
{
return $this->getReferrer();
}
/**
* Get User Agent
* @return string|null
*/
public function getUserAgent()
{
if (isset($this->env['USER_AGENT'])) {
return $this->env['USER_AGENT'];
} else {
return null;
}
}
}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,40 +29,54 @@
* 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;
/**
* Response
*
* This is a simple abstraction over top an HTTP response. This
* provides methods to set the HTTP status, the HTTP headers,
* and the HTTP body.
* Object-oriented representation of an HTTP response that is
* returned to the client. This class is responsible for:
*
* - HTTP response status
* - HTTP response body
* - HTTP response headers
* - HTTP response cookies
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @author Kris Jordan <http://github.com/KrisJordan>
* @since Version 1.0
*/
class Response implements \ArrayAccess, \Countable, \IteratorAggregate
{
class Slim_Http_Response {
/**
* @var Slim_Http_Request
*/
protected $request;
/**
* @var string
*/
protected $httpVersion = '1.1';
/**
* @var int HTTP status code
*/
protected $status;
protected $status = 200;
/**
* @var \Slim\Http\Headers List of HTTP response headers
* @var array Key-value array of HTTP response headers
*/
protected $header;
protected $headers = array();
/**
* @var string HTTP response body
*/
protected $body;
protected $body = '';
/**
* @var int Length of HTTP response body
*/
protected $length;
protected $length = 0;
/**
* @var array HTTP response codes and messages
@ -120,340 +133,189 @@ class Response implements \ArrayAccess, \Countable, \IteratorAggregate
);
/**
* Constructor
* @param string $body The HTTP response body
* @param int $status The HTTP response status
* @param \Slim\Http\Headers|array $header The HTTP response headers
* @var CookieJar Manages Cookies to be sent with this Response
*/
public function __construct($body = '', $status = 200, $header = array())
{
$this->status = (int) $status;
$headers = array();
foreach ($header as $key => $value) {
$headers[$key] = $value;
}
$this->header = new Headers(array_merge(array('Content-Type' => 'text/html'), $headers));
$this->body = '';
$this->write($body);
protected $cookieJar;
/**
* Constructor
*/
public function __construct( Slim_Http_Request $req ) {
$this->request = $req;
$this->header('Content-Type', 'text/html');
}
/**
* Get and set status
* @param int|null $status
* @return int
* Set and/or get the HTTP response version
* @param string $version
* @return void
* @throws InvalidArgumentException If argument is not a valid HTTP version
*/
public function status($status = null)
{
if (!is_null($status)) {
$this->status = (int) $status;
public function httpVersion( $version = null ) {
if ( $version ) {
$version = (string)$version;
if ( $version === '1.0' || $version === '1.1' ) {
$this->httpVersion = $version;
} else {
throw new InvalidArgumentException('Invalid HTTP version in Response object');
}
}
return $this->httpVersion;
}
/**
* Set and/or get the HTTP response status code
* @param int $status
* @return int
* @throws InvalidArgumentException If argument is not a valid HTTP status code
*/
public function status( $status = null ) {
if ( !is_null($status) ) {
if ( !in_array(intval($status), array_keys(self::$messages)) ) {
throw new InvalidArgumentException('Cannot set Response status. Provided status code "' . $status . '" is not a valid HTTP response code.');
}
$this->status = intval($status);
}
return $this->status;
}
/**
* Get and set header
* @param string $name Header name
* @param string|null $value Header value
* @return string Header value
* Get HTTP response headers
* @return array
*/
public function header($name, $value = null)
{
public function headers() {
return $this->headers;
}
/**
* Get and/or set an HTTP response header
* @param string $key The header name
* @param string $value The header value
* @return string|null The header value, or NULL if header not set
*/
public function header( $key, $value = null ) {
if ( !is_null($value) ) {
$this[$name] = $value;
$this->headers[$key] = $value;
}
return $this[$name];
return isset($this->headers[$key]) ? $this->headers[$key] : null;
}
/**
* Get headers
* @return \Slim\Http\Headers
* Set the HTTP response body
* @param string $body The new HTTP response body
* @return string The new HTTP response body
*/
public function headers()
{
return $this->header;
}
/**
* Get and set body
* @param string|null $body Content of HTTP response body
* @return string
*/
public function body($body = null)
{
public function body( $body = null ) {
if ( !is_null($body) ) {
$this->write($body, true);
$this->body = '';
$this->length = 0;
$this->write($body);
}
return $this->body;
}
/**
* Get and set length
* @param int|null $length
* @return int
*/
public function length($length = null)
{
if (!is_null($length)) {
$this->length = (int) $length;
}
return $this->length;
}
/**
* Append HTTP response body
* Append the HTTP response body
* @param string $body Content to append to the current HTTP response body
* @param bool $replace Overwrite existing response body?
* @return string The updated HTTP response body
*/
public function write($body, $replace = false)
{
if ($replace) {
$this->body = $body;
} else {
$this->body .= (string) $body;
}
$this->length = strlen($this->body);
return $this->body;
public function write( $body ) {
$body = (string)$body;
$this->length += strlen($body);
$this->body .= $body;
$this->header('Content-Length', $this->length);
return $body;
}
/**
* Finalize
*
* This prepares this response and returns an array
* of [status, headers, body]. This array is passed to outer middleware
* if available or directly to the Slim run method.
*
* @return array[int status, array headers, string body]
* Set cookie jar
* @param Slim_Http_CookieJar $cookieJar
* @return void
*/
public function finalize()
{
public function setCookieJar( Slim_Http_CookieJar $cookieJar ) {
$this->cookieJar = $cookieJar;
}
/**
* Get cookie jar
* @return Slim_Http_CookieJar
*/
public function getCookieJar() {
return $this->cookieJar;
}
/**
* Finalize response headers before response is sent
* @return void
*/
public function finalize() {
if ( in_array($this->status, array(204, 304)) ) {
unset($this['Content-Type'], $this['Content-Length']);
return array($this->status, $this->header, '');
} else {
return array($this->status, $this->header, $this->body);
$this->body('');
unset($this->headers['Content-Type']);
}
}
/**
* Set cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
* header on its own and delegates this responsibility to the `Slim_Http_Util` class. This
* response's header is passed by reference to the utility class and is directly modified. By not
* relying on PHP's native implementation, Slim allows middleware the opportunity to massage or
* analyze the raw header before the response is ultimately delivered to the HTTP client.
*
* @param string $name The name of the cookie
* @param string|array $value If string, the value of cookie; if array, properties for
* cookie including: value, expire, path, domain, secure, httponly
*/
public function setCookie($name, $value)
{
Util::setCookieHeader($this->header, $name, $value);
}
/**
* Delete cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
* header on its own and delegates this responsibility to the `Slim_Http_Util` class. This
* response's header is passed by reference to the utility class and is directly modified. By not
* relying on PHP's native implementation, Slim allows middleware the opportunity to massage or
* analyze the raw header before the response is ultimately delivered to the HTTP client.
*
* This method will set a cookie with the given name that has an expiration time in the past; this will
* prompt the HTTP client to invalidate and remove the client-side cookie. Optionally, you may
* also pass a key/value array as the second argument. If the "domain" key is present in this
* array, only the Cookie with the given name AND domain will be removed. The invalidating cookie
* sent with this response will adopt all properties of the second argument.
*
* @param string $name The name of the cookie
* @param array $value Properties for cookie including: value, expire, path, domain, secure, httponly
*/
public function deleteCookie($name, $value = array())
{
Util::deleteCookieHeader($this->header, $name, $value);
}
/**
* Redirect
*
* This method prepares this response to return an HTTP Redirect response
* to the HTTP client.
*
* @param string $url The redirect destination
* @param int $status The redirect HTTP status code
*/
public function redirect ($url, $status = 302)
{
$this->status = $status;
$this['Location'] = $url;
}
/**
* Helpers: Empty?
* @return bool
*/
public function isEmpty()
{
return in_array($this->status, array(201, 204, 304));
}
/**
* Helpers: Informational?
* @return bool
*/
public function isInformational()
{
return $this->status >= 100 && $this->status < 200;
}
/**
* Helpers: OK?
* @return bool
*/
public function isOk()
{
return $this->status === 200;
}
/**
* Helpers: Successful?
* @return bool
*/
public function isSuccessful()
{
return $this->status >= 200 && $this->status < 300;
}
/**
* Helpers: Redirect?
* @return bool
*/
public function isRedirect()
{
return in_array($this->status, array(301, 302, 303, 307));
}
/**
* Helpers: Redirection?
* @return bool
*/
public function isRedirection()
{
return $this->status >= 300 && $this->status < 400;
}
/**
* Helpers: Forbidden?
* @return bool
*/
public function isForbidden()
{
return $this->status === 403;
}
/**
* Helpers: Not Found?
* @return bool
*/
public function isNotFound()
{
return $this->status === 404;
}
/**
* Helpers: Client error?
* @return bool
*/
public function isClientError()
{
return $this->status >= 400 && $this->status < 500;
}
/**
* Helpers: Server Error?
* @return bool
*/
public function isServerError()
{
return $this->status >= 500 && $this->status < 600;
}
/**
* Array Access: Offset Exists
*/
public function offsetExists( $offset )
{
return isset($this->header[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet( $offset )
{
if (isset($this->header[$offset])) {
return $this->header[$offset];
} else {
return null;
}
}
/**
* Array Access: Offset Set
*/
public function offsetSet($offset, $value)
{
$this->header[$offset] = $value;
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset($offset)
{
unset($this->header[$offset]);
}
/**
* Countable: Count
*/
public function count()
{
return count($this->header);
}
/**
* Get Iterator
*
* This returns the contained `\Slim\Http\Headers` instance which
* is itself iterable.
*
* @return \Slim\Http\Headers
*/
public function getIterator()
{
return $this->header;
}
/**
* Get message for HTTP status code
* @return string|null
*/
public static function getMessageForCode($status)
{
if (isset(self::$messages[$status])) {
return self::$messages[$status];
public static function getMessageForCode( $status ) {
return isset(self::$messages[$status]) ? self::$messages[$status] : null;
}
/**
* Can this HTTP response have a body?
* @return bool
*/
public function canHaveBody() {
return ( $this->status < 100 || $this->status >= 200 ) && $this->status != 204 && $this->status != 304;
}
/**
* Send headers for HTTP response
* @return void
*/
protected function sendHeaders() {
//Finalize response
$this->finalize();
if ( substr(PHP_SAPI, 0, 3) === 'cgi') {
//Send Status header if running with fastcgi
header('Status: ' . self::getMessageForCode($this->status()));
} else {
return null;
//Else send HTTP message
header(sprintf('HTTP/%s %s', $this->httpVersion, self::getMessageForCode($this->status())));
}
//Send headers
foreach ( $this->headers() as $name => $value ) {
header("$name: $value");
}
//Send cookies
foreach ( $this->getCookieJar()->getResponseCookies() as $name => $cookie ) {
setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpires(), $cookie->getPath(), $cookie->getDomain(), $cookie->getSecure(), $cookie->getHttpOnly());
}
//Flush all output to client
flush();
}
/**
* Send HTTP response
*
* This method will set Response headers, set Response cookies,
* and `echo` the Response body to the current output buffer.
*
* @return void
*/
public function send() {
if ( !headers_sent() ) {
$this->sendHeaders();
}
if ( $this->canHaveBody() && $this->request->isHead() === false ) {
echo $this->body;
}
}
}

131
Slim/Http/Uri.php Normal file
View File

@ -0,0 +1,131 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.5.0
*
* 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.
*/
/**
* Uri
*
* Parses base uri and application uri from Request.
*
* @package Slim
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Slim_Http_Uri {
/**
* @var string "https" or "http"
*/
protected static $scheme;
/**
* @var string
*/
protected static $baseUri;
/**
* @var string
*/
protected static $uri;
/**
* @var string The URI query string, excluding leading "?"
*/
protected static $queryString;
/**
* Get Base URI without trailing slash
* @param bool $reload Force reparse the base URI?
* @return string
*/
public static function getBaseUri( $reload = false ) {
if ( $reload || is_null(self::$baseUri) ) {
$requestUri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF']; //Full Request URI
$scriptName = $_SERVER['SCRIPT_NAME']; //Script path from docroot
$baseUri = strpos($requestUri, $scriptName) === 0 ? $scriptName : str_replace('\\', '/', dirname($scriptName));
self::$baseUri = rtrim($baseUri, '/');
}
return self::$baseUri;
}
/**
* Get URI with leading slash
* @param bool $reload Force reparse the URI?
* @return string
* @throws RuntimeException If unable if unable to determine URI
*/
public static function getUri( $reload = false ) {
if ( $reload || is_null(self::$uri) ) {
$uri = '';
if ( !empty($_SERVER['PATH_INFO']) ) {
$uri = $_SERVER['PATH_INFO'];
} else {
if ( isset($_SERVER['REQUEST_URI']) ) {
$uri = parse_url(self::getScheme() . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
} else if ( isset($_SERVER['PHP_SELF']) ) {
$uri = $_SERVER['PHP_SELF'];
} else {
throw new RuntimeException('Unable to detect request URI');
}
}
if ( self::getBaseUri() !== '' && strpos($uri, self::getBaseUri()) === 0 ) {
$uri = substr($uri, strlen(self::getBaseUri()));
}
self::$uri = '/' . ltrim($uri, '/');
}
return self::$uri;
}
/**
* Get URI Scheme
* @param bool $reload For reparse the URL scheme?
* @return string "https" or "http"
*/
public static function getScheme( $reload = false ) {
if ( $reload || is_null(self::$scheme) ) {
self::$scheme = ( empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ) ? 'http' : 'https';
}
return self::$scheme;
}
/**
* Get URI Query String
* @param bool $reload For reparse the URL query string?
* @return string
*/
public static function getQueryString( $reload = false ) {
if ( $reload || is_null(self::$queryString) ) {
self::$queryString = $_SERVER['QUERY_STRING'];
}
return self::$queryString;
}
}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,14 +29,12 @@
* 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
* Log Adapter
*
* 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:
* This is an adapter for your own custom Logger. This adapter assumes
* your custom Logger provides the following public instance methods:
*
* debug( mixed $object )
* info( mixed $object )
@ -45,75 +42,39 @@ namespace Slim;
* error( mixed $object )
* fatal( mixed $object )
*
* 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.
* This class assumes nothing else about your custom Logger, so you are free
* to use Apache's Log4PHP logger or any other log class that, at the
* very least, implements the five public instance methods shown above.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Log
{
const FATAL = 0;
const ERROR = 1;
const WARN = 2;
const INFO = 3;
const DEBUG = 4;
class Slim_Log {
/**
* @var array
* @var mixed An object that implements expected Logger interface
*/
protected static $levels = array(
self::FATAL => 'FATAL',
self::ERROR => 'ERROR',
self::WARN => 'WARN',
self::INFO => 'INFO',
self::DEBUG => 'DEBUG'
);
protected $logger;
/**
* @var mixed
*/
protected $writer;
/**
* @var bool
* @var bool Enable logging?
*/
protected $enabled;
/**
* @var int
*/
protected $level;
/**
* Constructor
* @param mixed $writer
*/
public function __construct($writer)
{
$this->writer = $writer;
public function __construct() {
$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
* @return void
*/
public function setEnabled($enabled)
{
public function setEnabled( $enabled ) {
if ( $enabled ) {
$this->enabled = true;
} else {
@ -121,52 +82,11 @@ class Log
}
}
/**
* 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()
{
public function isEnabled() {
return $this->enabled;
}
@ -175,9 +95,8 @@ class Log
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function debug($object)
{
return $this->log($object, self::DEBUG);
public function debug( $object ) {
return isset($this->logger) && $this->isEnabled() ? $this->logger->debug($object) : false;
}
/**
@ -185,9 +104,8 @@ class Log
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function info($object)
{
return $this->log($object, self::INFO);
public function info( $object ) {
return isset($this->logger) && $this->isEnabled() ? $this->logger->info($object) : false;
}
/**
@ -195,9 +113,8 @@ class Log
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function warn($object)
{
return $this->log($object, self::WARN);
public function warn( $object ) {
return isset($this->logger) && $this->isEnabled() ? $this->logger->warn($object) : false;
}
/**
@ -205,9 +122,8 @@ class Log
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function error($object)
{
return $this->log($object, self::ERROR);
public function error( $object ) {
return isset($this->logger) && $this->isEnabled() ? $this->logger->error($object) : false;
}
/**
@ -215,23 +131,25 @@ class Log
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function fatal($object)
{
return $this->log($object, self::FATAL);
public function fatal( $object ) {
return isset($this->logger) && $this->isEnabled() ? $this->logger->fatal($object) : false;
}
/**
* Log message
* @param mixed The object to log
* @param int The message level
* @return int|false
* Set Logger
* @param mixed $logger
* @return void
*/
protected function log($object, $level)
{
if ($this->enabled && $this->writer && $level <= $this->level) {
return $this->writer->write($object, $level);
} else {
return false;
public function setLogger( $logger ) {
$this->logger = $logger;
}
/**
* Get Logger
* @return mixed
*/
public function getLogger() {
return $this->logger;
}
}

200
Slim/Logger.php Normal file
View File

@ -0,0 +1,200 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.5.0
*
* 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.
*/
/**
* Logger
*
* A simple Logger that writes to a daily-unique log file in
* a user-specified directory. By default, this class will write log
* messages for all log levels; the log level may be changed to filter
* unwanted log messages from the log file.
*
* @package Slim
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Slim_Logger {
/**
* @var array Log levels
*/
protected $levels = array(
0 => 'FATAL',
1 => 'ERROR',
2 => 'WARN',
3 => 'INFO',
4 => 'DEBUG'
);
/**
* @var string Absolute path to log directory with trailing slash
*/
protected $directory;
/**
* Constructor
* @param string $directory Absolute or relative path to log directory
* @param int $level The maximum log level reported by this Logger
*/
public function __construct( $directory, $level = 4 ) {
$this->setDirectory($directory);
$this->setLevel($level);
}
/**
* Set log directory
* @param string $directory Absolute or relative path to log directory
* @return void
*/
public function setDirectory( $directory ) {
$realPath = realpath($directory);
if ( $realPath ) {
$this->directory = rtrim($realPath, '/') . '/';
} else {
$this->directory = false;
}
}
/**
* Get log directory
* @return string|false Absolute path to log directory with trailing slash
*/
public function getDirectory() {
return $this->directory;
}
/**
* Set log level
* @param int The maximum log level reported by this Logger
* @return void
* @throws InvalidArgumentException If level specified is not 0, 1, 2, 3, 4
*/
public function setLevel( $level ) {
$theLevel = (int)$level;
if ( $theLevel >= 0 && $theLevel <= 4 ) {
$this->level = $theLevel;
} else {
throw new InvalidArgumentException('Invalid Log Level. Must be one of: 0, 1, 2, 3, 4.');
}
}
/**
* Get log level
* @return int
*/
public function getLevel() {
return $this->level;
}
/**
* Log debug data
* @param mixed $data
* @return void
*/
public function debug( $data ) {
$this->log($data, 4);
}
/**
* Log info data
* @param mixed $data
* @return void
*/
public function info( $data ) {
$this->log($data, 3);
}
/**
* Log warn data
* @param mixed $data
* @return void
*/
public function warn( $data ) {
$this->log($data, 2);
}
/**
* Log error data
* @param mixed $data
* @return void
*/
public function error( $data ) {
$this->log($data, 1);
}
/**
* Log fatal data
* @param mixed $data
* @return void
*/
public function fatal( $data ) {
$this->log($data, 0);
}
/**
* Get absolute path to current daily log file
* @return string
*/
public function getFile() {
return $this->getDirectory() . strftime('%Y-%m-%d') . '.log';
}
/**
* Log data to file
* @param mixed $data
* @param int $level
* @return void
* @throws RuntimeException If log directory not found or not writable
*/
protected function log( $data, $level ) {
$dir = $this->getDirectory();
if ( $dir == false || !is_dir($dir) ) {
throw new RuntimeException("Log directory '$dir' invalid.");
}
if ( !is_writable($dir) ) {
throw new RuntimeException("Log directory '$dir' not writable.");
}
if ( $level <= $this->getLevel() ) {
$this->write(sprintf("[%s] %s - %s\r\n", $this->levels[$level], date('c'), (string)$data));
}
}
/**
* Persist data to log
* @param string Log message
* @return void
*/
protected function write( $data ) {
@file_put_contents($this->getFile(), $data, FILE_APPEND | LOCK_EX);
}
}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,23 +29,23 @@
* 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;
/**
* Route
*
* @package Slim
* @author Josh Lockhart, Thomas Bley
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Route
{
class Slim_Route {
/**
* @var string The route pattern (e.g. "/books/:id")
* @var string The route pattern (ie. "/books/:id")
*/
protected $pattern;
/**
* @var mixed The route callable
* @var mixed The callable associated with this route
*/
protected $callable;
@ -56,7 +55,7 @@ class Route
protected $conditions = array();
/**
* @var array Default conditions applied to all route instances
* @var array Default conditions applied to all Route instances
*/
protected static $defaultConditions = array();
@ -70,33 +69,27 @@ class Route
*/
protected $params = array();
/**
* @var array value array of URL parameter names
*/
protected $paramNames = array();
/**
* @var array key array of URL parameter names with + at the end
*/
protected $paramNamesPath = array();
/**
* @var array HTTP methods supported by this Route
*/
protected $methods = array();
/**
* @var array[Callable] Middleware to be run before only this route instance
* @var Slim_Router The Router to which this Route belongs
*/
protected $router;
/**
* @var array[Callable] Middleware
*/
protected $middleware = array();
/**
* Constructor
* @param string $pattern The URL pattern (e.g. "/books/:id")
* @param string $pattern The URL pattern (ie. "/books/:id")
* @param mixed $callable Anything that returns TRUE for is_callable()
*/
public function __construct($pattern, $callable)
{
public function __construct( $pattern, $callable ) {
$this->setPattern($pattern);
$this->setCallable($callable);
$this->setConditions(self::getDefaultConditions());
@ -105,9 +98,9 @@ class Route
/**
* Set default route conditions for all instances
* @param array $defaultConditions
* @return void
*/
public static function setDefaultConditions(array $defaultConditions)
{
public static function setDefaultConditions( array $defaultConditions ) {
self::$defaultConditions = $defaultConditions;
}
@ -115,8 +108,7 @@ class Route
* Get default route conditions for all instances
* @return array
*/
public static function getDefaultConditions()
{
public static function getDefaultConditions() {
return self::$defaultConditions;
}
@ -124,35 +116,33 @@ class Route
* Get route pattern
* @return string
*/
public function getPattern()
{
public function getPattern() {
return $this->pattern;
}
/**
* Set route pattern
* @param string $pattern
* @return void
*/
public function setPattern($pattern)
{
$this->pattern = $pattern;
public function setPattern( $pattern ) {
$this->pattern = str_replace(')', ')?', (string)$pattern);
}
/**
* Get route callable
* @return mixed
*/
public function getCallable()
{
public function getCallable() {
return $this->callable;
}
/**
* Set route callable
* @param mixed $callable
* @return void
*/
public function setCallable($callable)
{
public function setCallable($callable) {
$this->callable = $callable;
}
@ -160,17 +150,16 @@ class Route
* Get route conditions
* @return array
*/
public function getConditions()
{
public function getConditions() {
return $this->conditions;
}
/**
* Set route conditions
* @param array $conditions
* @return void
*/
public function setConditions(array $conditions)
{
public function setConditions( array $conditions ) {
$this->conditions = $conditions;
}
@ -178,72 +167,33 @@ class Route
* Get route name
* @return string|null
*/
public function getName()
{
public function getName() {
return $this->name;
}
/**
* Set route name
* @param string $name
* @return void
*/
public function setName($name)
{
public function setName( $name ) {
$this->name = (string)$name;
$this->router->cacheNamedRoute($this->name, $this);
}
/**
* Get route parameters
* @return array
*/
public function getParams()
{
public function getParams() {
return $this->params;
}
/**
* Set route parameters
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* Get route parameter value
* @param string $index Name of URL parameter
* @return string
* @throws \InvalidArgumentException If route parameter does not exist at index
*/
public function getParam($index)
{
if (!isset($this->params[$index])) {
throw new \InvalidArgumentException('Route parameter does not exist at specified index');
}
return $this->params[$index];
}
/**
* Set route parameter value
* @param string $index Name of URL parameter
* @param mixed $value The new parameter value
* @throws \InvalidArgumentException If route parameter does not exist at index
*/
public function setParam($index, $value)
{
if (!isset($this->params[$index])) {
throw new \InvalidArgumentException('Route parameter does not exist at specified index');
}
$this->params[$index] = $value;
}
/**
* Add supported HTTP method(s)
* @return void
*/
public function setHttpMethods()
{
public function setHttpMethods() {
$args = func_get_args();
$this->methods = $args;
}
@ -252,29 +202,26 @@ class Route
* Get supported HTTP methods
* @return array
*/
public function getHttpMethods()
{
public function getHttpMethods() {
return $this->methods;
}
/**
* Append supported HTTP methods
* @return void
*/
public function appendHttpMethods()
{
public function appendHttpMethods() {
$args = func_get_args();
$this->methods = array_merge($this->methods, $args);
}
/**
* Append supported HTTP methods (alias for Route::appendHttpMethods)
* @return \Slim\Route
* @return Slim_Route
*/
public function via()
{
public function via() {
$args = func_get_args();
$this->methods = array_merge($this->methods, $args);
return $this;
}
@ -282,17 +229,32 @@ class Route
* Detect support for an HTTP method
* @return bool
*/
public function supportsHttpMethod($method)
{
public function supportsHttpMethod( $method ) {
return in_array($method, $this->methods);
}
/**
* Get router
* @return Slim_Router
*/
public function getRouter() {
return $this->router;
}
/**
* Set router
* @param Slim_Router $router
* @return void
*/
public function setRouter( Slim_Router $router ) {
$this->router = $router;
}
/**
* Get middleware
* @return array[Callable]
*/
public function getMiddleware()
{
public function getMiddleware() {
return $this->middleware;
}
@ -305,22 +267,20 @@ class Route
* assume the argument is an array of callables and merge the array
* with `$this->middleware`. Even if non-callables are included in the
* argument array, we still merge them; we lazily check each item
* against `is_callable` during Router::dispatch().
* against `is_callable` during Route::dispatch().
*
* @param Callable|array[Callable]
* @return \Slim\Route
* @throws \InvalidArgumentException If argument is not callable or not an array
* @return Slim_Route
* @throws InvalidArgumentException If argument is not callable or not an array
*/
public function setMiddleware($middleware)
{
public function setMiddleware( $middleware ) {
if ( is_callable($middleware) ) {
$this->middleware[] = $middleware;
} else if ( is_array($middleware) ) {
$this->middleware = array_merge($this->middleware, $middleware);
} else {
throw new \InvalidArgumentException('Route middleware must be callable or an array of callables');
throw new InvalidArgumentException('Route middleware must be callable or an array of callables');
}
return $this;
}
@ -335,73 +295,104 @@ class Route
* @param string $resourceUri A Request URI
* @return bool
*/
public function matches($resourceUri)
{
//Convert URL params into regex patterns, construct a regex for this route, init params
$patternAsRegex = preg_replace_callback('#:([\w]+)\+?#', array($this, 'matchesCallback'),
str_replace(')', ')?', (string) $this->pattern));
public function matches( $resourceUri ) {
//Extract URL params
preg_match_all('@:([\w]+)@', $this->pattern, $paramNames, PREG_PATTERN_ORDER);
$paramNames = $paramNames[0];
//Convert URL params into regex patterns, construct a regex for this route
$patternAsRegex = preg_replace_callback('@:[\w]+@', array($this, 'convertPatternToRegex'), $this->pattern);
if ( substr($this->pattern, -1) === '/' ) {
$patternAsRegex .= '?';
$patternAsRegex = $patternAsRegex . '?';
}
$patternAsRegex = '@^' . $patternAsRegex . '$@';
//Cache URL params' names and values if this route matches the current HTTP request
if (!preg_match('#^' . $patternAsRegex . '$#', $resourceUri, $paramValues)) {
if ( preg_match($patternAsRegex, $resourceUri, $paramValues) ) {
array_shift($paramValues);
foreach ( $paramNames as $index => $value ) {
$val = substr($value, 1);
if ( isset($paramValues[$val]) ) {
$this->params[$val] = urldecode($paramValues[$val]);
}
}
return true;
} else {
return false;
}
foreach ($this->paramNames as $name) {
if (isset($paramValues[$name])) {
if (isset($this->paramNamesPath[ $name ])) {
$this->params[$name] = explode('/', urldecode($paramValues[$name]));
} else {
$this->params[$name] = urldecode($paramValues[$name]);
}
}
}
return true;
}
/**
* Convert a URL parameter (e.g. ":id", ":id+") into a regular expression
* Convert a URL parameter (ie. ":id") into a regular expression
* @param array URL parameters
* @return string Regular expression for URL parameter
*/
protected function matchesCallback($m)
{
$this->paramNames[] = $m[1];
if (isset($this->conditions[ $m[1] ])) {
return '(?P<' . $m[1] . '>' . $this->conditions[ $m[1] ] . ')';
protected function convertPatternToRegex( $matches ) {
$key = str_replace(':', '', $matches[0]);
if ( array_key_exists($key, $this->conditions) ) {
return '(?P<' . $key . '>' . $this->conditions[$key] . ')';
} else {
return '(?P<' . $key . '>[a-zA-Z0-9_\-\.\!\~\*\\\'\(\)\:\@\&\=\$\+,%]+)';
}
if (substr($m[0], -1) === '+') {
$this->paramNamesPath[ $m[1] ] = 1;
return '(?P<' . $m[1] . '>.+)';
}
return '(?P<' . $m[1] . '>[^/]+)';
}
/**
* Set route name
* @param string $name The name of the route
* @return \Slim\Route
* @return Slim_Route
*/
public function name($name)
{
public function name( $name ) {
$this->setName($name);
return $this;
}
/**
* Merge route conditions
* @param array $conditions Key-value array of URL parameter conditions
* @return \Slim\Route
* @return Slim_Route
*/
public function conditions(array $conditions)
{
public function conditions( array $conditions ) {
$this->conditions = array_merge($this->conditions, $conditions);
return $this;
}
/**
* Dispatch route
*
* This method invokes this route's callable. If middleware is
* registered for this route, each callable middleware is invoked in
* the order specified.
*
* This method is smart about trailing slashes on the route pattern.
* If this route's pattern is defined with a trailing slash, and if the
* current request URI does not have a trailing slash but otherwise
* matches this route's pattern, a Slim_Exception_RequestSlash
* will be thrown triggering an HTTP 301 Permanent Redirect to the same
* URI _with_ a trailing slash. This Exception is caught in the
* `Slim::run` loop. If this route's pattern is defined without a
* trailing slash, and if the current request URI does have a trailing
* slash, this route will not be matched and a 404 Not Found
* response will be sent if no subsequent matching routes are found.
*
* @return bool Was route callable invoked successfully?
* @throws Slim_Exception_RequestSlash
*/
public function dispatch() {
if ( substr($this->pattern, -1) === '/' && substr($this->router->getRequest()->getResourceUri(), -1) !== '/' ) {
throw new Slim_Exception_RequestSlash();
}
//Invoke middleware
foreach ( $this->middleware as $mw ) {
if ( is_callable($mw) ) {
call_user_func($mw);
}
}
//Invoke callable
if ( is_callable($this->getCallable()) ) {
call_user_func_array($this->callable, array_values($this->params));
return true;
}
return false;
}
}

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,41 +29,43 @@
* 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;
/**
* Router
*
* This class organizes, iterates, and dispatches \Slim\Route objects.
* Responsible for registering route paths with associated callables.
* When a Slim application is run, the Router finds a matching Route for
* the current HTTP request, and if a matching route is found, executes
* the Route's associated callable passing it parameters from the Request URI.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class Router implements \Iterator
{
/**
* @var string Request URI
*/
protected $resourceUri;
class Slim_Router implements IteratorAggregate {
/**
* @var array Lookup hash of all route objects
* @var Slim_Http_Request
*/
protected $request;
/**
* @var array Lookup hash of routes, keyed by Request method
*/
protected $routes;
/**
* @var array Lookup hash of named route objects, keyed by route name (lazy-loaded)
* @var array Lookup hash of named routes, keyed by route name
*/
protected $namedRoutes;
/**
* @var array Array of route objects that match the request URI (lazy-loaded)
* @var array Array of routes that match the Request method and URL
*/
protected $matchedRoutes;
/**
* @var mixed Callable to be invoked if no matching route objects are found
* @var mixed Callable to be invoked if no matching routes are found
*/
protected $notFound;
@ -75,193 +76,104 @@ class Router implements \Iterator
/**
* Constructor
* @param Slim_Http_Request $request The HTTP request object
*/
public function __construct()
{
public function __construct( Slim_Http_Request $request ) {
$this->request = $request;
$this->routes = array();
}
/**
* Set Resource URI
*
* This method injects the current request's resource URI. This method should be invoked
* only immediately before router iteration.
*
* @param string $uri The request URI
* Get Iterator
* @return ArrayIterator
*/
public function setResourceUri($uri)
{
$this->resourceUri = $uri;
public function getIterator() {
return new ArrayIterator($this->getMatchedRoutes());
}
/**
* Get Current Route object
* @return \Slim\Route|false
* Get Request
* @return Slim_Http_Request
*/
public function getCurrentRoute()
{
$this->getMatchedRoutes(); // <-- Parse if not already parsed
return $this->current();
public function getRequest() {
return $this->request;
}
/**
* Return route objects that match the current request URI
* @param bool $reload Should matching routes be re-parsed?
* @return array[\Slim\Route]
* Set Request
* @param Slim_Http_Request $req
* @return void
*/
public function getMatchedRoutes($reload = false)
{
public function setRequest( Slim_Http_Request $req ) {
$this->request = $req;
}
/**
* Return routes that match the current request
* @return array[Slim_Route]
*/
public function getMatchedRoutes( $reload = false ) {
if ( $reload || is_null($this->matchedRoutes) ) {
$this->matchedRoutes = array();
foreach ( $this->routes as $route ) {
if ($route->matches($this->resourceUri)) {
if ( $route->matches($this->request->getResourceUri()) ) {
$this->matchedRoutes[] = $route;
}
}
}
return $this->matchedRoutes;
}
/**
* Map a route object to a callback function
* Map a route to a callback function
* @param string $pattern The URL pattern (ie. "/books/:id")
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return \Slim\Route
* @return Slim_Route
*/
public function map($pattern, $callable)
{
$route = new \Slim\Route($pattern, $callable);
public function map( $pattern, $callable ) {
$route = new Slim_Route($pattern, $callable);
$route->setRouter($this);
$this->routes[] = $route;
return $route;
}
/**
* Cache named route
* @param string $name The route name
* @param Slim_Route $route The route object
* @throws RuntimeException If a named route already exists with the same name
* @return void
*/
public function cacheNamedRoute( $name, Slim_Route $route ) {
if ( isset($this->namedRoutes[(string)$name]) ) {
throw new RuntimeException('Named route already exists with name: ' . $name);
}
$this->namedRoutes[$name] = $route;
}
/**
* Get URL for named route
* @param string $name The name of the route
* @param array Associative array of URL parameter names and replacement values
* @param array Associative array of URL parameter names and values
* @throws RuntimeException If named route not found
* @return string The URL for the given route populated with provided replacement values
* @return string The URL for the given route populated with the given parameters
*/
public function urlFor($name, $params = array())
{
if (!$this->hasNamedRoute($name)) {
throw new \RuntimeException('Named route not found for name: ' . $name);
public function urlFor( $name, $params = array() ) {
if ( !isset($this->namedRoutes[(string)$name]) ) {
throw new RuntimeException('Named route not found for name: ' . $name);
}
$search = array();
foreach (array_keys($params) as $key) {
$search[] = '#:' . $key . '\+?(?!\w)#';
$pattern = $this->namedRoutes[(string)$name]->getPattern();
$search = $replace = array();
foreach ( $params as $key => $value ) {
$search[] = ':' . $key;
$replace[] = $value;
}
$pattern = preg_replace($search, $params, $this->getNamedRoute($name)->getPattern());
$pattern = str_replace($search, $replace, $pattern);
//Remove remnants of unpopulated, trailing optional pattern segments
return preg_replace('#\(/?:.+\)|\(|\)#', '', $pattern);
}
/**
* Dispatch route
*
* This method invokes the route object's callable. If middleware is
* registered for the route, each callable middleware is invoked in
* the order specified.
*
* This method is smart about trailing slashes on the route pattern.
* If the route's pattern is defined with a trailing slash, and if the
* current request URI does not have a trailing slash but otherwise
* matches the route's pattern, a Slim_Exception_RequestSlash
* will be thrown triggering an HTTP 301 Permanent Redirect to the same
* URI _with_ a trailing slash. This Exception is caught in the
* `Slim::call` loop. If the route's pattern is defined without a
* trailing slash, and if the current request URI does have a trailing
* slash, the route will not be matched and a 404 Not Found
* response will be sent if no subsequent matching routes are found.
*
* @param \Slim\Route $route The route object
* @return bool Was route callable invoked successfully?
* @throws \Slim\Exception\RequestSlash
*/
public function dispatch(\Slim\Route $route)
{
if (substr($route->getPattern(), -1) === '/' && substr($this->resourceUri, -1) !== '/') {
throw new Exception\RequestSlash();
}
//Invoke middleware
foreach ($route->getMiddleware() as $mw) {
if (is_callable($mw)) {
call_user_func_array($mw, array($route));
}
}
//Invoke callable
if (is_callable($route->getCallable())) {
call_user_func_array($route->getCallable(), array_values($route->getParams()));
return true;
}
return false;
}
/**
* Add named route
* @param string $name The route name
* @param \Slim\Route $route The route object
* @throws \RuntimeException If a named route already exists with the same name
*/
public function addNamedRoute($name, \Slim\Route $route)
{
if ($this->hasNamedRoute($name)) {
throw new \RuntimeException('Named route already exists with name: ' . $name);
}
$this->namedRoutes[(string) $name] = $route;
}
/**
* Has named route
* @param string $name The route name
* @return bool
*/
public function hasNamedRoute($name)
{
$this->getNamedRoutes();
return isset($this->namedRoutes[(string) $name]);
}
/**
* Get named route
* @param string $name
* @return \Slim\Route|null
*/
public function getNamedRoute($name)
{
$this->getNamedRoutes();
if ($this->hasNamedRoute($name)) {
return $this->namedRoutes[(string) $name];
} else {
return null;
}
}
/**
* Get named routes
* @return \ArrayIterator
*/
public function getNamedRoutes()
{
if (is_null($this->namedRoutes)) {
$this->namedRoutes = array();
foreach ($this->routes as $route) {
if ($route->getName() !== null) {
$this->addNamedRoute($route->getName(), $route);
}
}
}
return new \ArrayIterator($this->namedRoutes);
return preg_replace(array(
'@\(\/?:.+\/??\)\??@',
'@\?|\(|\)@'
), '', $this->request->getRootUri() . $pattern);
}
/**
@ -269,12 +181,10 @@ class Router implements \Iterator
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return mixed
*/
public function notFound($callable = null)
{
public function notFound( $callable = null ) {
if ( is_callable($callable) ) {
$this->notFound = $callable;
}
return $this->notFound;
}
@ -283,55 +193,11 @@ class Router implements \Iterator
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return mixed
*/
public function error($callable = null)
{
public function error( $callable = null ) {
if ( is_callable($callable) ) {
$this->error = $callable;
}
return $this->error;
}
/**
* Iterator Interface: Rewind
*/
public function rewind()
{
reset($this->matchedRoutes);
}
/**
* Iterator Interface: Current
* @return \Slim\Route|false
*/
public function current()
{
return current($this->matchedRoutes);
}
/**
* Iterator Interface: Key
* @return int|null
*/
public function key()
{
return key($this->matchedRoutes);
}
/**
* Iterator Interface: Next
*/
public function next()
{
next($this->matchedRoutes);
}
/**
* Iterator Interface: Valid
* @return boolean
*/
public function valid()
{
return $this->current();
}
}

192
Slim/Session/Flash.php Normal file
View File

@ -0,0 +1,192 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.5.0
*
* 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.
*/
/**
* Flash Messaging
*
* This class enables Flash messaging. Messages are persisted in $_SESSION
* with a user-defined key.
*
* USAGE:
*
* 1. Set Flash message to be shown on the next request
*
* Slim::flash('error', 'The object could not be saved');
*
* 2. Set Flash message to be shown on the current request
*
* Slim::flashNow('error', 'The object could not be saved');
*
* 3. Keep old Flash messages for the next request
*
* Slim::flashKeep();
*
* @package Slim
* @author Josh Lockhart
* @since Version 1.3
*/
class Slim_Session_Flash implements ArrayAccess {
/**
* @var string Key used to identify flash information in $_SESSION array
*/
protected $sessionKey = 'flash';
/**
* @var array[array] Storage for flash messages
*/
protected $messages = array(
'prev' => array(), //flash messages from prev request
'next' => array(), //flash messages for next request
'now' => array() //flash messages for current request
);
/**
* Constructor
*
* Establishes Flash session key and loads existing
* Flash messages from the $_SESSION.
*
* @param string $sessionKey
* @return void
*/
public function __construct( $sessionKey = null ) {
if ( !is_null($sessionKey) ) {
$this->setSessionKey($sessionKey);
}
$this->load();
}
/**
* Set the $_SESSION key used to access Flash messages
* @param string $key
* @throws RuntimeException If session key is null
* @return Slim_Session_Flash
*/
public function setSessionKey( $key ) {
if ( is_null($key) ) {
throw new RuntimeException('Session key cannot be null');
}
$this->sessionKey = (string)$key;
return $this;
}
/**
* Get the $_SESSION key used to access Flash messages
* @return string
*/
public function getSessionKey() {
return $this->sessionKey;
}
/**
* Set a Flash message for the current request
* @param string $key
* @param string $value
* @return Slim_Session_Flash
*/
public function now( $key, $value ) {
$this->messages['now'][(string)$key] = $value;
return $this->save();
}
/**
* Set a Flash message for the next request
* @param string $key
* @param string $value
* @return Slim_Session_Flash
*/
public function set( $key, $value ) {
$this->messages['next'][(string)$key] = $value;
return $this->save();
}
/**
* Get Flash messages intended for the current request's View
* @return array[String]
*/
public function getMessages() {
return array_merge($this->messages['prev'], $this->messages['now']);
}
/**
* Load Flash messages from $_SESSION
* @return Slim_Session_Flash
*/
public function load() {
$this->messages['prev'] = isset($_SESSION[$this->sessionKey]) ? $_SESSION[$this->sessionKey] : array();
return $this;
}
/**
* Transfer Flash messages from the previous request
* so they are available to the next request.
* @return Slim_Session_Flash
*/
public function keep() {
foreach ( $this->messages['prev'] as $key => $val ) {
$this->messages['next'][$key] = $val;
}
return $this->save();
}
/**
* Save Flash messages to $_SESSION
* @return Slim_Session_Flash
*/
public function save() {
$_SESSION[$this->sessionKey] = $this->messages['next'];
return $this;
}
/***** ARRAY ACCESS INTERFACE *****/
public function offsetExists( $offset ) {
$messages = $this->getMessages();
return isset($messages[$offset]);
}
public function offsetGet( $offset ) {
$messages = $this->getMessages();
return isset($messages[$offset]) ? $messages[$offset] : null;
}
public function offsetSet( $offset, $value ) {
$this->now($offset, $value);
}
public function offsetUnset( $offset ) {
unset($this->messages['prev'][$offset]);
unset($this->messages['now'][$offset]);
}
}

125
Slim/Session/Handler.php Normal file
View File

@ -0,0 +1,125 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* 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.
*/
/**
* Abstract Session Handler
*
* This abstract class should be extended by each concrete
* session handler. This class defines the contractual class interface
* methods that must be implemented in concrete subclasses. This class
* also provides the final `register` method used by Slim itself to
* actually register the concrete session handler with PHP.
*
* @package Slim
* @author Josh Lockhart
* @since Version 1.3
*/
abstract class Slim_Session_Handler {
/**
* @var Slim
*/
protected $app;
/**
* Register session handler
*
* @return bool
*/
final public function register( Slim $app ) {
$this->app = $app;
return session_set_save_handler(
array($this, 'open'),
array($this, 'close'),
array($this, 'read'),
array($this, 'write'),
array($this, 'destroy'),
array($this, 'gc')
);
}
/**
* Open session
*
* @param string $savePath
* @param string $sessionName
* @return mixed
*/
abstract public function open( $savePath, $sessionName );
/**
* Close session
*
* @return mixed
*/
abstract public function close();
/**
* Read session data with ID
*
* @param string $id The session identifier
* @return string
*/
abstract public function read( $id );
/**
* Write session data with ID
*
* The "write" handler is not executed until after the output stream is
* closed. Thus, output from debugging statements in the "write" handler
* will never be seen in the browser. If debugging output is necessary, it
* is suggested that the debug output be written to a file instead.
*
* @param string $id The session identifier
* @param mixed $sessionData The session data
* @return mixed
*/
abstract public function write( $id, $sessionData );
/**
* Destroy session with ID
*
* @param string $id The session identifier
* @return mixed
*/
abstract public function destroy( $id );
/**
* Session garbage collection
*
* Executed when the PHP session garbage collector is invoked; should
* remove all session data older than the `$maxLifetime`.
*
* @param int $maxLifetime
* @return mixed
*/
abstract public function gc( $maxLifetime );
}

View File

@ -0,0 +1,71 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* 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.
*/
/**
* Session Cookie Handler
*
* This class is used as an adapter for PHP's $_SESSION handling.
* Session data will be written to and read from signed, encrypted
* cookies. If the current PHP installation does not have the `mcrypt`
* extension, session data will be written to signed but unencrypted
* cookies; however, the session cookies will still be secure and will
* become invalid if manually edited after set by PHP.
*
* @package Slim
* @author Josh Lockhart
* @since Version 1.3
*/
class Slim_Session_Handler_Cookies extends Slim_Session_Handler {
public function open( $savePath, $sessionName ) {
return true;
}
public function close() {
return true; //Not used
}
public function read( $id ) {
return $this->app->getEncryptedCookie($id);
}
public function write( $id, $sessionData ) {
$this->app->setEncryptedCookie($id, $sessionData, 0);
}
public function destroy( $id ) {
$this->app->deleteCookie($id);
}
public function gc( $maxLifetime ) {
return true; //Not used
}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,12 +2,11 @@
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @author Josh Lockhart <info@joshlockhart.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 2.0.0
* @package Slim
* @version 1.5.0
*
* MIT LICENSE
*
@ -30,62 +29,47 @@
* 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
* 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.
* The View is responsible for rendering and/or displaying a template.
* It is recommended that you subclass View and re-implement the
* `View::render` method to use a custom templating engine such as
* Smarty, Twig, Mustache, etc. It is important that `View::render`
* `return` the final template output. Do not `echo` the output.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
* @author Josh Lockhart <info@joshlockhart.com>
* @since Version 1.0
*/
class View
{
/**
* @var string Absolute or relative filesystem path to a specific template
*
* DEPRECATION WARNING!
* This variable will be removed in the near future
*/
protected $templatePath = '';
class Slim_View {
/**
* @var array Associative array of template variables
* @var array Key-value array of data available to the template
*/
protected $data = array();
/**
* @var string Absolute or relative path to the application's templates directory
* @var string Absolute or relative path to the templates directory
*/
protected $templatesDirectory;
/**
* Constructor
*
* This is empty but may be implemented in a subclass
* This is empty but may be overridden in a subclass
*/
public function __construct()
{
}
public function __construct() {}
/**
* Get data
* @param string|null $key
* @return mixed If key is null, array of template data;
* If key exists, value of datum with key;
* If key does not exist, null;
* @param string $key
* @return array|mixed|null All View data if no $key, value of datum
* if $key, or NULL if $key but datum
* does not exist.
*/
public function getData($key = null)
{
public function getData( $key = null ) {
if ( !is_null($key) ) {
return isset($this->data[$key]) ? $this->data[$key] : null;
} else {
@ -96,121 +80,88 @@ class View
/**
* Set data
*
* If two arguments:
* A single datum with key is assigned value;
* This method is overloaded to accept two different method signatures.
* You may use this to set a specific key with a specfic value,
* or you may use this to set all data to a specific array.
*
* $view->setData('color', 'red');
* USAGE:
*
* If one argument:
* Replace all data with provided array keys and values;
* View::setData('color', 'red');
* View::setData(array('color' => 'red', 'number' => 1));
*
* $view->setData(array('color' => 'red', 'number' => 1));
*
* @param mixed
* @param mixed
* @param string|array
* @param mixed Optional. Only use if first argument is a string.
* @return void
* @throws InvalidArgumentException If incorrect method signature
*/
public function setData()
{
public function setData() {
$args = func_get_args();
if ( count($args) === 1 && is_array($args[0]) ) {
$this->data = $args[0];
} else if ( count($args) === 2 ) {
$this->data[(string)$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, ... ]);`');
throw new InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`');
}
}
/**
* Append new data to existing template data
* @param array
* @throws InvalidArgumentException If not given an array argument
* Append data to existing View data
* @param array $data
* @return void
*/
public function appendData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
public function appendData( array $data ) {
$this->data = array_merge($this->data, $data);
}
/**
* Get templates directory
* @return string|null Path to templates directory without trailing slash;
* Returns null if templates directory not set;
* @return string|null Path to templates directory without trailing slash
*/
public function getTemplatesDirectory()
{
public function getTemplatesDirectory() {
return $this->templatesDirectory;
}
/**
* Set templates directory
* @param string $dir
* @return void
* @throws RuntimeException If directory is not a directory or does not exist
*/
public function setTemplatesDirectory($dir)
{
public function setTemplatesDirectory( $dir ) {
if ( !is_dir($dir) ) {
throw new RuntimeException('Cannot set View templates directory to: ' . $dir . '. Directory does not exist.');
}
$this->templatesDirectory = rtrim($dir, '/');
}
/**
* Set template
* @param string $template
* @throws RuntimeException If template file does not exist
*
* DEPRECATION WARNING!
* This method will be removed in the near future.
*/
public function setTemplate($template)
{
$this->templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
if (!file_exists($this->templatePath)) {
throw new \RuntimeException('View cannot render template `' . $this->templatePath . '`. Template does not exist.');
}
}
/**
* Display template
*
* This method echoes the rendered template to the current output buffer
*
* @param string $template Pathname of template file relative to templates directoy
* @param string $template Path to template file relative to templates directoy
* @return void
*/
public function display($template)
{
echo $this->fetch($template);
}
/**
* Fetch rendered template
*
* This method returns the rendered template
*
* @param string $template Pathname of template file relative to templates directory
* @return string
*/
public function fetch($template)
{
return $this->render($template);
public function display( $template ) {
echo $this->render($template);
}
/**
* Render template
*
* @param string $template Pathname of template file relative to templates directory
* @return string
*
* DEPRECATION WARNING!
* Use `\Slim\View::fetch` to return a rendered template instead of `\Slim\View::render`.
* @param string $template Path to template file relative to templates directory
* @return string Rendered template
* @throws RuntimeException If template does not exist
*/
public function render($template)
{
$this->setTemplate($template);
public function render( $template ) {
extract($this->data);
$templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
if ( !file_exists($templatePath) ) {
throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.');
}
ob_start();
require $this->templatePath;
require $templatePath;
return ob_get_clean();
}
}

24
aprs_func.php Normal file
View File

@ -0,0 +1,24 @@
<?php
function aprspass ($callsign) {
$stophere = strpos($callsign, '-');
if ($stophere) $callsign = substr($callsign, 0, $stophere);
$realcall = strtoupper(substr($callsign, 0, 10));
// initialize hash
$hash = 0x73e2;
$i = 0;
$len = strlen($realcall);
// hash callsign two bytes at a time
while ($i < $len) {
$hash ^= ord(substr($realcall, $i, 1))<<8;
$hash ^= ord(substr($realcall, $i + 1, 1));
$i += 2;
}
// mask off the high bit so number is always positive
return $hash & 0x7fff;
}
?>

24
index.php Normal file
View File

@ -0,0 +1,24 @@
<?php
// Load Slim
require 'Slim/Slim.php';
$app = new Slim();
// Functions
//GET route
$app->get('/', function () {
// Require HTML Template
require('templates/main.php');
});
$app->post('/passcode', function () {
require('aprs_func.php');
echo aprspass($_POST['callsign']);
});
// Run slim
$app->run();
?>

41
templates/main.php Normal file
View File

@ -0,0 +1,41 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>APRS Passcode Generator</title>
<style type="text/css" media="screen">
body {
font-family: Arial, "MS Trebuchet", sans-serif;
font-size: 14px;
background-color: whiteSmoke;
}
#container {
margin: 0 auto;
width: 400px;
padding: 10px;
border: 1px solid #E5E5E5;
background-color: #ffffff;
}
label {
width: 100%;
}
</style>
</head>
<body>
<div id="container">
<h1>APRS Passcode Generator</h1>
<form method="post" action="index.php/passcode">
<label for="callsign">Callsign</label>
<input type="text" name="callsign" value="" />
<input type="submit" name="Submit" value="Get Passcode" />
</form>
<p>Techical Example of Passcode Generation using PHP</p>
<p>Source code available on <a href="https://github.com/magicbug/PHP-APRS-Passcode" title="Github" target="_blank">Github</a></p>
</div>
</body>
</html>

0
templates/passcode.php Normal file
View File