Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 3930296e5015150e2288336fd3f56b078aaaefe8 0 parents
@ccoenraets authored
Showing with 4,708 additions and 0 deletions.
  1. +57 −0 cellar.sql
  2. +10 −0 part1/api/.htaccess
  3. +45 −0 part1/api/Slim/Exception/Pass.php
  4. +46 −0 part1/api/Slim/Exception/RequestSlash.php
  5. +43 −0 part1/api/Slim/Exception/Stop.php
  6. +222 −0 part1/api/Slim/Http/Cookie.php
  7. +401 −0 part1/api/Slim/Http/CookieJar.php
  8. +405 −0 part1/api/Slim/Http/Request.php
  9. +321 −0 part1/api/Slim/Http/Response.php
  10. +131 −0 part1/api/Slim/Http/Uri.php
  11. +155 −0 part1/api/Slim/Log.php
  12. +200 −0 part1/api/Slim/Logger.php
  13. +398 −0 part1/api/Slim/Route.php
  14. +203 −0 part1/api/Slim/Router.php
  15. +192 −0 part1/api/Slim/Session/Flash.php
  16. +125 −0 part1/api/Slim/Session/Handler.php
  17. +71 −0 part1/api/Slim/Session/Handler/Cookies.php
  18. +1,174 −0 part1/api/Slim/Slim.php
  19. +167 −0 part1/api/Slim/View.php
  20. +131 −0 part1/api/index.php
  21. +78 −0 part1/css/styles.css
  22. +59 −0 part1/index.html
  23. +4 −0 part1/js/jquery-1.7.1.min.js
  24. +60 −0 part1/js/main.js
  25. BIN  part1/pics/block_nine.jpg
  26. BIN  part1/pics/bodega_lurton.jpg
  27. BIN  part1/pics/bouscat.jpg
  28. BIN  part1/pics/domaine_serene.jpg
  29. BIN  part1/pics/ex_umbris.jpg
  30. BIN  part1/pics/generic.jpg
  31. BIN  part1/pics/lan_rioja.jpg
  32. BIN  part1/pics/le_doyenne.jpg
  33. BIN  part1/pics/lurton-pinot-gris.jpg
  34. BIN  part1/pics/margerum.jpg
  35. BIN  part1/pics/morizottes.jpg
  36. BIN  part1/pics/rex_hill.jpg
  37. BIN  part1/pics/saint_cosme.jpg
  38. BIN  part1/pics/viticcio.jpg
  39. +10 −0 readme.md
