diff options
Diffstat (limited to 'api/Slim/Http')
-rwxr-xr-x | api/Slim/Http/Cookie.php | 222 | ||||
-rwxr-xr-x | api/Slim/Http/CookieJar.php | 401 | ||||
-rwxr-xr-x | api/Slim/Http/Request.php | 405 | ||||
-rwxr-xr-x | api/Slim/Http/Response.php | 321 | ||||
-rwxr-xr-x | api/Slim/Http/Uri.php | 131 |
5 files changed, 1480 insertions, 0 deletions
diff --git a/api/Slim/Http/Cookie.php b/api/Slim/Http/Cookie.php new file mode 100755 index 0000000..ffb2881 --- /dev/null +++ b/api/Slim/Http/Cookie.php @@ -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; + } + +}
\ No newline at end of file diff --git a/api/Slim/Http/CookieJar.php b/api/Slim/Http/CookieJar.php new file mode 100755 index 0000000..f2f0305 --- /dev/null +++ b/api/Slim/Http/CookieJar.php @@ -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; + } + +} diff --git a/api/Slim/Http/Request.php b/api/Slim/Http/Request.php new file mode 100755 index 0000000..3880a53 --- /dev/null +++ b/api/Slim/Http/Request.php @@ -0,0 +1,405 @@ +<?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. + */ + +/** + * Request + * + * 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 <info@joshlockhart.com> + * @author Kris Jordan <http://www.github.com/KrisJordan> + * @since Version 1.0 + */ +class Slim_Http_Request { + + const METHOD_HEAD = 'HEAD'; + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; + const METHOD_PUT = 'PUT'; + const METHOD_DELETE = 'DELETE'; + const METHOD_OPTIONS = 'OPTIONS'; + const METHOD_OVERRIDE = '_METHOD'; + + /** + * @var string Request method (ie. "GET", "POST", "PUT", "DELETE", "HEAD") + */ + protected $method; + + /** + * @var array Key-value array of HTTP request headers + */ + 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 + */ + 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->method === self::METHOD_GET; + } + + /** + * Is this a POST request? + * @return bool + */ + public function isPost() { + return $this->method === self::METHOD_POST; + } + + /** + * Is this a PUT request? + * @return bool + */ + public function isPut() { + return $this->method === self::METHOD_PUT; + } + + /** + * Is this a DELETE request? + * @return bool + */ + public function isDelete() { + return $this->method === self::METHOD_DELETE; + } + + /** + * Is this a HEAD request? + * @return bool + */ + public function isHead() { + return $this->method === self::METHOD_HEAD; + } + + /** + * Is this a OPTIONS request? + * @return bool + */ + public function isOptions() { + return $this->method === self::METHOD_OPTIONS; + } + + /** + * Is this a XHR request? + * @return bool + */ + public function isAjax() { + return ( $this->params('isajax') || $this->headers('X_REQUESTED_WITH') === 'XMLHttpRequest' ); + } + + /** + * 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 params( $key ) { + foreach ( array('put', 'post', 'get') as $dataSource ) { + $source = $this->$dataSource; + if ( isset($source[(string)$key]) ) { + return $source[(string)$key]; + } + } + return null; + } + + /** + * 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 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 Array if key is null, else array value + */ + protected function arrayOrArrayValue( array &$array, $key = null ) { + return is_null($key) ? $array : $this->arrayValueForKey($array, $key); + } + + /** + * Fetch value from array + * @return mixed|null + */ + protected function arrayValueForKey( array &$array, $key ) { + return isset($array[(string)$key]) ? $array[(string)$key] : null; + } + + /** + * 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 $rawData; + } + } + + /** + * Get PUT parameters + * @return array Key-value array of HTTP request PUT parameters + */ + 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($input, $output); + } + return $output; + } else { + return array(); + } + } + + /** + * Get HTTP request headers + * @return array Key-value array of HTTP request headers + */ + protected function loadHttpHeaders() { + $headers = array(); + 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; + } + + /** + * Convert HTTP header name + * @return string + */ + protected function convertHttpHeaderName( $name ) { + return str_replace('_', '-', strtolower($name)); + } + + /** + * 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 + */ + 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; + } + } + } + +}
\ No newline at end of file diff --git a/api/Slim/Http/Response.php b/api/Slim/Http/Response.php new file mode 100755 index 0000000..5414edb --- /dev/null +++ b/api/Slim/Http/Response.php @@ -0,0 +1,321 @@ +<?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. + */ + +/** + * Response + * + * 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 <info@joshlockhart.com> + * @author Kris Jordan <http://github.com/KrisJordan> + * @since Version 1.0 + */ +class Slim_Http_Response { + + /** + * @var Slim_Http_Request + */ + protected $request; + + /** + * @var string + */ + protected $httpVersion = '1.1'; + + /** + * @var int HTTP status code + */ + protected $status = 200; + + /** + * @var array Key-value array of HTTP response headers + */ + protected $headers = array(); + + /** + * @var string HTTP response body + */ + protected $body = ''; + + /** + * @var int Length of HTTP response body + */ + protected $length = 0; + + /** + * @var array HTTP response codes and messages + */ + protected static $messages = array( + //Informational 1xx + 100 => '100 Continue', + 101 => '101 Switching Protocols', + //Successful 2xx + 200 => '200 OK', + 201 => '201 Created', + 202 => '202 Accepted', + 203 => '203 Non-Authoritative Information', + 204 => '204 No Content', + 205 => '205 Reset Content', + 206 => '206 Partial Content', + //Redirection 3xx + 300 => '300 Multiple Choices', + 301 => '301 Moved Permanently', + 302 => '302 Found', + 303 => '303 See Other', + 304 => '304 Not Modified', + 305 => '305 Use Proxy', + 306 => '306 (Unused)', + 307 => '307 Temporary Redirect', + //Client Error 4xx + 400 => '400 Bad Request', + 401 => '401 Unauthorized', + 402 => '402 Payment Required', + 403 => '403 Forbidden', + 404 => '404 Not Found', + 405 => '405 Method Not Allowed', + 406 => '406 Not Acceptable', + 407 => '407 Proxy Authentication Required', + 408 => '408 Request Timeout', + 409 => '409 Conflict', + 410 => '410 Gone', + 411 => '411 Length Required', + 412 => '412 Precondition Failed', + 413 => '413 Request Entity Too Large', + 414 => '414 Request-URI Too Long', + 415 => '415 Unsupported Media Type', + 416 => '416 Requested Range Not Satisfiable', + 417 => '417 Expectation Failed', + 422 => '422 Unprocessable Entity', + 423 => '423 Locked', + //Server Error 5xx + 500 => '500 Internal Server Error', + 501 => '501 Not Implemented', + 502 => '502 Bad Gateway', + 503 => '503 Service Unavailable', + 504 => '504 Gateway Timeout', + 505 => '505 HTTP Version Not Supported' + ); + + /** + * @var CookieJar Manages Cookies to be sent with this Response + */ + protected $cookieJar; + + /** + * Constructor + */ + public function __construct( Slim_Http_Request $req ) { + $this->request = $req; + $this->header('Content-Type', 'text/html'); + } + + /** + * 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 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 HTTP response headers + * @return array + */ + 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->headers[$key] = $value; + } + return isset($this->headers[$key]) ? $this->headers[$key] : null; + } + + /** + * Set the HTTP response body + * @param string $body The new HTTP response body + * @return string The new HTTP response body + */ + public function body( $body = null ) { + if ( !is_null($body) ) { + $this->body = ''; + $this->length = 0; + $this->write($body); + } + return $this->body; + } + + /** + * Append the HTTP response body + * @param string $body Content to append to the current HTTP response body + * @return string The updated HTTP response body + */ + public function write( $body ) { + $body = (string)$body; + $this->length += strlen($body); + $this->body .= $body; + $this->header('Content-Length', $this->length); + return $body; + } + + /** + * Set cookie jar + * @param Slim_Http_CookieJar $cookieJar + * @return void + */ + 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)) ) { + $this->body(''); + unset($this->headers['Content-Type']); + } + } + + /** + * Get message for HTTP status code + * @return string|null + */ + 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 { + //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; + } + } + +}
\ No newline at end of file diff --git a/api/Slim/Http/Uri.php b/api/Slim/Http/Uri.php new file mode 100755 index 0000000..dfe3448 --- /dev/null +++ b/api/Slim/Http/Uri.php @@ -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; + } + +}
\ No newline at end of file |