57 cellar.sql
@@ -0,0 +1,57 @@
+-- MySQL dump 10.13 Distrib 5.5.15, for osx10.6 (i386)
+--
+-- Host: localhost Database: cellar
+-- ------------------------------------------------------
+-- Server version 5.5.15
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `wine`
+--
+
+DROP TABLE IF EXISTS `wine`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `wine` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(45) DEFAULT NULL,
+ `year` varchar(45) DEFAULT NULL,
+ `grapes` varchar(45) DEFAULT NULL,
+ `country` varchar(45) DEFAULT NULL,
+ `region` varchar(45) DEFAULT NULL,
+ `description` blob,
+ `picture` varchar(256) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `wine`
+--
+
+LOCK TABLES `wine` WRITE;
+/*!40000 ALTER TABLE `wine` DISABLE KEYS */;
+INSERT INTO `wine` VALUES (1,'CHATEAU DE SAINT COSME','2009','Grenache / Syrah','France','Southern Rhone / Gigondas','The aromas of fruit and spice give one a hint of the light drinkability of this lovely wine, which makes an excellent complement to fish dishes.','saint_cosme.jpg'),(2,'LAN RIOJA CRIANZA','2006','Tempranillo','Spain','Rioja','A resurgence of interest in boutique vineyards has opened the door for this excellent foray into the dessert wine market. Light and bouncy, with a hint of black truffle, this wine will not fail to tickle the taste buds.','lan_rioja.jpg'),(3,'MARGERUM SYBARITE','2010','Sauvignon Blanc','USA','California Central Cosat','The cache of a fine Cabernet in ones wine cellar can now be replaced with a childishly playful wine bubbling over with tempting tastes of\nblack cherry and licorice. This is a taste sure to transport you back in time.','margerum.jpg'),(4,'OWEN ROE \"EX UMBRIS\"','2009','Syrah','USA','Washington','A one-two punch of black pepper and jalapeno will send your senses reeling, as the orange essence snaps you back to reality. Don\'t miss\nthis award-winning taste sensation.','ex_umbris.jpg'),(5,'REX HILL','2009','Pinot Noir','USA','Oregon','One cannot doubt that this will be the wine served at the Hollywood award shows, because it has undeniable star power. Be the first to catch\nthe debut that everyone will be talking about tomorrow.','rex_hill.jpg'),(6,'VITICCIO CLASSICO RISERVA','2007','Sangiovese Merlot','Italy','Tuscany','Though soft and rounded in texture, the body of this wine is full and rich and oh-so-appealing. This delivery is even more impressive when one takes note of the tender tannins that leave the taste buds wholly satisfied.','viticcio.jpg'),(7,'CHATEAU LE DOYENNE','2005','Merlot','France','Bordeaux','Though dense and chewy, this wine does not overpower with its finely balanced depth and structure. It is a truly luxurious experience for the\nsenses.','le_doyenne.jpg'),(8,'DOMAINE DU BOUSCAT','2009','Merlot','France','Bordeaux','The light golden color of this wine belies the bright flavor it holds. A true summer wine, it begs for a picnic lunch in a sun-soaked vineyard.','bouscat.jpg'),(9,'BLOCK NINE','2009','Pinot Noir','USA','California','With hints of ginger and spice, this wine makes an excellent complement to light appetizer and dessert fare for a holiday gathering.','block_nine.jpg'),(10,'DOMAINE SERENE','2007','Pinot Noir','USA','Oregon','Though subtle in its complexities, this wine is sure to please a wide range of enthusiasts. Notes of pomegranate will delight as the nutty finish completes the picture of a fine sipping experience.','domaine_serene.jpg'),(11,'BODEGA LURTON','2011','Pinot Gris','Argentina','Mendoza','Solid notes of black currant blended with a light citrus make this wine an easy pour for varied palates.','bodega_lurton.jpg'),(12,'LES MORIZOTTES','2009','Chardonnay','France','Burgundy','Breaking the mold of the classics, this offering will surprise and undoubtedly get tongues wagging with the hints of coffee and tobacco in\nperfect alignment with more traditional notes. Breaking the mold of the classics, this offering will surprise and\nundoubtedly get tongues wagging with the hints of coffee and tobacco in\nperfect alignment with more traditional notes. Sure to please the late-night crowd with the slight jolt of adrenaline it brings.','morizottes.jpg');
+/*!40000 ALTER TABLE `wine` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2011-12-01 9:22:24
10 part1/api/.htaccess
@@ -0,0 +1,10 @@
+RewriteEngine On
+
+# Some hosts may require you to use the `RewriteBase` directive.
+# If you need to use the `RewriteBase` directive, it should be the
+# absolute physical path to the directory that contains this htaccess file.
+#
+# RewriteBase /
+
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ index.php [QSA,L]
45 part1/api/Slim/Exception/Pass.php
@@ -0,0 +1,45 @@
+<?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.
+ */
+
+/**
+ * Pass Exception
+ *
+ * This Exception will cause the Router::dispatch method
+ * to skip the current matching route and continue to the next
+ * matching route. If no subsequent routes are found, a
+ * HTTP 404 Not Found response will be sent to the client.
+ *
+ * @package Slim
+ * @author Josh Lockhart <info@joshlockhart.com>
+ * @since Version 1.0
+ */
+class Slim_Exception_Pass extends Exception {}
46 part1/api/Slim/Exception/RequestSlash.php
@@ -0,0 +1,46 @@
+<?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 Slash Exception
+ *
+ * This Exception is thrown when Slim detects a matching route
+ * (defined with a trailing slash) and the HTTP request
+ * matches the route but does not have a trailing slash. This
+ * exception will be caught in `Slim::run` and trigger a 301 redirect
+ * to the same resource URI with a trailing slash.
+ *
+ * @package Slim
+ * @author Josh Lockhart <info@joshlockhart.com>
+ * @since Version 1.0
+ */
+class Slim_Exception_RequestSlash extends Exception {}
43 part1/api/Slim/Exception/Stop.php
@@ -0,0 +1,43 @@
+<?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.
+ */
+
+/**
+ * Stop Exception
+ *
+ * This Exception is thrown when the Slim application needs to abort
+ * processing and return control flow to the outer PHP script.
+ *
+ * @package Slim
+ * @author Josh Lockhart <info@joshlockhart.com>
+ * @since Version 1.0
+ */
+class Slim_Exception_Stop extends Exception {}
222 part1/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;
+ }
+
+}
401 part1/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;
+ }
+
+}
405 part1/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;
+ }
+ }
+ }
+
+}
321 part1/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;
+ }
+ }
+
+}
131 part1/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;
+ }
+
+}
155 part1/api/Slim/Log.php
@@ -0,0 +1,155 @@
+<?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.
+ */
+
+/**
+ * Log Adapter
+ *
+ * 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 )
+ * warn( mixed $object )
+ * error( mixed $object )
+ * fatal( mixed $object )
+ *
+ * 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 <info@joshlockhart.com>
+ * @since Version 1.0
+ */
+class Slim_Log {
+
+ /**
+ * @var mixed An object that implements expected Logger interface
+ */
+ protected $logger;
+
+ /**
+ * @var bool Enable logging?
+ */
+ protected $enabled;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->enabled = true;
+ }
+
+ /**
+ * Enable or disable logging
+ * @param bool $enabled
+ * @return void
+ */
+ public function setEnabled( $enabled ) {
+ if ( $enabled ) {
+ $this->enabled = true;
+ } else {
+ $this->enabled = false;
+ }
+ }
+
+ /**
+ * Is logging enabled?
+ * @return bool
+ */
+ public function isEnabled() {
+ return $this->enabled;
+ }
+
+ /**
+ * Log debug message
+ * @param mixed $object
+ * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function debug( $object ) {
+ return isset($this->logger) && $this->isEnabled() ? $this->logger->debug($object) : false;
+ }
+
+ /**
+ * Log info message
+ * @param mixed $object
+ * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function info( $object ) {
+ return isset($this->logger) && $this->isEnabled() ? $this->logger->info($object) : false;
+ }
+
+ /**
+ * Log warn message
+ * @param mixed $object
+ * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function warn( $object ) {
+ return isset($this->logger) && $this->isEnabled() ? $this->logger->warn($object) : false;
+ }
+
+ /**
+ * Log error message
+ * @param mixed $object
+ * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function error( $object ) {
+ return isset($this->logger) && $this->isEnabled() ? $this->logger->error($object) : false;
+ }
+
+ /**
+ * Log fatal message
+ * @param mixed $object
+ * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function fatal( $object ) {
+ return isset($this->logger) && $this->isEnabled() ? $this->logger->fatal($object) : false;
+ }
+
+ /**
+ * Set Logger
+ * @param mixed $logger
+ * @return void
+ */
+ public function setLogger( $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Get Logger
+ * @return mixed
+ */
+ public function getLogger() {
+ return $this->logger;
+ }
+
+}
200 part1/api/Slim/Logger.php
@@ -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);
+ }
+
+}
398 part1/api/Slim/Route.php
@@ -0,0 +1,398 @@
+<?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.
+ */
+
+/**
+ * Route
+ *
+ * @package Slim
+ * @author Josh Lockhart <info@joshlockhart.com>
+ * @since Version 1.0
+ */
+class Slim_Route {
+
+ /**
+ * @var string The route pattern (ie. "/books/:id")
+ */
+ protected $pattern;
+
+ /**
+ * @var mixed The callable associated with this route
+ */
+ protected $callable;
+
+ /**
+ * @var array Conditions for this route's URL parameters
+ */
+ protected $conditions = array();
+
+ /**
+ * @var array Default conditions applied to all Route instances
+ */
+ protected static $defaultConditions = array();
+
+ /**
+ * @var string The name of this route (optional)
+ */
+ protected $name;
+
+ /**
+ * @var array Key-value array of URL parameters
+ */
+ protected $params = array();
+
+ /**
+ * @var array HTTP methods supported by this Route
+ */
+ protected $methods = array();
+
+ /**
+ * @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 (ie. "/books/:id")
+ * @param mixed $callable Anything that returns TRUE for is_callable()
+ */
+ public function __construct( $pattern, $callable ) {
+ $this->setPattern($pattern);
+ $this->setCallable($callable);
+ $this->setConditions(self::getDefaultConditions());
+ }
+
+ /**
+ * Set default route conditions for all instances
+ * @param array $defaultConditions
+ * @return void
+ */
+ public static function setDefaultConditions( array $defaultConditions ) {
+ self::$defaultConditions = $defaultConditions;
+ }
+
+ /**
+ * Get default route conditions for all instances
+ * @return array
+ */
+ public static function getDefaultConditions() {
+ return self::$defaultConditions;
+ }
+
+ /**
+ * Get route pattern
+ * @return string
+ */
+ public function getPattern() {
+ return $this->pattern;
+ }
+
+ /**
+ * Set route pattern
+ * @param string $pattern
+ * @return void
+ */
+ public function setPattern( $pattern ) {
+ $this->pattern = str_replace(')', ')?', (string)$pattern);
+ }
+
+ /**
+ * Get route callable
+ * @return mixed
+ */
+ public function getCallable() {
+ return $this->callable;
+ }
+
+ /**
+ * Set route callable
+ * @param mixed $callable
+ * @return void
+ */
+ public function setCallable($callable) {
+ $this->callable = $callable;
+ }
+
+ /**
+ * Get route conditions
+ * @return array
+ */
+ public function getConditions() {
+ return $this->conditions;
+ }
+
+ /**
+ * Set route conditions
+ * @param array $conditions
+ * @return void
+ */
+ public function setConditions( array $conditions ) {
+ $this->conditions = $conditions;
+ }
+
+ /**
+ * Get route name
+ * @return string|null
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Set route name
+<