├── README.md ├── angular-crud.sql ├── api ├── .htaccess ├── Slim │ ├── Environment.php │ ├── Exception │ │ ├── Pass.php │ │ └── Stop.php │ ├── Helper │ │ └── Set.php │ ├── Http │ │ ├── Cookies.php │ │ ├── Headers.php │ │ ├── Request.php │ │ ├── Response.php │ │ └── Util.php │ ├── Log.php │ ├── LogWriter.php │ ├── Middleware.php │ ├── Middleware │ │ ├── ContentTypes.php │ │ ├── Flash.php │ │ ├── MethodOverride.php │ │ ├── PrettyExceptions.php │ │ └── SessionCookie.php │ ├── Route.php │ ├── Router.php │ ├── Slim.php │ └── View.php └── index.php ├── assets ├── js │ ├── add │ │ ├── add.controller.js │ │ ├── add.html │ │ └── add.module.js │ ├── app.js │ ├── config │ │ ├── config.module.js │ │ └── config.routes.js │ ├── edit │ │ ├── edit.controller.js │ │ ├── edit.html │ │ └── edit.module.js │ └── home │ │ ├── home.controller.js │ │ ├── home.html │ │ └── home.module.js ├── styles │ └── main.css └── vendor │ ├── angular-loading │ ├── loading-bar.min.css │ └── loading-bar.min.js │ ├── angular-ui-router.min.js │ ├── angular.min.js │ ├── boostrap │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ └── bootstrap.min.js │ └── jquery-1.11.2.min.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | PHP-Angular-MYSQL CRUD 2 | ====================== 3 | 4 | An example CRUD application using AngularJS, Slim PHP framework and MySql. 5 | 6 | Requirements: 7 | * AngularJS 8 | * Slim Framework -------------------------------------------------------------------------------- /angular-crud.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.0.10deb1 3 | -- http://www.phpmyadmin.net 4 | -- 5 | -- Host: localhost 6 | -- Generation Time: Apr 12, 2015 at 10:50 PM 7 | -- Server version: 5.5.41-0ubuntu0.14.04.1 8 | -- PHP Version: 5.5.9-1ubuntu4.7 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | 19 | -- 20 | -- Database: `angular-crud` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- Table structure for table `products` 27 | -- 28 | 29 | CREATE TABLE IF NOT EXISTS `products` ( 30 | `product_id` int(10) NOT NULL AUTO_INCREMENT, 31 | `product_name` varchar(500) NOT NULL, 32 | `product_description` varchar(500) NOT NULL, 33 | `product_price` int(10) NOT NULL, 34 | `product_stock` int(10) NOT NULL, 35 | `deleted` tinyint(1) DEFAULT '0', 36 | PRIMARY KEY (`product_id`) 37 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=67 ; 38 | 39 | -- 40 | -- Table structure for table `users` 41 | -- 42 | 43 | CREATE TABLE IF NOT EXISTS `users` ( 44 | `id` int(11) NOT NULL AUTO_INCREMENT, 45 | `username` varchar(255) NOT NULL, 46 | `password` varchar(50) NOT NULL, 47 | `first_name` varchar(100) NOT NULL, 48 | `last_name` varchar(100) NOT NULL, 49 | `address` varchar(255) DEFAULT NULL, 50 | PRIMARY KEY (`id`) 51 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; 52 | 53 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 54 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 55 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 56 | -------------------------------------------------------------------------------- /api/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | # Some hosts may require you to use the `RewriteBase` directive. 4 | # If you need to use the `RewriteBase` directive, it should be the 5 | # absolute physical path to the directory that contains this htaccess file. 6 | # 7 | # RewriteBase / 8 | 9 | RewriteCond %{REQUEST_FILENAME} !-f 10 | RewriteRule ^(.*)$ index.php [QSA,L] -------------------------------------------------------------------------------- /api/Slim/Environment.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Environment 37 | * 38 | * This class creates and returns a key/value array of common 39 | * environment variables for the current HTTP request. 40 | * 41 | * This is a singleton class; derived environment variables will 42 | * be common across multiple Slim applications. 43 | * 44 | * This class matches the Rack (Ruby) specification as closely 45 | * as possible. More information available below. 46 | * 47 | * @package Slim 48 | * @author Josh Lockhart 49 | * @since 1.6.0 50 | */ 51 | class Environment implements \ArrayAccess, \IteratorAggregate 52 | { 53 | /** 54 | * @var array 55 | */ 56 | protected $properties; 57 | 58 | /** 59 | * @var \Slim\Environment 60 | */ 61 | protected static $environment; 62 | 63 | /** 64 | * Get environment instance (singleton) 65 | * 66 | * This creates and/or returns an environment instance (singleton) 67 | * derived from $_SERVER variables. You may override the global server 68 | * variables by using `\Slim\Environment::mock()` instead. 69 | * 70 | * @param bool $refresh Refresh properties using global server variables? 71 | * @return \Slim\Environment 72 | */ 73 | public static function getInstance($refresh = false) 74 | { 75 | if (is_null(self::$environment) || $refresh) { 76 | self::$environment = new self(); 77 | } 78 | 79 | return self::$environment; 80 | } 81 | 82 | /** 83 | * Get mock environment instance 84 | * 85 | * @param array $userSettings 86 | * @return \Slim\Environment 87 | */ 88 | public static function mock($userSettings = array()) 89 | { 90 | $defaults = array( 91 | 'REQUEST_METHOD' => 'GET', 92 | 'SCRIPT_NAME' => '', 93 | 'PATH_INFO' => '', 94 | 'QUERY_STRING' => '', 95 | 'SERVER_NAME' => 'localhost', 96 | 'SERVER_PORT' => 80, 97 | 'ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 98 | 'ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', 99 | 'ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 100 | 'USER_AGENT' => 'Slim Framework', 101 | 'REMOTE_ADDR' => '127.0.0.1', 102 | 'slim.url_scheme' => 'http', 103 | 'slim.input' => '', 104 | 'slim.errors' => @fopen('php://stderr', 'w') 105 | ); 106 | self::$environment = new self(array_merge($defaults, $userSettings)); 107 | 108 | return self::$environment; 109 | } 110 | 111 | /** 112 | * Constructor (private access) 113 | * 114 | * @param array|null $settings If present, these are used instead of global server variables 115 | */ 116 | private function __construct($settings = null) 117 | { 118 | if ($settings) { 119 | $this->properties = $settings; 120 | } else { 121 | $env = array(); 122 | 123 | //The HTTP request method 124 | $env['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD']; 125 | 126 | //The IP 127 | $env['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; 128 | 129 | // Server params 130 | $scriptName = $_SERVER['SCRIPT_NAME']; // <-- "/foo/index.php" 131 | $requestUri = $_SERVER['REQUEST_URI']; // <-- "/foo/bar?test=abc" or "/foo/index.php/bar?test=abc" 132 | $queryString = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; // <-- "test=abc" or "" 133 | 134 | // Physical path 135 | if (strpos($requestUri, $scriptName) !== false) { 136 | $physicalPath = $scriptName; // <-- Without rewriting 137 | } else { 138 | $physicalPath = str_replace('\\', '', dirname($scriptName)); // <-- With rewriting 139 | } 140 | $env['SCRIPT_NAME'] = rtrim($physicalPath, '/'); // <-- Remove trailing slashes 141 | 142 | // Virtual path 143 | $env['PATH_INFO'] = $requestUri; 144 | if (substr($requestUri, 0, strlen($physicalPath)) == $physicalPath) { 145 | $env['PATH_INFO'] = substr($requestUri, strlen($physicalPath)); // <-- Remove physical path 146 | } 147 | $env['PATH_INFO'] = str_replace('?' . $queryString, '', $env['PATH_INFO']); // <-- Remove query string 148 | $env['PATH_INFO'] = '/' . ltrim($env['PATH_INFO'], '/'); // <-- Ensure leading slash 149 | 150 | // Query string (without leading "?") 151 | $env['QUERY_STRING'] = $queryString; 152 | 153 | //Name of server host that is running the script 154 | $env['SERVER_NAME'] = $_SERVER['SERVER_NAME']; 155 | 156 | //Number of server port that is running the script 157 | //Fixes: https://github.com/slimphp/Slim/issues/962 158 | $env['SERVER_PORT'] = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80; 159 | 160 | //HTTP request headers (retains HTTP_ prefix to match $_SERVER) 161 | $headers = \Slim\Http\Headers::extract($_SERVER); 162 | foreach ($headers as $key => $value) { 163 | $env[$key] = $value; 164 | } 165 | 166 | //Is the application running under HTTPS or HTTP protocol? 167 | $env['slim.url_scheme'] = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https'; 168 | 169 | //Input stream (readable one time only; not available for multipart/form-data requests) 170 | $rawInput = @file_get_contents('php://input'); 171 | if (!$rawInput) { 172 | $rawInput = ''; 173 | } 174 | $env['slim.input'] = $rawInput; 175 | 176 | //Error stream 177 | $env['slim.errors'] = @fopen('php://stderr', 'w'); 178 | 179 | $this->properties = $env; 180 | } 181 | } 182 | 183 | /** 184 | * Array Access: Offset Exists 185 | */ 186 | public function offsetExists($offset) 187 | { 188 | return isset($this->properties[$offset]); 189 | } 190 | 191 | /** 192 | * Array Access: Offset Get 193 | */ 194 | public function offsetGet($offset) 195 | { 196 | if (isset($this->properties[$offset])) { 197 | return $this->properties[$offset]; 198 | } 199 | 200 | return null; 201 | } 202 | 203 | /** 204 | * Array Access: Offset Set 205 | */ 206 | public function offsetSet($offset, $value) 207 | { 208 | $this->properties[$offset] = $value; 209 | } 210 | 211 | /** 212 | * Array Access: Offset Unset 213 | */ 214 | public function offsetUnset($offset) 215 | { 216 | unset($this->properties[$offset]); 217 | } 218 | 219 | /** 220 | * IteratorAggregate 221 | * 222 | * @return \ArrayIterator 223 | */ 224 | public function getIterator() 225 | { 226 | return new \ArrayIterator($this->properties); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /api/Slim/Exception/Pass.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Exception; 34 | 35 | /** 36 | * Pass Exception 37 | * 38 | * This Exception will cause the Router::dispatch method 39 | * to skip the current matching route and continue to the next 40 | * matching route. If no subsequent routes are found, a 41 | * HTTP 404 Not Found response will be sent to the client. 42 | * 43 | * @package Slim 44 | * @author Josh Lockhart 45 | * @since 1.0.0 46 | */ 47 | class Pass extends \Exception 48 | { 49 | } 50 | -------------------------------------------------------------------------------- /api/Slim/Exception/Stop.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Exception; 34 | 35 | /** 36 | * Stop Exception 37 | * 38 | * This Exception is thrown when the Slim application needs to abort 39 | * processing and return control flow to the outer PHP script. 40 | * 41 | * @package Slim 42 | * @author Josh Lockhart 43 | * @since 1.0.0 44 | */ 45 | class Stop extends \Exception 46 | { 47 | } 48 | -------------------------------------------------------------------------------- /api/Slim/Helper/Set.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Helper; 34 | 35 | class Set implements \ArrayAccess, \Countable, \IteratorAggregate 36 | { 37 | /** 38 | * Key-value array of arbitrary data 39 | * @var array 40 | */ 41 | protected $data = array(); 42 | 43 | /** 44 | * Constructor 45 | * @param array $items Pre-populate set with this key-value array 46 | */ 47 | public function __construct($items = array()) 48 | { 49 | $this->replace($items); 50 | } 51 | 52 | /** 53 | * Normalize data key 54 | * 55 | * Used to transform data key into the necessary 56 | * key format for this set. Used in subclasses 57 | * like \Slim\Http\Headers. 58 | * 59 | * @param string $key The data key 60 | * @return mixed The transformed/normalized data key 61 | */ 62 | protected function normalizeKey($key) 63 | { 64 | return $key; 65 | } 66 | 67 | /** 68 | * Set data key to value 69 | * @param string $key The data key 70 | * @param mixed $value The data value 71 | */ 72 | public function set($key, $value) 73 | { 74 | $this->data[$this->normalizeKey($key)] = $value; 75 | } 76 | 77 | /** 78 | * Get data value with key 79 | * @param string $key The data key 80 | * @param mixed $default The value to return if data key does not exist 81 | * @return mixed The data value, or the default value 82 | */ 83 | public function get($key, $default = null) 84 | { 85 | if ($this->has($key)) { 86 | $isInvokable = is_object($this->data[$this->normalizeKey($key)]) && method_exists($this->data[$this->normalizeKey($key)], '__invoke'); 87 | 88 | return $isInvokable ? $this->data[$this->normalizeKey($key)]($this) : $this->data[$this->normalizeKey($key)]; 89 | } 90 | 91 | return $default; 92 | } 93 | 94 | /** 95 | * Add data to set 96 | * @param array $items Key-value array of data to append to this set 97 | */ 98 | public function replace($items) 99 | { 100 | foreach ($items as $key => $value) { 101 | $this->set($key, $value); // Ensure keys are normalized 102 | } 103 | } 104 | 105 | /** 106 | * Fetch set data 107 | * @return array This set's key-value data array 108 | */ 109 | public function all() 110 | { 111 | return $this->data; 112 | } 113 | 114 | /** 115 | * Fetch set data keys 116 | * @return array This set's key-value data array keys 117 | */ 118 | public function keys() 119 | { 120 | return array_keys($this->data); 121 | } 122 | 123 | /** 124 | * Does this set contain a key? 125 | * @param string $key The data key 126 | * @return boolean 127 | */ 128 | public function has($key) 129 | { 130 | return array_key_exists($this->normalizeKey($key), $this->data); 131 | } 132 | 133 | /** 134 | * Remove value with key from this set 135 | * @param string $key The data key 136 | */ 137 | public function remove($key) 138 | { 139 | unset($this->data[$this->normalizeKey($key)]); 140 | } 141 | 142 | /** 143 | * Property Overloading 144 | */ 145 | 146 | public function __get($key) 147 | { 148 | return $this->get($key); 149 | } 150 | 151 | public function __set($key, $value) 152 | { 153 | $this->set($key, $value); 154 | } 155 | 156 | public function __isset($key) 157 | { 158 | return $this->has($key); 159 | } 160 | 161 | public function __unset($key) 162 | { 163 | $this->remove($key); 164 | } 165 | 166 | /** 167 | * Clear all values 168 | */ 169 | public function clear() 170 | { 171 | $this->data = array(); 172 | } 173 | 174 | /** 175 | * Array Access 176 | */ 177 | 178 | public function offsetExists($offset) 179 | { 180 | return $this->has($offset); 181 | } 182 | 183 | public function offsetGet($offset) 184 | { 185 | return $this->get($offset); 186 | } 187 | 188 | public function offsetSet($offset, $value) 189 | { 190 | $this->set($offset, $value); 191 | } 192 | 193 | public function offsetUnset($offset) 194 | { 195 | $this->remove($offset); 196 | } 197 | 198 | /** 199 | * Countable 200 | */ 201 | 202 | public function count() 203 | { 204 | return count($this->data); 205 | } 206 | 207 | /** 208 | * IteratorAggregate 209 | */ 210 | 211 | public function getIterator() 212 | { 213 | return new \ArrayIterator($this->data); 214 | } 215 | 216 | /** 217 | * Ensure a value or object will remain globally unique 218 | * @param string $key The value or object name 219 | * @param \Closure $value The closure that defines the object 220 | * @return mixed 221 | */ 222 | public function singleton($key, $value) 223 | { 224 | $this->set($key, function ($c) use ($value) { 225 | static $object; 226 | 227 | if (null === $object) { 228 | $object = $value($c); 229 | } 230 | 231 | return $object; 232 | }); 233 | } 234 | 235 | /** 236 | * Protect closure from being directly invoked 237 | * @param \Closure $callable A closure to keep from being invoked and evaluated 238 | * @return \Closure 239 | */ 240 | public function protect(\Closure $callable) 241 | { 242 | return function () use ($callable) { 243 | return $callable; 244 | }; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /api/Slim/Http/Cookies.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Http; 34 | 35 | class Cookies extends \Slim\Helper\Set 36 | { 37 | /** 38 | * Default cookie settings 39 | * @var array 40 | */ 41 | protected $defaults = array( 42 | 'value' => '', 43 | 'domain' => null, 44 | 'path' => null, 45 | 'expires' => null, 46 | 'secure' => false, 47 | 'httponly' => false 48 | ); 49 | 50 | /** 51 | * Set cookie 52 | * 53 | * The second argument may be a single scalar value, in which case 54 | * it will be merged with the default settings and considered the `value` 55 | * of the merged result. 56 | * 57 | * The second argument may also be an array containing any or all of 58 | * the keys shown in the default settings above. This array will be 59 | * merged with the defaults shown above. 60 | * 61 | * @param string $key Cookie name 62 | * @param mixed $value Cookie settings 63 | */ 64 | public function set($key, $value) 65 | { 66 | if (is_array($value)) { 67 | $cookieSettings = array_replace($this->defaults, $value); 68 | } else { 69 | $cookieSettings = array_replace($this->defaults, array('value' => $value)); 70 | } 71 | parent::set($key, $cookieSettings); 72 | } 73 | 74 | /** 75 | * Remove cookie 76 | * 77 | * Unlike \Slim\Helper\Set, this will actually *set* a cookie with 78 | * an expiration date in the past. This expiration date will force 79 | * the client-side cache to remove its cookie with the given name 80 | * and settings. 81 | * 82 | * @param string $key Cookie name 83 | * @param array $settings Optional cookie settings 84 | */ 85 | public function remove($key, $settings = array()) 86 | { 87 | $settings['value'] = ''; 88 | $settings['expires'] = time() - 86400; 89 | $this->set($key, array_replace($this->defaults, $settings)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /api/Slim/Http/Headers.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Http; 34 | 35 | /** 36 | * HTTP Headers 37 | * 38 | * @package Slim 39 | * @author Josh Lockhart 40 | * @since 1.6.0 41 | */ 42 | class Headers extends \Slim\Helper\Set 43 | { 44 | /******************************************************************************** 45 | * Static interface 46 | *******************************************************************************/ 47 | 48 | /** 49 | * Special-case HTTP headers that are otherwise unidentifiable as HTTP headers. 50 | * Typically, HTTP headers in the $_SERVER array will be prefixed with 51 | * `HTTP_` or `X_`. These are not so we list them here for later reference. 52 | * 53 | * @var array 54 | */ 55 | protected static $special = array( 56 | 'CONTENT_TYPE', 57 | 'CONTENT_LENGTH', 58 | 'PHP_AUTH_USER', 59 | 'PHP_AUTH_PW', 60 | 'PHP_AUTH_DIGEST', 61 | 'AUTH_TYPE' 62 | ); 63 | 64 | /** 65 | * Extract HTTP headers from an array of data (e.g. $_SERVER) 66 | * @param array $data 67 | * @return array 68 | */ 69 | public static function extract($data) 70 | { 71 | $results = array(); 72 | foreach ($data as $key => $value) { 73 | $key = strtoupper($key); 74 | if (strpos($key, 'X_') === 0 || strpos($key, 'HTTP_') === 0 || in_array($key, static::$special)) { 75 | if ($key === 'HTTP_CONTENT_LENGTH') { 76 | continue; 77 | } 78 | $results[$key] = $value; 79 | } 80 | } 81 | 82 | return $results; 83 | } 84 | 85 | /******************************************************************************** 86 | * Instance interface 87 | *******************************************************************************/ 88 | 89 | /** 90 | * Transform header name into canonical form 91 | * @param string $key 92 | * @return string 93 | */ 94 | protected function normalizeKey($key) 95 | { 96 | $key = strtolower($key); 97 | $key = str_replace(array('-', '_'), ' ', $key); 98 | $key = preg_replace('#^http #', '', $key); 99 | $key = ucwords($key); 100 | $key = str_replace(' ', '-', $key); 101 | 102 | return $key; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /api/Slim/Http/Request.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Http; 34 | 35 | /** 36 | * Slim HTTP Request 37 | * 38 | * This class provides a human-friendly interface to the Slim environment variables; 39 | * environment variables are passed by reference and will be modified directly. 40 | * 41 | * @package Slim 42 | * @author Josh Lockhart 43 | * @since 1.0.0 44 | */ 45 | class Request 46 | { 47 | const METHOD_HEAD = 'HEAD'; 48 | const METHOD_GET = 'GET'; 49 | const METHOD_POST = 'POST'; 50 | const METHOD_PUT = 'PUT'; 51 | const METHOD_PATCH = 'PATCH'; 52 | const METHOD_DELETE = 'DELETE'; 53 | const METHOD_OPTIONS = 'OPTIONS'; 54 | const METHOD_OVERRIDE = '_METHOD'; 55 | 56 | /** 57 | * @var array 58 | */ 59 | protected static $formDataMediaTypes = array('application/x-www-form-urlencoded'); 60 | 61 | /** 62 | * Application Environment 63 | * @var \Slim\Environment 64 | */ 65 | protected $env; 66 | 67 | /** 68 | * HTTP Headers 69 | * @var \Slim\Http\Headers 70 | */ 71 | public $headers; 72 | 73 | /** 74 | * HTTP Cookies 75 | * @var \Slim\Helper\Set 76 | */ 77 | public $cookies; 78 | 79 | /** 80 | * Constructor 81 | * @param \Slim\Environment $env 82 | */ 83 | public function __construct(\Slim\Environment $env) 84 | { 85 | $this->env = $env; 86 | $this->headers = new \Slim\Http\Headers(\Slim\Http\Headers::extract($env)); 87 | $this->cookies = new \Slim\Helper\Set(\Slim\Http\Util::parseCookieHeader($env['HTTP_COOKIE'])); 88 | } 89 | 90 | /** 91 | * Get HTTP method 92 | * @return string 93 | */ 94 | public function getMethod() 95 | { 96 | return $this->env['REQUEST_METHOD']; 97 | } 98 | 99 | /** 100 | * Is this a GET request? 101 | * @return bool 102 | */ 103 | public function isGet() 104 | { 105 | return $this->getMethod() === self::METHOD_GET; 106 | } 107 | 108 | /** 109 | * Is this a POST request? 110 | * @return bool 111 | */ 112 | public function isPost() 113 | { 114 | return $this->getMethod() === self::METHOD_POST; 115 | } 116 | 117 | /** 118 | * Is this a PUT request? 119 | * @return bool 120 | */ 121 | public function isPut() 122 | { 123 | return $this->getMethod() === self::METHOD_PUT; 124 | } 125 | 126 | /** 127 | * Is this a PATCH request? 128 | * @return bool 129 | */ 130 | public function isPatch() 131 | { 132 | return $this->getMethod() === self::METHOD_PATCH; 133 | } 134 | 135 | /** 136 | * Is this a DELETE request? 137 | * @return bool 138 | */ 139 | public function isDelete() 140 | { 141 | return $this->getMethod() === self::METHOD_DELETE; 142 | } 143 | 144 | /** 145 | * Is this a HEAD request? 146 | * @return bool 147 | */ 148 | public function isHead() 149 | { 150 | return $this->getMethod() === self::METHOD_HEAD; 151 | } 152 | 153 | /** 154 | * Is this a OPTIONS request? 155 | * @return bool 156 | */ 157 | public function isOptions() 158 | { 159 | return $this->getMethod() === self::METHOD_OPTIONS; 160 | } 161 | 162 | /** 163 | * Is this an AJAX request? 164 | * @return bool 165 | */ 166 | public function isAjax() 167 | { 168 | if ($this->params('isajax')) { 169 | return true; 170 | } elseif (isset($this->headers['X_REQUESTED_WITH']) && $this->headers['X_REQUESTED_WITH'] === 'XMLHttpRequest') { 171 | return true; 172 | } 173 | 174 | return false; 175 | } 176 | 177 | /** 178 | * Is this an XHR request? (alias of Slim_Http_Request::isAjax) 179 | * @return bool 180 | */ 181 | public function isXhr() 182 | { 183 | return $this->isAjax(); 184 | } 185 | 186 | /** 187 | * Fetch GET and POST data 188 | * 189 | * This method returns a union of GET and POST data as a key-value array, or the value 190 | * of the array key if requested; if the array key does not exist, NULL is returned, 191 | * unless there is a default value specified. 192 | * 193 | * @param string $key 194 | * @param mixed $default 195 | * @return array|mixed|null 196 | */ 197 | public function params($key = null, $default = null) 198 | { 199 | $union = array_merge($this->get(), $this->post()); 200 | if ($key) { 201 | return isset($union[$key]) ? $union[$key] : $default; 202 | } 203 | 204 | return $union; 205 | } 206 | 207 | /** 208 | * Fetch GET data 209 | * 210 | * This method returns a key-value array of data sent in the HTTP request query string, or 211 | * the value of the array key if requested; if the array key does not exist, NULL is returned. 212 | * 213 | * @param string $key 214 | * @param mixed $default Default return value when key does not exist 215 | * @return array|mixed|null 216 | */ 217 | public function get($key = null, $default = null) 218 | { 219 | if (!isset($this->env['slim.request.query_hash'])) { 220 | $output = array(); 221 | if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) { 222 | mb_parse_str($this->env['QUERY_STRING'], $output); 223 | } else { 224 | parse_str($this->env['QUERY_STRING'], $output); 225 | } 226 | $this->env['slim.request.query_hash'] = Util::stripSlashesIfMagicQuotes($output); 227 | } 228 | if ($key) { 229 | if (isset($this->env['slim.request.query_hash'][$key])) { 230 | return $this->env['slim.request.query_hash'][$key]; 231 | } else { 232 | return $default; 233 | } 234 | } else { 235 | return $this->env['slim.request.query_hash']; 236 | } 237 | } 238 | 239 | /** 240 | * Fetch POST data 241 | * 242 | * This method returns a key-value array of data sent in the HTTP request body, or 243 | * the value of a hash key if requested; if the array key does not exist, NULL is returned. 244 | * 245 | * @param string $key 246 | * @param mixed $default Default return value when key does not exist 247 | * @return array|mixed|null 248 | * @throws \RuntimeException If environment input is not available 249 | */ 250 | public function post($key = null, $default = null) 251 | { 252 | if (!isset($this->env['slim.input'])) { 253 | throw new \RuntimeException('Missing slim.input in environment variables'); 254 | } 255 | if (!isset($this->env['slim.request.form_hash'])) { 256 | $this->env['slim.request.form_hash'] = array(); 257 | if ($this->isFormData() && is_string($this->env['slim.input'])) { 258 | $output = array(); 259 | if (function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte'])) { 260 | mb_parse_str($this->env['slim.input'], $output); 261 | } else { 262 | parse_str($this->env['slim.input'], $output); 263 | } 264 | $this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($output); 265 | } else { 266 | $this->env['slim.request.form_hash'] = Util::stripSlashesIfMagicQuotes($_POST); 267 | } 268 | } 269 | if ($key) { 270 | if (isset($this->env['slim.request.form_hash'][$key])) { 271 | return $this->env['slim.request.form_hash'][$key]; 272 | } else { 273 | return $default; 274 | } 275 | } else { 276 | return $this->env['slim.request.form_hash']; 277 | } 278 | } 279 | 280 | /** 281 | * Fetch PUT data (alias for \Slim\Http\Request::post) 282 | * @param string $key 283 | * @param mixed $default Default return value when key does not exist 284 | * @return array|mixed|null 285 | */ 286 | public function put($key = null, $default = null) 287 | { 288 | return $this->post($key, $default); 289 | } 290 | 291 | /** 292 | * Fetch PATCH data (alias for \Slim\Http\Request::post) 293 | * @param string $key 294 | * @param mixed $default Default return value when key does not exist 295 | * @return array|mixed|null 296 | */ 297 | public function patch($key = null, $default = null) 298 | { 299 | return $this->post($key, $default); 300 | } 301 | 302 | /** 303 | * Fetch DELETE data (alias for \Slim\Http\Request::post) 304 | * @param string $key 305 | * @param mixed $default Default return value when key does not exist 306 | * @return array|mixed|null 307 | */ 308 | public function delete($key = null, $default = null) 309 | { 310 | return $this->post($key, $default); 311 | } 312 | 313 | /** 314 | * Fetch COOKIE data 315 | * 316 | * This method returns a key-value array of Cookie data sent in the HTTP request, or 317 | * the value of a array key if requested; if the array key does not exist, NULL is returned. 318 | * 319 | * @param string $key 320 | * @return array|string|null 321 | */ 322 | public function cookies($key = null) 323 | { 324 | if ($key) { 325 | return $this->cookies->get($key); 326 | } 327 | 328 | return $this->cookies; 329 | // if (!isset($this->env['slim.request.cookie_hash'])) { 330 | // $cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : ''; 331 | // $this->env['slim.request.cookie_hash'] = Util::parseCookieHeader($cookieHeader); 332 | // } 333 | // if ($key) { 334 | // if (isset($this->env['slim.request.cookie_hash'][$key])) { 335 | // return $this->env['slim.request.cookie_hash'][$key]; 336 | // } else { 337 | // return null; 338 | // } 339 | // } else { 340 | // return $this->env['slim.request.cookie_hash']; 341 | // } 342 | } 343 | 344 | /** 345 | * Does the Request body contain parsed form data? 346 | * @return bool 347 | */ 348 | public function isFormData() 349 | { 350 | $method = isset($this->env['slim.method_override.original_method']) ? $this->env['slim.method_override.original_method'] : $this->getMethod(); 351 | 352 | return ($method === self::METHOD_POST && is_null($this->getContentType())) || in_array($this->getMediaType(), self::$formDataMediaTypes); 353 | } 354 | 355 | /** 356 | * Get Headers 357 | * 358 | * This method returns a key-value array of headers sent in the HTTP request, or 359 | * the value of a hash key if requested; if the array key does not exist, NULL is returned. 360 | * 361 | * @param string $key 362 | * @param mixed $default The default value returned if the requested header is not available 363 | * @return mixed 364 | */ 365 | public function headers($key = null, $default = null) 366 | { 367 | if ($key) { 368 | return $this->headers->get($key, $default); 369 | } 370 | 371 | return $this->headers; 372 | // if ($key) { 373 | // $key = strtoupper($key); 374 | // $key = str_replace('-', '_', $key); 375 | // $key = preg_replace('@^HTTP_@', '', $key); 376 | // if (isset($this->env[$key])) { 377 | // return $this->env[$key]; 378 | // } else { 379 | // return $default; 380 | // } 381 | // } else { 382 | // $headers = array(); 383 | // foreach ($this->env as $key => $value) { 384 | // if (strpos($key, 'slim.') !== 0) { 385 | // $headers[$key] = $value; 386 | // } 387 | // } 388 | // 389 | // return $headers; 390 | // } 391 | } 392 | 393 | /** 394 | * Get Body 395 | * @return string 396 | */ 397 | public function getBody() 398 | { 399 | return $this->env['slim.input']; 400 | } 401 | 402 | /** 403 | * Get Content Type 404 | * @return string|null 405 | */ 406 | public function getContentType() 407 | { 408 | return $this->headers->get('CONTENT_TYPE'); 409 | } 410 | 411 | /** 412 | * Get Media Type (type/subtype within Content Type header) 413 | * @return string|null 414 | */ 415 | public function getMediaType() 416 | { 417 | $contentType = $this->getContentType(); 418 | if ($contentType) { 419 | $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 420 | 421 | return strtolower($contentTypeParts[0]); 422 | } 423 | 424 | return null; 425 | } 426 | 427 | /** 428 | * Get Media Type Params 429 | * @return array 430 | */ 431 | public function getMediaTypeParams() 432 | { 433 | $contentType = $this->getContentType(); 434 | $contentTypeParams = array(); 435 | if ($contentType) { 436 | $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 437 | $contentTypePartsLength = count($contentTypeParts); 438 | for ($i = 1; $i < $contentTypePartsLength; $i++) { 439 | $paramParts = explode('=', $contentTypeParts[$i]); 440 | $contentTypeParams[strtolower($paramParts[0])] = $paramParts[1]; 441 | } 442 | } 443 | 444 | return $contentTypeParams; 445 | } 446 | 447 | /** 448 | * Get Content Charset 449 | * @return string|null 450 | */ 451 | public function getContentCharset() 452 | { 453 | $mediaTypeParams = $this->getMediaTypeParams(); 454 | if (isset($mediaTypeParams['charset'])) { 455 | return $mediaTypeParams['charset']; 456 | } 457 | 458 | return null; 459 | } 460 | 461 | /** 462 | * Get Content-Length 463 | * @return int 464 | */ 465 | public function getContentLength() 466 | { 467 | return $this->headers->get('CONTENT_LENGTH', 0); 468 | } 469 | 470 | /** 471 | * Get Host 472 | * @return string 473 | */ 474 | public function getHost() 475 | { 476 | if (isset($this->env['HTTP_HOST'])) { 477 | if (strpos($this->env['HTTP_HOST'], ':') !== false) { 478 | $hostParts = explode(':', $this->env['HTTP_HOST']); 479 | 480 | return $hostParts[0]; 481 | } 482 | 483 | return $this->env['HTTP_HOST']; 484 | } 485 | 486 | return $this->env['SERVER_NAME']; 487 | } 488 | 489 | /** 490 | * Get Host with Port 491 | * @return string 492 | */ 493 | public function getHostWithPort() 494 | { 495 | return sprintf('%s:%s', $this->getHost(), $this->getPort()); 496 | } 497 | 498 | /** 499 | * Get Port 500 | * @return int 501 | */ 502 | public function getPort() 503 | { 504 | return (int)$this->env['SERVER_PORT']; 505 | } 506 | 507 | /** 508 | * Get Scheme (https or http) 509 | * @return string 510 | */ 511 | public function getScheme() 512 | { 513 | return $this->env['slim.url_scheme']; 514 | } 515 | 516 | /** 517 | * Get Script Name (physical path) 518 | * @return string 519 | */ 520 | public function getScriptName() 521 | { 522 | return $this->env['SCRIPT_NAME']; 523 | } 524 | 525 | /** 526 | * LEGACY: Get Root URI (alias for Slim_Http_Request::getScriptName) 527 | * @return string 528 | */ 529 | public function getRootUri() 530 | { 531 | return $this->getScriptName(); 532 | } 533 | 534 | /** 535 | * Get Path (physical path + virtual path) 536 | * @return string 537 | */ 538 | public function getPath() 539 | { 540 | return $this->getScriptName() . $this->getPathInfo(); 541 | } 542 | 543 | /** 544 | * Get Path Info (virtual path) 545 | * @return string 546 | */ 547 | public function getPathInfo() 548 | { 549 | return $this->env['PATH_INFO']; 550 | } 551 | 552 | /** 553 | * LEGACY: Get Resource URI (alias for Slim_Http_Request::getPathInfo) 554 | * @return string 555 | */ 556 | public function getResourceUri() 557 | { 558 | return $this->getPathInfo(); 559 | } 560 | 561 | /** 562 | * Get URL (scheme + host [ + port if non-standard ]) 563 | * @return string 564 | */ 565 | public function getUrl() 566 | { 567 | $url = $this->getScheme() . '://' . $this->getHost(); 568 | if (($this->getScheme() === 'https' && $this->getPort() !== 443) || ($this->getScheme() === 'http' && $this->getPort() !== 80)) { 569 | $url .= sprintf(':%s', $this->getPort()); 570 | } 571 | 572 | return $url; 573 | } 574 | 575 | /** 576 | * Get IP 577 | * @return string 578 | */ 579 | public function getIp() 580 | { 581 | $keys = array('X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR', 'CLIENT_IP', 'REMOTE_ADDR'); 582 | foreach ($keys as $key) { 583 | if (isset($this->env[$key])) { 584 | return $this->env[$key]; 585 | } 586 | } 587 | 588 | return $this->env['REMOTE_ADDR']; 589 | } 590 | 591 | /** 592 | * Get Referrer 593 | * @return string|null 594 | */ 595 | public function getReferrer() 596 | { 597 | return $this->headers->get('HTTP_REFERER'); 598 | } 599 | 600 | /** 601 | * Get Referer (for those who can't spell) 602 | * @return string|null 603 | */ 604 | public function getReferer() 605 | { 606 | return $this->getReferrer(); 607 | } 608 | 609 | /** 610 | * Get User Agent 611 | * @return string|null 612 | */ 613 | public function getUserAgent() 614 | { 615 | return $this->headers->get('HTTP_USER_AGENT'); 616 | } 617 | } 618 | -------------------------------------------------------------------------------- /api/Slim/Http/Response.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Http; 34 | 35 | /** 36 | * Response 37 | * 38 | * This is a simple abstraction over top an HTTP response. This 39 | * provides methods to set the HTTP status, the HTTP headers, 40 | * and the HTTP body. 41 | * 42 | * @package Slim 43 | * @author Josh Lockhart 44 | * @since 1.0.0 45 | */ 46 | class Response implements \ArrayAccess, \Countable, \IteratorAggregate 47 | { 48 | /** 49 | * @var int HTTP status code 50 | */ 51 | protected $status; 52 | 53 | /** 54 | * @var \Slim\Http\Headers 55 | */ 56 | public $headers; 57 | 58 | /** 59 | * @var \Slim\Http\Cookies 60 | */ 61 | public $cookies; 62 | 63 | /** 64 | * @var string HTTP response body 65 | */ 66 | protected $body; 67 | 68 | /** 69 | * @var int Length of HTTP response body 70 | */ 71 | protected $length; 72 | 73 | /** 74 | * @var array HTTP response codes and messages 75 | */ 76 | protected static $messages = array( 77 | //Informational 1xx 78 | 100 => '100 Continue', 79 | 101 => '101 Switching Protocols', 80 | //Successful 2xx 81 | 200 => '200 OK', 82 | 201 => '201 Created', 83 | 202 => '202 Accepted', 84 | 203 => '203 Non-Authoritative Information', 85 | 204 => '204 No Content', 86 | 205 => '205 Reset Content', 87 | 206 => '206 Partial Content', 88 | 226 => '226 IM Used', 89 | //Redirection 3xx 90 | 300 => '300 Multiple Choices', 91 | 301 => '301 Moved Permanently', 92 | 302 => '302 Found', 93 | 303 => '303 See Other', 94 | 304 => '304 Not Modified', 95 | 305 => '305 Use Proxy', 96 | 306 => '306 (Unused)', 97 | 307 => '307 Temporary Redirect', 98 | //Client Error 4xx 99 | 400 => '400 Bad Request', 100 | 401 => '401 Unauthorized', 101 | 402 => '402 Payment Required', 102 | 403 => '403 Forbidden', 103 | 404 => '404 Not Found', 104 | 405 => '405 Method Not Allowed', 105 | 406 => '406 Not Acceptable', 106 | 407 => '407 Proxy Authentication Required', 107 | 408 => '408 Request Timeout', 108 | 409 => '409 Conflict', 109 | 410 => '410 Gone', 110 | 411 => '411 Length Required', 111 | 412 => '412 Precondition Failed', 112 | 413 => '413 Request Entity Too Large', 113 | 414 => '414 Request-URI Too Long', 114 | 415 => '415 Unsupported Media Type', 115 | 416 => '416 Requested Range Not Satisfiable', 116 | 417 => '417 Expectation Failed', 117 | 418 => '418 I\'m a teapot', 118 | 422 => '422 Unprocessable Entity', 119 | 423 => '423 Locked', 120 | 426 => '426 Upgrade Required', 121 | 428 => '428 Precondition Required', 122 | 429 => '429 Too Many Requests', 123 | 431 => '431 Request Header Fields Too Large', 124 | //Server Error 5xx 125 | 500 => '500 Internal Server Error', 126 | 501 => '501 Not Implemented', 127 | 502 => '502 Bad Gateway', 128 | 503 => '503 Service Unavailable', 129 | 504 => '504 Gateway Timeout', 130 | 505 => '505 HTTP Version Not Supported', 131 | 506 => '506 Variant Also Negotiates', 132 | 510 => '510 Not Extended', 133 | 511 => '511 Network Authentication Required' 134 | ); 135 | 136 | /** 137 | * Constructor 138 | * @param string $body The HTTP response body 139 | * @param int $status The HTTP response status 140 | * @param \Slim\Http\Headers|array $headers The HTTP response headers 141 | */ 142 | public function __construct($body = '', $status = 200, $headers = array()) 143 | { 144 | $this->setStatus($status); 145 | $this->headers = new \Slim\Http\Headers(array('Content-Type' => 'text/html')); 146 | $this->headers->replace($headers); 147 | $this->cookies = new \Slim\Http\Cookies(); 148 | $this->write($body); 149 | } 150 | 151 | public function getStatus() 152 | { 153 | return $this->status; 154 | } 155 | 156 | public function setStatus($status) 157 | { 158 | $this->status = (int)$status; 159 | } 160 | 161 | /** 162 | * DEPRECATION WARNING! Use `getStatus` or `setStatus` instead. 163 | * 164 | * Get and set status 165 | * @param int|null $status 166 | * @return int 167 | */ 168 | public function status($status = null) 169 | { 170 | if (!is_null($status)) { 171 | $this->status = (int) $status; 172 | } 173 | 174 | return $this->status; 175 | } 176 | 177 | /** 178 | * DEPRECATION WARNING! Access `headers` property directly. 179 | * 180 | * Get and set header 181 | * @param string $name Header name 182 | * @param string|null $value Header value 183 | * @return string Header value 184 | */ 185 | public function header($name, $value = null) 186 | { 187 | if (!is_null($value)) { 188 | $this->headers->set($name, $value); 189 | } 190 | 191 | return $this->headers->get($name); 192 | } 193 | 194 | /** 195 | * DEPRECATION WARNING! Access `headers` property directly. 196 | * 197 | * Get headers 198 | * @return \Slim\Http\Headers 199 | */ 200 | public function headers() 201 | { 202 | return $this->headers; 203 | } 204 | 205 | public function getBody() 206 | { 207 | return $this->body; 208 | } 209 | 210 | public function setBody($content) 211 | { 212 | $this->write($content, true); 213 | } 214 | 215 | /** 216 | * DEPRECATION WARNING! use `getBody` or `setBody` instead. 217 | * 218 | * Get and set body 219 | * @param string|null $body Content of HTTP response body 220 | * @return string 221 | */ 222 | public function body($body = null) 223 | { 224 | if (!is_null($body)) { 225 | $this->write($body, true); 226 | } 227 | 228 | return $this->body; 229 | } 230 | 231 | /** 232 | * Append HTTP response body 233 | * @param string $body Content to append to the current HTTP response body 234 | * @param bool $replace Overwrite existing response body? 235 | * @return string The updated HTTP response body 236 | */ 237 | public function write($body, $replace = false) 238 | { 239 | if ($replace) { 240 | $this->body = $body; 241 | } else { 242 | $this->body .= (string)$body; 243 | } 244 | $this->length = strlen($this->body); 245 | 246 | return $this->body; 247 | } 248 | 249 | public function getLength() 250 | { 251 | return $this->length; 252 | } 253 | 254 | /** 255 | * DEPRECATION WARNING! Use `getLength` or `write` or `body` instead. 256 | * 257 | * Get and set length 258 | * @param int|null $length 259 | * @return int 260 | */ 261 | public function length($length = null) 262 | { 263 | if (!is_null($length)) { 264 | $this->length = (int) $length; 265 | } 266 | 267 | return $this->length; 268 | } 269 | 270 | /** 271 | * Finalize 272 | * 273 | * This prepares this response and returns an array 274 | * of [status, headers, body]. This array is passed to outer middleware 275 | * if available or directly to the Slim run method. 276 | * 277 | * @return array[int status, array headers, string body] 278 | */ 279 | public function finalize() 280 | { 281 | // Prepare response 282 | if (in_array($this->status, array(204, 304))) { 283 | $this->headers->remove('Content-Type'); 284 | $this->headers->remove('Content-Length'); 285 | $this->setBody(''); 286 | } 287 | 288 | return array($this->status, $this->headers, $this->body); 289 | } 290 | 291 | /** 292 | * DEPRECATION WARNING! Access `cookies` property directly. 293 | * 294 | * Set cookie 295 | * 296 | * Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie` 297 | * header on its own and delegates this responsibility to the `Slim_Http_Util` class. This 298 | * response's header is passed by reference to the utility class and is directly modified. By not 299 | * relying on PHP's native implementation, Slim allows middleware the opportunity to massage or 300 | * analyze the raw header before the response is ultimately delivered to the HTTP client. 301 | * 302 | * @param string $name The name of the cookie 303 | * @param string|array $value If string, the value of cookie; if array, properties for 304 | * cookie including: value, expire, path, domain, secure, httponly 305 | */ 306 | public function setCookie($name, $value) 307 | { 308 | // Util::setCookieHeader($this->header, $name, $value); 309 | $this->cookies->set($name, $value); 310 | } 311 | 312 | /** 313 | * DEPRECATION WARNING! Access `cookies` property directly. 314 | * 315 | * Delete cookie 316 | * 317 | * Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie` 318 | * header on its own and delegates this responsibility to the `Slim_Http_Util` class. This 319 | * response's header is passed by reference to the utility class and is directly modified. By not 320 | * relying on PHP's native implementation, Slim allows middleware the opportunity to massage or 321 | * analyze the raw header before the response is ultimately delivered to the HTTP client. 322 | * 323 | * This method will set a cookie with the given name that has an expiration time in the past; this will 324 | * prompt the HTTP client to invalidate and remove the client-side cookie. Optionally, you may 325 | * also pass a key/value array as the second argument. If the "domain" key is present in this 326 | * array, only the Cookie with the given name AND domain will be removed. The invalidating cookie 327 | * sent with this response will adopt all properties of the second argument. 328 | * 329 | * @param string $name The name of the cookie 330 | * @param array $settings Properties for cookie including: value, expire, path, domain, secure, httponly 331 | */ 332 | public function deleteCookie($name, $settings = array()) 333 | { 334 | $this->cookies->remove($name, $settings); 335 | // Util::deleteCookieHeader($this->header, $name, $value); 336 | } 337 | 338 | /** 339 | * Redirect 340 | * 341 | * This method prepares this response to return an HTTP Redirect response 342 | * to the HTTP client. 343 | * 344 | * @param string $url The redirect destination 345 | * @param int $status The redirect HTTP status code 346 | */ 347 | public function redirect ($url, $status = 302) 348 | { 349 | $this->setStatus($status); 350 | $this->headers->set('Location', $url); 351 | } 352 | 353 | /** 354 | * Helpers: Empty? 355 | * @return bool 356 | */ 357 | public function isEmpty() 358 | { 359 | return in_array($this->status, array(201, 204, 304)); 360 | } 361 | 362 | /** 363 | * Helpers: Informational? 364 | * @return bool 365 | */ 366 | public function isInformational() 367 | { 368 | return $this->status >= 100 && $this->status < 200; 369 | } 370 | 371 | /** 372 | * Helpers: OK? 373 | * @return bool 374 | */ 375 | public function isOk() 376 | { 377 | return $this->status === 200; 378 | } 379 | 380 | /** 381 | * Helpers: Successful? 382 | * @return bool 383 | */ 384 | public function isSuccessful() 385 | { 386 | return $this->status >= 200 && $this->status < 300; 387 | } 388 | 389 | /** 390 | * Helpers: Redirect? 391 | * @return bool 392 | */ 393 | public function isRedirect() 394 | { 395 | return in_array($this->status, array(301, 302, 303, 307)); 396 | } 397 | 398 | /** 399 | * Helpers: Redirection? 400 | * @return bool 401 | */ 402 | public function isRedirection() 403 | { 404 | return $this->status >= 300 && $this->status < 400; 405 | } 406 | 407 | /** 408 | * Helpers: Forbidden? 409 | * @return bool 410 | */ 411 | public function isForbidden() 412 | { 413 | return $this->status === 403; 414 | } 415 | 416 | /** 417 | * Helpers: Not Found? 418 | * @return bool 419 | */ 420 | public function isNotFound() 421 | { 422 | return $this->status === 404; 423 | } 424 | 425 | /** 426 | * Helpers: Client error? 427 | * @return bool 428 | */ 429 | public function isClientError() 430 | { 431 | return $this->status >= 400 && $this->status < 500; 432 | } 433 | 434 | /** 435 | * Helpers: Server Error? 436 | * @return bool 437 | */ 438 | public function isServerError() 439 | { 440 | return $this->status >= 500 && $this->status < 600; 441 | } 442 | 443 | /** 444 | * DEPRECATION WARNING! ArrayAccess interface will be removed from \Slim\Http\Response. 445 | * Iterate `headers` or `cookies` properties directly. 446 | */ 447 | 448 | /** 449 | * Array Access: Offset Exists 450 | */ 451 | public function offsetExists($offset) 452 | { 453 | return isset($this->headers[$offset]); 454 | } 455 | 456 | /** 457 | * Array Access: Offset Get 458 | */ 459 | public function offsetGet($offset) 460 | { 461 | return $this->headers[$offset]; 462 | } 463 | 464 | /** 465 | * Array Access: Offset Set 466 | */ 467 | public function offsetSet($offset, $value) 468 | { 469 | $this->headers[$offset] = $value; 470 | } 471 | 472 | /** 473 | * Array Access: Offset Unset 474 | */ 475 | public function offsetUnset($offset) 476 | { 477 | unset($this->headers[$offset]); 478 | } 479 | 480 | /** 481 | * DEPRECATION WARNING! Countable interface will be removed from \Slim\Http\Response. 482 | * Call `count` on `headers` or `cookies` properties directly. 483 | * 484 | * Countable: Count 485 | */ 486 | public function count() 487 | { 488 | return count($this->headers); 489 | } 490 | 491 | /** 492 | * DEPRECATION WARNING! IteratorAggregate interface will be removed from \Slim\Http\Response. 493 | * Iterate `headers` or `cookies` properties directly. 494 | * 495 | * Get Iterator 496 | * 497 | * This returns the contained `\Slim\Http\Headers` instance which 498 | * is itself iterable. 499 | * 500 | * @return \Slim\Http\Headers 501 | */ 502 | public function getIterator() 503 | { 504 | return $this->headers->getIterator(); 505 | } 506 | 507 | /** 508 | * Get message for HTTP status code 509 | * @param int $status 510 | * @return string|null 511 | */ 512 | public static function getMessageForCode($status) 513 | { 514 | if (isset(self::$messages[$status])) { 515 | return self::$messages[$status]; 516 | } else { 517 | return null; 518 | } 519 | } 520 | } 521 | -------------------------------------------------------------------------------- /api/Slim/Http/Util.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Http; 34 | 35 | /** 36 | * Slim HTTP Utilities 37 | * 38 | * This class provides useful methods for handling HTTP requests. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Util 45 | { 46 | /** 47 | * Strip slashes from string or array 48 | * 49 | * This method strips slashes from its input. By default, this method will only 50 | * strip slashes from its input if magic quotes are enabled. Otherwise, you may 51 | * override the magic quotes setting with either TRUE or FALSE as the send argument 52 | * to force this method to strip or not strip slashes from its input. 53 | * 54 | * @param array|string $rawData 55 | * @param bool $overrideStripSlashes 56 | * @return array|string 57 | */ 58 | public static function stripSlashesIfMagicQuotes($rawData, $overrideStripSlashes = null) 59 | { 60 | $strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes; 61 | if ($strip) { 62 | return self::stripSlashes($rawData); 63 | } 64 | 65 | return $rawData; 66 | } 67 | 68 | /** 69 | * Strip slashes from string or array 70 | * @param array|string $rawData 71 | * @return array|string 72 | */ 73 | protected static function stripSlashes($rawData) 74 | { 75 | return is_array($rawData) ? array_map(array('self', 'stripSlashes'), $rawData) : stripslashes($rawData); 76 | } 77 | 78 | /** 79 | * Encrypt data 80 | * 81 | * This method will encrypt data using a given key, vector, and cipher. 82 | * By default, this will encrypt data using the RIJNDAEL/AES 256 bit cipher. You 83 | * may override the default cipher and cipher mode by passing your own desired 84 | * cipher and cipher mode as the final key-value array argument. 85 | * 86 | * @param string $data The unencrypted data 87 | * @param string $key The encryption key 88 | * @param string $iv The encryption initialization vector 89 | * @param array $settings Optional key-value array with custom algorithm and mode 90 | * @return string 91 | */ 92 | public static function encrypt($data, $key, $iv, $settings = array()) 93 | { 94 | if ($data === '' || !extension_loaded('mcrypt')) { 95 | return $data; 96 | } 97 | 98 | //Merge settings with defaults 99 | $defaults = array( 100 | 'algorithm' => MCRYPT_RIJNDAEL_256, 101 | 'mode' => MCRYPT_MODE_CBC 102 | ); 103 | $settings = array_merge($defaults, $settings); 104 | 105 | //Get module 106 | $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], ''); 107 | 108 | //Validate IV 109 | $ivSize = mcrypt_enc_get_iv_size($module); 110 | if (strlen($iv) > $ivSize) { 111 | $iv = substr($iv, 0, $ivSize); 112 | } 113 | 114 | //Validate key 115 | $keySize = mcrypt_enc_get_key_size($module); 116 | if (strlen($key) > $keySize) { 117 | $key = substr($key, 0, $keySize); 118 | } 119 | 120 | //Encrypt value 121 | mcrypt_generic_init($module, $key, $iv); 122 | $res = @mcrypt_generic($module, $data); 123 | mcrypt_generic_deinit($module); 124 | 125 | return $res; 126 | } 127 | 128 | /** 129 | * Decrypt data 130 | * 131 | * This method will decrypt data using a given key, vector, and cipher. 132 | * By default, this will decrypt data using the RIJNDAEL/AES 256 bit cipher. You 133 | * may override the default cipher and cipher mode by passing your own desired 134 | * cipher and cipher mode as the final key-value array argument. 135 | * 136 | * @param string $data The encrypted data 137 | * @param string $key The encryption key 138 | * @param string $iv The encryption initialization vector 139 | * @param array $settings Optional key-value array with custom algorithm and mode 140 | * @return string 141 | */ 142 | public static function decrypt($data, $key, $iv, $settings = array()) 143 | { 144 | if ($data === '' || !extension_loaded('mcrypt')) { 145 | return $data; 146 | } 147 | 148 | //Merge settings with defaults 149 | $defaults = array( 150 | 'algorithm' => MCRYPT_RIJNDAEL_256, 151 | 'mode' => MCRYPT_MODE_CBC 152 | ); 153 | $settings = array_merge($defaults, $settings); 154 | 155 | //Get module 156 | $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], ''); 157 | 158 | //Validate IV 159 | $ivSize = mcrypt_enc_get_iv_size($module); 160 | if (strlen($iv) > $ivSize) { 161 | $iv = substr($iv, 0, $ivSize); 162 | } 163 | 164 | //Validate key 165 | $keySize = mcrypt_enc_get_key_size($module); 166 | if (strlen($key) > $keySize) { 167 | $key = substr($key, 0, $keySize); 168 | } 169 | 170 | //Decrypt value 171 | mcrypt_generic_init($module, $key, $iv); 172 | $decryptedData = @mdecrypt_generic($module, $data); 173 | $res = rtrim($decryptedData, "\0"); 174 | mcrypt_generic_deinit($module); 175 | 176 | return $res; 177 | } 178 | 179 | /** 180 | * Serialize Response cookies into raw HTTP header 181 | * @param \Slim\Http\Headers $headers The Response headers 182 | * @param \Slim\Http\Cookies $cookies The Response cookies 183 | * @param array $config The Slim app settings 184 | */ 185 | public static function serializeCookies(\Slim\Http\Headers &$headers, \Slim\Http\Cookies $cookies, array $config) 186 | { 187 | if ($config['cookies.encrypt']) { 188 | foreach ($cookies as $name => $settings) { 189 | if (is_string($settings['expires'])) { 190 | $expires = strtotime($settings['expires']); 191 | } else { 192 | $expires = (int) $settings['expires']; 193 | } 194 | 195 | $settings['value'] = static::encodeSecureCookie( 196 | $settings['value'], 197 | $expires, 198 | $config['cookies.secret_key'], 199 | $config['cookies.cipher'], 200 | $config['cookies.cipher_mode'] 201 | ); 202 | static::setCookieHeader($headers, $name, $settings); 203 | } 204 | } else { 205 | foreach ($cookies as $name => $settings) { 206 | static::setCookieHeader($headers, $name, $settings); 207 | } 208 | } 209 | } 210 | 211 | /** 212 | * Encode secure cookie value 213 | * 214 | * This method will create the secure value of an HTTP cookie. The 215 | * cookie value is encrypted and hashed so that its value is 216 | * secure and checked for integrity when read in subsequent requests. 217 | * 218 | * @param string $value The insecure HTTP cookie value 219 | * @param int $expires The UNIX timestamp at which this cookie will expire 220 | * @param string $secret The secret key used to hash the cookie value 221 | * @param int $algorithm The algorithm to use for encryption 222 | * @param int $mode The algorithm mode to use for encryption 223 | * @return string 224 | */ 225 | public static function encodeSecureCookie($value, $expires, $secret, $algorithm, $mode) 226 | { 227 | $key = hash_hmac('sha1', (string) $expires, $secret); 228 | $iv = self::getIv($expires, $secret); 229 | $secureString = base64_encode( 230 | self::encrypt( 231 | $value, 232 | $key, 233 | $iv, 234 | array( 235 | 'algorithm' => $algorithm, 236 | 'mode' => $mode 237 | ) 238 | ) 239 | ); 240 | $verificationString = hash_hmac('sha1', $expires . $value, $key); 241 | 242 | return implode('|', array($expires, $secureString, $verificationString)); 243 | } 244 | 245 | /** 246 | * Decode secure cookie value 247 | * 248 | * This method will decode the secure value of an HTTP cookie. The 249 | * cookie value is encrypted and hashed so that its value is 250 | * secure and checked for integrity when read in subsequent requests. 251 | * 252 | * @param string $value The secure HTTP cookie value 253 | * @param string $secret The secret key used to hash the cookie value 254 | * @param int $algorithm The algorithm to use for encryption 255 | * @param int $mode The algorithm mode to use for encryption 256 | * @return bool|string 257 | */ 258 | public static function decodeSecureCookie($value, $secret, $algorithm, $mode) 259 | { 260 | if ($value) { 261 | $value = explode('|', $value); 262 | if (count($value) === 3 && ((int) $value[0] === 0 || (int) $value[0] > time())) { 263 | $key = hash_hmac('sha1', $value[0], $secret); 264 | $iv = self::getIv($value[0], $secret); 265 | $data = self::decrypt( 266 | base64_decode($value[1]), 267 | $key, 268 | $iv, 269 | array( 270 | 'algorithm' => $algorithm, 271 | 'mode' => $mode 272 | ) 273 | ); 274 | $verificationString = hash_hmac('sha1', $value[0] . $data, $key); 275 | if ($verificationString === $value[2]) { 276 | return $data; 277 | } 278 | } 279 | } 280 | 281 | return false; 282 | } 283 | 284 | /** 285 | * Set HTTP cookie header 286 | * 287 | * This method will construct and set the HTTP `Set-Cookie` header. Slim 288 | * uses this method instead of PHP's native `setcookie` method. This allows 289 | * more control of the HTTP header irrespective of the native implementation's 290 | * dependency on PHP versions. 291 | * 292 | * This method accepts the Slim_Http_Headers object by reference as its 293 | * first argument; this method directly modifies this object instead of 294 | * returning a value. 295 | * 296 | * @param array $header 297 | * @param string $name 298 | * @param string $value 299 | */ 300 | public static function setCookieHeader(&$header, $name, $value) 301 | { 302 | //Build cookie header 303 | if (is_array($value)) { 304 | $domain = ''; 305 | $path = ''; 306 | $expires = ''; 307 | $secure = ''; 308 | $httponly = ''; 309 | if (isset($value['domain']) && $value['domain']) { 310 | $domain = '; domain=' . $value['domain']; 311 | } 312 | if (isset($value['path']) && $value['path']) { 313 | $path = '; path=' . $value['path']; 314 | } 315 | if (isset($value['expires'])) { 316 | if (is_string($value['expires'])) { 317 | $timestamp = strtotime($value['expires']); 318 | } else { 319 | $timestamp = (int) $value['expires']; 320 | } 321 | if ($timestamp !== 0) { 322 | $expires = '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp); 323 | } 324 | } 325 | if (isset($value['secure']) && $value['secure']) { 326 | $secure = '; secure'; 327 | } 328 | if (isset($value['httponly']) && $value['httponly']) { 329 | $httponly = '; HttpOnly'; 330 | } 331 | $cookie = sprintf('%s=%s%s', urlencode($name), urlencode((string) $value['value']), $domain . $path . $expires . $secure . $httponly); 332 | } else { 333 | $cookie = sprintf('%s=%s', urlencode($name), urlencode((string) $value)); 334 | } 335 | 336 | //Set cookie header 337 | if (!isset($header['Set-Cookie']) || $header['Set-Cookie'] === '') { 338 | $header['Set-Cookie'] = $cookie; 339 | } else { 340 | $header['Set-Cookie'] = implode("\n", array($header['Set-Cookie'], $cookie)); 341 | } 342 | } 343 | 344 | /** 345 | * Delete HTTP cookie header 346 | * 347 | * This method will construct and set the HTTP `Set-Cookie` header to invalidate 348 | * a client-side HTTP cookie. If a cookie with the same name (and, optionally, domain) 349 | * is already set in the HTTP response, it will also be removed. Slim uses this method 350 | * instead of PHP's native `setcookie` method. This allows more control of the HTTP header 351 | * irrespective of PHP's native implementation's dependency on PHP versions. 352 | * 353 | * This method accepts the Slim_Http_Headers object by reference as its 354 | * first argument; this method directly modifies this object instead of 355 | * returning a value. 356 | * 357 | * @param array $header 358 | * @param string $name 359 | * @param array $value 360 | */ 361 | public static function deleteCookieHeader(&$header, $name, $value = array()) 362 | { 363 | //Remove affected cookies from current response header 364 | $cookiesOld = array(); 365 | $cookiesNew = array(); 366 | if (isset($header['Set-Cookie'])) { 367 | $cookiesOld = explode("\n", $header['Set-Cookie']); 368 | } 369 | foreach ($cookiesOld as $c) { 370 | if (isset($value['domain']) && $value['domain']) { 371 | $regex = sprintf('@%s=.*domain=%s@', urlencode($name), preg_quote($value['domain'])); 372 | } else { 373 | $regex = sprintf('@%s=@', urlencode($name)); 374 | } 375 | if (preg_match($regex, $c) === 0) { 376 | $cookiesNew[] = $c; 377 | } 378 | } 379 | if ($cookiesNew) { 380 | $header['Set-Cookie'] = implode("\n", $cookiesNew); 381 | } else { 382 | unset($header['Set-Cookie']); 383 | } 384 | 385 | //Set invalidating cookie to clear client-side cookie 386 | self::setCookieHeader($header, $name, array_merge(array('value' => '', 'path' => null, 'domain' => null, 'expires' => time() - 100), $value)); 387 | } 388 | 389 | /** 390 | * Parse cookie header 391 | * 392 | * This method will parse the HTTP request's `Cookie` header 393 | * and extract cookies into an associative array. 394 | * 395 | * @param string 396 | * @return array 397 | */ 398 | public static function parseCookieHeader($header) 399 | { 400 | $cookies = array(); 401 | $header = rtrim($header, "\r\n"); 402 | $headerPieces = preg_split('@\s*[;,]\s*@', $header); 403 | foreach ($headerPieces as $c) { 404 | $cParts = explode('=', $c, 2); 405 | if (count($cParts) === 2) { 406 | $key = urldecode($cParts[0]); 407 | $value = urldecode($cParts[1]); 408 | if (!isset($cookies[$key])) { 409 | $cookies[$key] = $value; 410 | } 411 | } 412 | } 413 | 414 | return $cookies; 415 | } 416 | 417 | /** 418 | * Generate a random IV 419 | * 420 | * This method will generate a non-predictable IV for use with 421 | * the cookie encryption 422 | * 423 | * @param int $expires The UNIX timestamp at which this cookie will expire 424 | * @param string $secret The secret key used to hash the cookie value 425 | * @return string Hash 426 | */ 427 | private static function getIv($expires, $secret) 428 | { 429 | $data1 = hash_hmac('sha1', 'a'.$expires.'b', $secret); 430 | $data2 = hash_hmac('sha1', 'z'.$expires.'y', $secret); 431 | 432 | return pack("h*", $data1.$data2); 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /api/Slim/Log.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Log 37 | * 38 | * This is the primary logger for a Slim application. You may provide 39 | * a Log Writer in conjunction with this Log to write to various output 40 | * destinations (e.g. a file). This class provides this interface: 41 | * 42 | * debug( mixed $object, array $context ) 43 | * info( mixed $object, array $context ) 44 | * notice( mixed $object, array $context ) 45 | * warning( mixed $object, array $context ) 46 | * error( mixed $object, array $context ) 47 | * critical( mixed $object, array $context ) 48 | * alert( mixed $object, array $context ) 49 | * emergency( mixed $object, array $context ) 50 | * log( mixed $level, mixed $object, array $context ) 51 | * 52 | * This class assumes only that your Log Writer has a public `write()` method 53 | * that accepts any object as its one and only argument. The Log Writer 54 | * class may write or send its argument anywhere: a file, STDERR, 55 | * a remote web API, etc. The possibilities are endless. 56 | * 57 | * @package Slim 58 | * @author Josh Lockhart 59 | * @since 1.0.0 60 | */ 61 | class Log 62 | { 63 | const EMERGENCY = 1; 64 | const ALERT = 2; 65 | const CRITICAL = 3; 66 | const FATAL = 3; //DEPRECATED replace with CRITICAL 67 | const ERROR = 4; 68 | const WARN = 5; 69 | const NOTICE = 6; 70 | const INFO = 7; 71 | const DEBUG = 8; 72 | 73 | /** 74 | * @var array 75 | */ 76 | protected static $levels = array( 77 | self::EMERGENCY => 'EMERGENCY', 78 | self::ALERT => 'ALERT', 79 | self::CRITICAL => 'CRITICAL', 80 | self::ERROR => 'ERROR', 81 | self::WARN => 'WARNING', 82 | self::NOTICE => 'NOTICE', 83 | self::INFO => 'INFO', 84 | self::DEBUG => 'DEBUG' 85 | ); 86 | 87 | /** 88 | * @var mixed 89 | */ 90 | protected $writer; 91 | 92 | /** 93 | * @var bool 94 | */ 95 | protected $enabled; 96 | 97 | /** 98 | * @var int 99 | */ 100 | protected $level; 101 | 102 | /** 103 | * Constructor 104 | * @param mixed $writer 105 | */ 106 | public function __construct($writer) 107 | { 108 | $this->writer = $writer; 109 | $this->enabled = true; 110 | $this->level = self::DEBUG; 111 | } 112 | 113 | /** 114 | * Is logging enabled? 115 | * @return bool 116 | */ 117 | public function getEnabled() 118 | { 119 | return $this->enabled; 120 | } 121 | 122 | /** 123 | * Enable or disable logging 124 | * @param bool $enabled 125 | */ 126 | public function setEnabled($enabled) 127 | { 128 | if ($enabled) { 129 | $this->enabled = true; 130 | } else { 131 | $this->enabled = false; 132 | } 133 | } 134 | 135 | /** 136 | * Set level 137 | * @param int $level 138 | * @throws \InvalidArgumentException If invalid log level specified 139 | */ 140 | public function setLevel($level) 141 | { 142 | if (!isset(self::$levels[$level])) { 143 | throw new \InvalidArgumentException('Invalid log level'); 144 | } 145 | $this->level = $level; 146 | } 147 | 148 | /** 149 | * Get level 150 | * @return int 151 | */ 152 | public function getLevel() 153 | { 154 | return $this->level; 155 | } 156 | 157 | /** 158 | * Set writer 159 | * @param mixed $writer 160 | */ 161 | public function setWriter($writer) 162 | { 163 | $this->writer = $writer; 164 | } 165 | 166 | /** 167 | * Get writer 168 | * @return mixed 169 | */ 170 | public function getWriter() 171 | { 172 | return $this->writer; 173 | } 174 | 175 | /** 176 | * Is logging enabled? 177 | * @return bool 178 | */ 179 | public function isEnabled() 180 | { 181 | return $this->enabled; 182 | } 183 | 184 | /** 185 | * Log debug message 186 | * @param mixed $object 187 | * @param array $context 188 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 189 | */ 190 | public function debug($object, $context = array()) 191 | { 192 | return $this->log(self::DEBUG, $object, $context); 193 | } 194 | 195 | /** 196 | * Log info message 197 | * @param mixed $object 198 | * @param array $context 199 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 200 | */ 201 | public function info($object, $context = array()) 202 | { 203 | return $this->log(self::INFO, $object, $context); 204 | } 205 | 206 | /** 207 | * Log notice message 208 | * @param mixed $object 209 | * @param array $context 210 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 211 | */ 212 | public function notice($object, $context = array()) 213 | { 214 | return $this->log(self::NOTICE, $object, $context); 215 | } 216 | 217 | /** 218 | * Log warning message 219 | * @param mixed $object 220 | * @param array $context 221 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 222 | */ 223 | public function warning($object, $context = array()) 224 | { 225 | return $this->log(self::WARN, $object, $context); 226 | } 227 | 228 | /** 229 | * DEPRECATED for function warning 230 | * Log warning message 231 | * @param mixed $object 232 | * @param array $context 233 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 234 | */ 235 | public function warn($object, $context = array()) 236 | { 237 | return $this->log(self::WARN, $object, $context); 238 | } 239 | 240 | /** 241 | * Log error message 242 | * @param mixed $object 243 | * @param array $context 244 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 245 | */ 246 | public function error($object, $context = array()) 247 | { 248 | return $this->log(self::ERROR, $object, $context); 249 | } 250 | 251 | /** 252 | * Log critical message 253 | * @param mixed $object 254 | * @param array $context 255 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 256 | */ 257 | public function critical($object, $context = array()) 258 | { 259 | return $this->log(self::CRITICAL, $object, $context); 260 | } 261 | 262 | /** 263 | * DEPRECATED for function critical 264 | * Log fatal message 265 | * @param mixed $object 266 | * @param array $context 267 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 268 | */ 269 | public function fatal($object, $context = array()) 270 | { 271 | return $this->log(self::CRITICAL, $object, $context); 272 | } 273 | 274 | /** 275 | * Log alert message 276 | * @param mixed $object 277 | * @param array $context 278 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 279 | */ 280 | public function alert($object, $context = array()) 281 | { 282 | return $this->log(self::ALERT, $object, $context); 283 | } 284 | 285 | /** 286 | * Log emergency message 287 | * @param mixed $object 288 | * @param array $context 289 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 290 | */ 291 | public function emergency($object, $context = array()) 292 | { 293 | return $this->log(self::EMERGENCY, $object, $context); 294 | } 295 | 296 | /** 297 | * Log message 298 | * @param mixed $level 299 | * @param mixed $object 300 | * @param array $context 301 | * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled 302 | * @throws \InvalidArgumentException If invalid log level 303 | */ 304 | public function log($level, $object, $context = array()) 305 | { 306 | if (!isset(self::$levels[$level])) { 307 | throw new \InvalidArgumentException('Invalid log level supplied to function'); 308 | } else if ($this->enabled && $this->writer && $level <= $this->level) { 309 | if (is_array($object) || (is_object($object) && !method_exists($object, "__toString"))) { 310 | $message = print_r($object, true); 311 | } else { 312 | $message = (string) $object; 313 | } 314 | 315 | if (count($context) > 0) { 316 | if (isset($context['exception']) && $context['exception'] instanceof \Exception) { 317 | $message .= ' - ' . $context['exception']; 318 | unset($context['exception']); 319 | } 320 | $message = $this->interpolate($message, $context); 321 | } 322 | return $this->writer->write($message, $level); 323 | } else { 324 | return false; 325 | } 326 | } 327 | 328 | /** 329 | * DEPRECATED for function log 330 | * Log message 331 | * @param mixed $object The object to log 332 | * @param int $level The message level 333 | * @return int|bool 334 | */ 335 | protected function write($object, $level) 336 | { 337 | return $this->log($level, $object); 338 | } 339 | 340 | /** 341 | * Interpolate log message 342 | * @param mixed $message The log message 343 | * @param array $context An array of placeholder values 344 | * @return string The processed string 345 | */ 346 | protected function interpolate($message, $context = array()) 347 | { 348 | $replace = array(); 349 | foreach ($context as $key => $value) { 350 | $replace['{' . $key . '}'] = $value; 351 | } 352 | return strtr($message, $replace); 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /api/Slim/LogWriter.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Log Writer 37 | * 38 | * This class is used by Slim_Log to write log messages to a valid, writable 39 | * resource handle (e.g. a file or STDERR). 40 | * 41 | * @package Slim 42 | * @author Josh Lockhart 43 | * @since 1.6.0 44 | */ 45 | class LogWriter 46 | { 47 | /** 48 | * @var resource 49 | */ 50 | protected $resource; 51 | 52 | /** 53 | * Constructor 54 | * @param resource $resource 55 | * @throws \InvalidArgumentException If invalid resource 56 | */ 57 | public function __construct($resource) 58 | { 59 | if (!is_resource($resource)) { 60 | throw new \InvalidArgumentException('Cannot create LogWriter. Invalid resource handle.'); 61 | } 62 | $this->resource = $resource; 63 | } 64 | 65 | /** 66 | * Write message 67 | * @param mixed $message 68 | * @param int $level 69 | * @return int|bool 70 | */ 71 | public function write($message, $level = null) 72 | { 73 | return fwrite($this->resource, (string) $message . PHP_EOL); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /api/Slim/Middleware.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Middleware 37 | * 38 | * @package Slim 39 | * @author Josh Lockhart 40 | * @since 1.6.0 41 | */ 42 | abstract class Middleware 43 | { 44 | /** 45 | * @var \Slim\Slim Reference to the primary application instance 46 | */ 47 | protected $app; 48 | 49 | /** 50 | * @var mixed Reference to the next downstream middleware 51 | */ 52 | protected $next; 53 | 54 | /** 55 | * Set application 56 | * 57 | * This method injects the primary Slim application instance into 58 | * this middleware. 59 | * 60 | * @param \Slim\Slim $application 61 | */ 62 | final public function setApplication($application) 63 | { 64 | $this->app = $application; 65 | } 66 | 67 | /** 68 | * Get application 69 | * 70 | * This method retrieves the application previously injected 71 | * into this middleware. 72 | * 73 | * @return \Slim\Slim 74 | */ 75 | final public function getApplication() 76 | { 77 | return $this->app; 78 | } 79 | 80 | /** 81 | * Set next middleware 82 | * 83 | * This method injects the next downstream middleware into 84 | * this middleware so that it may optionally be called 85 | * when appropriate. 86 | * 87 | * @param \Slim|\Slim\Middleware 88 | */ 89 | final public function setNextMiddleware($nextMiddleware) 90 | { 91 | $this->next = $nextMiddleware; 92 | } 93 | 94 | /** 95 | * Get next middleware 96 | * 97 | * This method retrieves the next downstream middleware 98 | * previously injected into this middleware. 99 | * 100 | * @return \Slim\Slim|\Slim\Middleware 101 | */ 102 | final public function getNextMiddleware() 103 | { 104 | return $this->next; 105 | } 106 | 107 | /** 108 | * Call 109 | * 110 | * Perform actions specific to this middleware and optionally 111 | * call the next downstream middleware. 112 | */ 113 | abstract public function call(); 114 | } 115 | -------------------------------------------------------------------------------- /api/Slim/Middleware/ContentTypes.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Middleware; 34 | 35 | /** 36 | * Content Types 37 | * 38 | * This is middleware for a Slim application that intercepts 39 | * the HTTP request body and parses it into the appropriate 40 | * PHP data structure if possible; else it returns the HTTP 41 | * request body unchanged. This is particularly useful 42 | * for preparing the HTTP request body for an XML or JSON API. 43 | * 44 | * @package Slim 45 | * @author Josh Lockhart 46 | * @since 1.6.0 47 | */ 48 | class ContentTypes extends \Slim\Middleware 49 | { 50 | /** 51 | * @var array 52 | */ 53 | protected $contentTypes; 54 | 55 | /** 56 | * Constructor 57 | * @param array $settings 58 | */ 59 | public function __construct($settings = array()) 60 | { 61 | $defaults = array( 62 | 'application/json' => array($this, 'parseJson'), 63 | 'application/xml' => array($this, 'parseXml'), 64 | 'text/xml' => array($this, 'parseXml'), 65 | 'text/csv' => array($this, 'parseCsv') 66 | ); 67 | $this->contentTypes = array_merge($defaults, $settings); 68 | } 69 | 70 | /** 71 | * Call 72 | */ 73 | public function call() 74 | { 75 | $mediaType = $this->app->request()->getMediaType(); 76 | if ($mediaType) { 77 | $env = $this->app->environment(); 78 | $env['slim.input_original'] = $env['slim.input']; 79 | $env['slim.input'] = $this->parse($env['slim.input'], $mediaType); 80 | } 81 | $this->next->call(); 82 | } 83 | 84 | /** 85 | * Parse input 86 | * 87 | * This method will attempt to parse the request body 88 | * based on its content type if available. 89 | * 90 | * @param string $input 91 | * @param string $contentType 92 | * @return mixed 93 | */ 94 | protected function parse ($input, $contentType) 95 | { 96 | if (isset($this->contentTypes[$contentType]) && is_callable($this->contentTypes[$contentType])) { 97 | $result = call_user_func($this->contentTypes[$contentType], $input); 98 | if ($result) { 99 | return $result; 100 | } 101 | } 102 | 103 | return $input; 104 | } 105 | 106 | /** 107 | * Parse JSON 108 | * 109 | * This method converts the raw JSON input 110 | * into an associative array. 111 | * 112 | * @param string $input 113 | * @return array|string 114 | */ 115 | protected function parseJson($input) 116 | { 117 | if (function_exists('json_decode')) { 118 | $result = json_decode($input, true); 119 | if(json_last_error() === JSON_ERROR_NONE) { 120 | return $result; 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Parse XML 127 | * 128 | * This method creates a SimpleXMLElement 129 | * based upon the XML input. If the SimpleXML 130 | * extension is not available, the raw input 131 | * will be returned unchanged. 132 | * 133 | * @param string $input 134 | * @return \SimpleXMLElement|string 135 | */ 136 | protected function parseXml($input) 137 | { 138 | if (class_exists('SimpleXMLElement')) { 139 | try { 140 | $backup = libxml_disable_entity_loader(true); 141 | $result = new \SimpleXMLElement($input); 142 | libxml_disable_entity_loader($backup); 143 | return $result; 144 | } catch (\Exception $e) { 145 | // Do nothing 146 | } 147 | } 148 | 149 | return $input; 150 | } 151 | 152 | /** 153 | * Parse CSV 154 | * 155 | * This method parses CSV content into a numeric array 156 | * containing an array of data for each CSV line. 157 | * 158 | * @param string $input 159 | * @return array 160 | */ 161 | protected function parseCsv($input) 162 | { 163 | $temp = fopen('php://memory', 'rw'); 164 | fwrite($temp, $input); 165 | fseek($temp, 0); 166 | $res = array(); 167 | while (($data = fgetcsv($temp)) !== false) { 168 | $res[] = $data; 169 | } 170 | fclose($temp); 171 | 172 | return $res; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /api/Slim/Middleware/Flash.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Middleware; 34 | 35 | /** 36 | * Flash 37 | * 38 | * This is middleware for a Slim application that enables 39 | * Flash messaging between HTTP requests. This allows you 40 | * set Flash messages for the current request, for the next request, 41 | * or to retain messages from the previous request through to 42 | * the next request. 43 | * 44 | * @package Slim 45 | * @author Josh Lockhart 46 | * @since 1.6.0 47 | */ 48 | class Flash extends \Slim\Middleware implements \ArrayAccess, \IteratorAggregate, \Countable 49 | { 50 | /** 51 | * @var array 52 | */ 53 | protected $settings; 54 | 55 | /** 56 | * @var array 57 | */ 58 | protected $messages; 59 | 60 | /** 61 | * Constructor 62 | * @param array $settings 63 | */ 64 | public function __construct($settings = array()) 65 | { 66 | $this->settings = array_merge(array('key' => 'slim.flash'), $settings); 67 | $this->messages = array( 68 | 'prev' => array(), //flash messages from prev request (loaded when middleware called) 69 | 'next' => array(), //flash messages for next request 70 | 'now' => array() //flash messages for current request 71 | ); 72 | } 73 | 74 | /** 75 | * Call 76 | */ 77 | public function call() 78 | { 79 | //Read flash messaging from previous request if available 80 | $this->loadMessages(); 81 | 82 | //Prepare flash messaging for current request 83 | $env = $this->app->environment(); 84 | $env['slim.flash'] = $this; 85 | $this->next->call(); 86 | $this->save(); 87 | } 88 | 89 | /** 90 | * Now 91 | * 92 | * Specify a flash message for a given key to be shown for the current request 93 | * 94 | * @param string $key 95 | * @param string $value 96 | */ 97 | public function now($key, $value) 98 | { 99 | $this->messages['now'][(string) $key] = $value; 100 | } 101 | 102 | /** 103 | * Set 104 | * 105 | * Specify a flash message for a given key to be shown for the next request 106 | * 107 | * @param string $key 108 | * @param string $value 109 | */ 110 | public function set($key, $value) 111 | { 112 | $this->messages['next'][(string) $key] = $value; 113 | } 114 | 115 | /** 116 | * Keep 117 | * 118 | * Retain flash messages from the previous request for the next request 119 | */ 120 | public function keep() 121 | { 122 | foreach ($this->messages['prev'] as $key => $val) { 123 | $this->messages['next'][$key] = $val; 124 | } 125 | } 126 | 127 | /** 128 | * Save 129 | */ 130 | public function save() 131 | { 132 | $_SESSION[$this->settings['key']] = $this->messages['next']; 133 | } 134 | 135 | /** 136 | * Load messages from previous request if available 137 | */ 138 | public function loadMessages() 139 | { 140 | if (isset($_SESSION[$this->settings['key']])) { 141 | $this->messages['prev'] = $_SESSION[$this->settings['key']]; 142 | } 143 | } 144 | 145 | /** 146 | * Return array of flash messages to be shown for the current request 147 | * 148 | * @return array 149 | */ 150 | public function getMessages() 151 | { 152 | return array_merge($this->messages['prev'], $this->messages['now']); 153 | } 154 | 155 | /** 156 | * Array Access: Offset Exists 157 | */ 158 | public function offsetExists($offset) 159 | { 160 | $messages = $this->getMessages(); 161 | 162 | return isset($messages[$offset]); 163 | } 164 | 165 | /** 166 | * Array Access: Offset Get 167 | */ 168 | public function offsetGet($offset) 169 | { 170 | $messages = $this->getMessages(); 171 | 172 | return isset($messages[$offset]) ? $messages[$offset] : null; 173 | } 174 | 175 | /** 176 | * Array Access: Offset Set 177 | */ 178 | public function offsetSet($offset, $value) 179 | { 180 | $this->now($offset, $value); 181 | } 182 | 183 | /** 184 | * Array Access: Offset Unset 185 | */ 186 | public function offsetUnset($offset) 187 | { 188 | unset($this->messages['prev'][$offset], $this->messages['now'][$offset]); 189 | } 190 | 191 | /** 192 | * Iterator Aggregate: Get Iterator 193 | * @return \ArrayIterator 194 | */ 195 | public function getIterator() 196 | { 197 | $messages = $this->getMessages(); 198 | 199 | return new \ArrayIterator($messages); 200 | } 201 | 202 | /** 203 | * Countable: Count 204 | */ 205 | public function count() 206 | { 207 | return count($this->getMessages()); 208 | } 209 | 210 | 211 | 212 | } 213 | -------------------------------------------------------------------------------- /api/Slim/Middleware/MethodOverride.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Middleware; 34 | 35 | /** 36 | * HTTP Method Override 37 | * 38 | * This is middleware for a Slim application that allows traditional 39 | * desktop browsers to submit pseudo PUT and DELETE requests by relying 40 | * on a pre-determined request parameter. Without this middleware, 41 | * desktop browsers are only able to submit GET and POST requests. 42 | * 43 | * This middleware is included automatically! 44 | * 45 | * @package Slim 46 | * @author Josh Lockhart 47 | * @since 1.6.0 48 | */ 49 | class MethodOverride extends \Slim\Middleware 50 | { 51 | /** 52 | * @var array 53 | */ 54 | protected $settings; 55 | 56 | /** 57 | * Constructor 58 | * @param array $settings 59 | */ 60 | public function __construct($settings = array()) 61 | { 62 | $this->settings = array_merge(array('key' => '_METHOD'), $settings); 63 | } 64 | 65 | /** 66 | * Call 67 | * 68 | * Implements Slim middleware interface. This method is invoked and passed 69 | * an array of environment variables. This middleware inspects the environment 70 | * variables for the HTTP method override parameter; if found, this middleware 71 | * modifies the environment settings so downstream middleware and/or the Slim 72 | * application will treat the request with the desired HTTP method. 73 | * 74 | * @return array[status, header, body] 75 | */ 76 | public function call() 77 | { 78 | $env = $this->app->environment(); 79 | if (isset($env['HTTP_X_HTTP_METHOD_OVERRIDE'])) { 80 | // Header commonly used by Backbone.js and others 81 | $env['slim.method_override.original_method'] = $env['REQUEST_METHOD']; 82 | $env['REQUEST_METHOD'] = strtoupper($env['HTTP_X_HTTP_METHOD_OVERRIDE']); 83 | } elseif (isset($env['REQUEST_METHOD']) && $env['REQUEST_METHOD'] === 'POST') { 84 | // HTML Form Override 85 | $req = new \Slim\Http\Request($env); 86 | $method = $req->post($this->settings['key']); 87 | if ($method) { 88 | $env['slim.method_override.original_method'] = $env['REQUEST_METHOD']; 89 | $env['REQUEST_METHOD'] = strtoupper($method); 90 | } 91 | } 92 | $this->next->call(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /api/Slim/Middleware/PrettyExceptions.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Middleware; 34 | 35 | /** 36 | * Pretty Exceptions 37 | * 38 | * This middleware catches any Exception thrown by the surrounded 39 | * application and displays a developer-friendly diagnostic screen. 40 | * 41 | * @package Slim 42 | * @author Josh Lockhart 43 | * @since 1.0.0 44 | */ 45 | class PrettyExceptions extends \Slim\Middleware 46 | { 47 | /** 48 | * @var array 49 | */ 50 | protected $settings; 51 | 52 | /** 53 | * Constructor 54 | * @param array $settings 55 | */ 56 | public function __construct($settings = array()) 57 | { 58 | $this->settings = $settings; 59 | } 60 | 61 | /** 62 | * Call 63 | */ 64 | public function call() 65 | { 66 | try { 67 | $this->next->call(); 68 | } catch (\Exception $e) { 69 | $log = $this->app->getLog(); // Force Slim to append log to env if not already 70 | $env = $this->app->environment(); 71 | $env['slim.log'] = $log; 72 | $env['slim.log']->error($e); 73 | $this->app->contentType('text/html'); 74 | $this->app->response()->status(500); 75 | $this->app->response()->body($this->renderBody($env, $e)); 76 | } 77 | } 78 | 79 | /** 80 | * Render response body 81 | * @param array $env 82 | * @param \Exception $exception 83 | * @return string 84 | */ 85 | protected function renderBody(&$env, $exception) 86 | { 87 | $title = 'Slim Application Error'; 88 | $code = $exception->getCode(); 89 | $message = $exception->getMessage(); 90 | $file = $exception->getFile(); 91 | $line = $exception->getLine(); 92 | $trace = str_replace(array('#', "\n"), array('
#', '
'), $exception->getTraceAsString()); 93 | $html = sprintf('

%s

', $title); 94 | $html .= '

The application could not run because of the following error:

'; 95 | $html .= '

Details

'; 96 | $html .= sprintf('
Type: %s
', get_class($exception)); 97 | if ($code) { 98 | $html .= sprintf('
Code: %s
', $code); 99 | } 100 | if ($message) { 101 | $html .= sprintf('
Message: %s
', $message); 102 | } 103 | if ($file) { 104 | $html .= sprintf('
File: %s
', $file); 105 | } 106 | if ($line) { 107 | $html .= sprintf('
Line: %s
', $line); 108 | } 109 | if ($trace) { 110 | $html .= '

Trace

'; 111 | $html .= sprintf('
%s
', $trace); 112 | } 113 | 114 | return sprintf("%s%s", $title, $html); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /api/Slim/Middleware/SessionCookie.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim\Middleware; 34 | 35 | /** 36 | * Session Cookie 37 | * 38 | * This class provides an HTTP cookie storage mechanism 39 | * for session data. This class avoids using a PHP session 40 | * and instead serializes/unserializes the $_SESSION global 41 | * variable to/from an HTTP cookie. 42 | * 43 | * You should NEVER store sensitive data in a client-side cookie 44 | * in any format, encrypted (with cookies.encrypt) or not. If you 45 | * need to store sensitive user information in a session, you should 46 | * rely on PHP's native session implementation, or use other middleware 47 | * to store session data in a database or alternative server-side cache. 48 | * 49 | * Because this class stores serialized session data in an HTTP cookie, 50 | * you are inherently limited to 4 Kb. If you attempt to store 51 | * more than this amount, serialization will fail. 52 | * 53 | * @package Slim 54 | * @author Josh Lockhart 55 | * @since 1.6.0 56 | */ 57 | class SessionCookie extends \Slim\Middleware 58 | { 59 | /** 60 | * @var array 61 | */ 62 | protected $settings; 63 | 64 | /** 65 | * Constructor 66 | * 67 | * @param array $settings 68 | */ 69 | public function __construct($settings = array()) 70 | { 71 | $defaults = array( 72 | 'expires' => '20 minutes', 73 | 'path' => '/', 74 | 'domain' => null, 75 | 'secure' => false, 76 | 'httponly' => false, 77 | 'name' => 'slim_session', 78 | ); 79 | $this->settings = array_merge($defaults, $settings); 80 | if (is_string($this->settings['expires'])) { 81 | $this->settings['expires'] = strtotime($this->settings['expires']); 82 | } 83 | 84 | /** 85 | * Session 86 | * 87 | * We must start a native PHP session to initialize the $_SESSION superglobal. 88 | * However, we won't be using the native session store for persistence, so we 89 | * disable the session cookie and cache limiter. We also set the session 90 | * handler to this class instance to avoid PHP's native session file locking. 91 | */ 92 | ini_set('session.use_cookies', 0); 93 | session_cache_limiter(false); 94 | session_set_save_handler( 95 | array($this, 'open'), 96 | array($this, 'close'), 97 | array($this, 'read'), 98 | array($this, 'write'), 99 | array($this, 'destroy'), 100 | array($this, 'gc') 101 | ); 102 | } 103 | 104 | /** 105 | * Call 106 | */ 107 | public function call() 108 | { 109 | $this->loadSession(); 110 | $this->next->call(); 111 | $this->saveSession(); 112 | } 113 | 114 | /** 115 | * Load session 116 | */ 117 | protected function loadSession() 118 | { 119 | if (session_id() === '') { 120 | session_start(); 121 | } 122 | $value = $this->app->getCookie($this->settings['name']); 123 | if ($value) { 124 | $value = json_decode($value, true); 125 | $_SESSION = is_array($value) ? $value : array(); 126 | } else { 127 | $_SESSION = array(); 128 | } 129 | } 130 | 131 | /** 132 | * Save session 133 | */ 134 | protected function saveSession() 135 | { 136 | $value = json_encode($_SESSION); 137 | 138 | if (strlen($value) > 4096) { 139 | $this->app->getLog()->error('WARNING! Slim\Middleware\SessionCookie data size is larger than 4KB. Content save failed.'); 140 | } else { 141 | $this->app->setCookie( 142 | $this->settings['name'], 143 | $value, 144 | $this->settings['expires'], 145 | $this->settings['path'], 146 | $this->settings['domain'], 147 | $this->settings['secure'], 148 | $this->settings['httponly'] 149 | ); 150 | } 151 | // session_destroy(); 152 | } 153 | 154 | /******************************************************************************** 155 | * Session Handler 156 | *******************************************************************************/ 157 | 158 | /** 159 | * @codeCoverageIgnore 160 | */ 161 | public function open($savePath, $sessionName) 162 | { 163 | return true; 164 | } 165 | 166 | /** 167 | * @codeCoverageIgnore 168 | */ 169 | public function close() 170 | { 171 | return true; 172 | } 173 | 174 | /** 175 | * @codeCoverageIgnore 176 | */ 177 | public function read($id) 178 | { 179 | return ''; 180 | } 181 | 182 | /** 183 | * @codeCoverageIgnore 184 | */ 185 | public function write($id, $data) 186 | { 187 | return true; 188 | } 189 | 190 | /** 191 | * @codeCoverageIgnore 192 | */ 193 | public function destroy($id) 194 | { 195 | return true; 196 | } 197 | 198 | /** 199 | * @codeCoverageIgnore 200 | */ 201 | public function gc($maxlifetime) 202 | { 203 | return true; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /api/Slim/Route.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Route 37 | * @package Slim 38 | * @author Josh Lockhart, Thomas Bley 39 | * @since 1.0.0 40 | */ 41 | class Route 42 | { 43 | /** 44 | * @var string The route pattern (e.g. "/books/:id") 45 | */ 46 | protected $pattern; 47 | 48 | /** 49 | * @var mixed The route callable 50 | */ 51 | protected $callable; 52 | 53 | /** 54 | * @var array Conditions for this route's URL parameters 55 | */ 56 | protected $conditions = array(); 57 | 58 | /** 59 | * @var array Default conditions applied to all route instances 60 | */ 61 | protected static $defaultConditions = array(); 62 | 63 | /** 64 | * @var string The name of this route (optional) 65 | */ 66 | protected $name; 67 | 68 | /** 69 | * @var array Key-value array of URL parameters 70 | */ 71 | protected $params = array(); 72 | 73 | /** 74 | * @var array value array of URL parameter names 75 | */ 76 | protected $paramNames = array(); 77 | 78 | /** 79 | * @var array key array of URL parameter names with + at the end 80 | */ 81 | protected $paramNamesPath = array(); 82 | 83 | /** 84 | * @var array HTTP methods supported by this Route 85 | */ 86 | protected $methods = array(); 87 | 88 | /** 89 | * @var array[Callable] Middleware to be run before only this route instance 90 | */ 91 | protected $middleware = array(); 92 | 93 | /** 94 | * @var bool Whether or not this route should be matched in a case-sensitive manner 95 | */ 96 | protected $caseSensitive; 97 | 98 | /** 99 | * Constructor 100 | * @param string $pattern The URL pattern (e.g. "/books/:id") 101 | * @param mixed $callable Anything that returns TRUE for is_callable() 102 | * @param bool $caseSensitive Whether or not this route should be matched in a case-sensitive manner 103 | */ 104 | public function __construct($pattern, $callable, $caseSensitive = true) 105 | { 106 | $this->setPattern($pattern); 107 | $this->setCallable($callable); 108 | $this->setConditions(self::getDefaultConditions()); 109 | $this->caseSensitive = $caseSensitive; 110 | } 111 | 112 | /** 113 | * Set default route conditions for all instances 114 | * @param array $defaultConditions 115 | */ 116 | public static function setDefaultConditions(array $defaultConditions) 117 | { 118 | self::$defaultConditions = $defaultConditions; 119 | } 120 | 121 | /** 122 | * Get default route conditions for all instances 123 | * @return array 124 | */ 125 | public static function getDefaultConditions() 126 | { 127 | return self::$defaultConditions; 128 | } 129 | 130 | /** 131 | * Get route pattern 132 | * @return string 133 | */ 134 | public function getPattern() 135 | { 136 | return $this->pattern; 137 | } 138 | 139 | /** 140 | * Set route pattern 141 | * @param string $pattern 142 | */ 143 | public function setPattern($pattern) 144 | { 145 | $this->pattern = $pattern; 146 | } 147 | 148 | /** 149 | * Get route callable 150 | * @return mixed 151 | */ 152 | public function getCallable() 153 | { 154 | return $this->callable; 155 | } 156 | 157 | /** 158 | * Set route callable 159 | * @param mixed $callable 160 | * @throws \InvalidArgumentException If argument is not callable 161 | */ 162 | public function setCallable($callable) 163 | { 164 | $matches = array(); 165 | if (is_string($callable) && preg_match('!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', $callable, $matches)) { 166 | $class = $matches[1]; 167 | $method = $matches[2]; 168 | $callable = function() use ($class, $method) { 169 | static $obj = null; 170 | if ($obj === null) { 171 | $obj = new $class; 172 | } 173 | return call_user_func_array(array($obj, $method), func_get_args()); 174 | }; 175 | } 176 | 177 | if (!is_callable($callable)) { 178 | throw new \InvalidArgumentException('Route callable must be callable'); 179 | } 180 | 181 | $this->callable = $callable; 182 | } 183 | 184 | /** 185 | * Get route conditions 186 | * @return array 187 | */ 188 | public function getConditions() 189 | { 190 | return $this->conditions; 191 | } 192 | 193 | /** 194 | * Set route conditions 195 | * @param array $conditions 196 | */ 197 | public function setConditions(array $conditions) 198 | { 199 | $this->conditions = $conditions; 200 | } 201 | 202 | /** 203 | * Get route name 204 | * @return string|null 205 | */ 206 | public function getName() 207 | { 208 | return $this->name; 209 | } 210 | 211 | /** 212 | * Set route name 213 | * @param string $name 214 | */ 215 | public function setName($name) 216 | { 217 | $this->name = (string)$name; 218 | } 219 | 220 | /** 221 | * Get route parameters 222 | * @return array 223 | */ 224 | public function getParams() 225 | { 226 | return $this->params; 227 | } 228 | 229 | /** 230 | * Set route parameters 231 | * @param array $params 232 | */ 233 | public function setParams($params) 234 | { 235 | $this->params = $params; 236 | } 237 | 238 | /** 239 | * Get route parameter value 240 | * @param string $index Name of URL parameter 241 | * @return string 242 | * @throws \InvalidArgumentException If route parameter does not exist at index 243 | */ 244 | public function getParam($index) 245 | { 246 | if (!isset($this->params[$index])) { 247 | throw new \InvalidArgumentException('Route parameter does not exist at specified index'); 248 | } 249 | 250 | return $this->params[$index]; 251 | } 252 | 253 | /** 254 | * Set route parameter value 255 | * @param string $index Name of URL parameter 256 | * @param mixed $value The new parameter value 257 | * @throws \InvalidArgumentException If route parameter does not exist at index 258 | */ 259 | public function setParam($index, $value) 260 | { 261 | if (!isset($this->params[$index])) { 262 | throw new \InvalidArgumentException('Route parameter does not exist at specified index'); 263 | } 264 | $this->params[$index] = $value; 265 | } 266 | 267 | /** 268 | * Add supported HTTP method(s) 269 | */ 270 | public function setHttpMethods() 271 | { 272 | $args = func_get_args(); 273 | $this->methods = $args; 274 | } 275 | 276 | /** 277 | * Get supported HTTP methods 278 | * @return array 279 | */ 280 | public function getHttpMethods() 281 | { 282 | return $this->methods; 283 | } 284 | 285 | /** 286 | * Append supported HTTP methods 287 | */ 288 | public function appendHttpMethods() 289 | { 290 | $args = func_get_args(); 291 | if(count($args) && is_array($args[0])){ 292 | $args = $args[0]; 293 | } 294 | $this->methods = array_merge($this->methods, $args); 295 | } 296 | 297 | /** 298 | * Append supported HTTP methods (alias for Route::appendHttpMethods) 299 | * @return \Slim\Route 300 | */ 301 | public function via() 302 | { 303 | $args = func_get_args(); 304 | if(count($args) && is_array($args[0])){ 305 | $args = $args[0]; 306 | } 307 | $this->methods = array_merge($this->methods, $args); 308 | 309 | return $this; 310 | } 311 | 312 | /** 313 | * Detect support for an HTTP method 314 | * @param string $method 315 | * @return bool 316 | */ 317 | public function supportsHttpMethod($method) 318 | { 319 | return in_array($method, $this->methods); 320 | } 321 | 322 | /** 323 | * Get middleware 324 | * @return array[Callable] 325 | */ 326 | public function getMiddleware() 327 | { 328 | return $this->middleware; 329 | } 330 | 331 | /** 332 | * Set middleware 333 | * 334 | * This method allows middleware to be assigned to a specific Route. 335 | * If the method argument `is_callable` (including callable arrays!), 336 | * we directly append the argument to `$this->middleware`. Else, we 337 | * assume the argument is an array of callables and merge the array 338 | * with `$this->middleware`. Each middleware is checked for is_callable() 339 | * and an InvalidArgumentException is thrown immediately if it isn't. 340 | * 341 | * @param Callable|array[Callable] 342 | * @return \Slim\Route 343 | * @throws \InvalidArgumentException If argument is not callable or not an array of callables. 344 | */ 345 | public function setMiddleware($middleware) 346 | { 347 | if (is_callable($middleware)) { 348 | $this->middleware[] = $middleware; 349 | } elseif (is_array($middleware)) { 350 | foreach ($middleware as $callable) { 351 | if (!is_callable($callable)) { 352 | throw new \InvalidArgumentException('All Route middleware must be callable'); 353 | } 354 | } 355 | $this->middleware = array_merge($this->middleware, $middleware); 356 | } else { 357 | throw new \InvalidArgumentException('Route middleware must be callable or an array of callables'); 358 | } 359 | 360 | return $this; 361 | } 362 | 363 | /** 364 | * Matches URI? 365 | * 366 | * Parse this route's pattern, and then compare it to an HTTP resource URI 367 | * This method was modeled after the techniques demonstrated by Dan Sosedoff at: 368 | * 369 | * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/ 370 | * 371 | * @param string $resourceUri A Request URI 372 | * @return bool 373 | */ 374 | public function matches($resourceUri) 375 | { 376 | //Convert URL params into regex patterns, construct a regex for this route, init params 377 | $patternAsRegex = preg_replace_callback( 378 | '#:([\w]+)\+?#', 379 | array($this, 'matchesCallback'), 380 | str_replace(')', ')?', (string)$this->pattern) 381 | ); 382 | if (substr($this->pattern, -1) === '/') { 383 | $patternAsRegex .= '?'; 384 | } 385 | 386 | $regex = '#^' . $patternAsRegex . '$#'; 387 | 388 | if ($this->caseSensitive === false) { 389 | $regex .= 'i'; 390 | } 391 | 392 | //Cache URL params' names and values if this route matches the current HTTP request 393 | if (!preg_match($regex, $resourceUri, $paramValues)) { 394 | return false; 395 | } 396 | foreach ($this->paramNames as $name) { 397 | if (isset($paramValues[$name])) { 398 | if (isset($this->paramNamesPath[$name])) { 399 | $this->params[$name] = explode('/', urldecode($paramValues[$name])); 400 | } else { 401 | $this->params[$name] = urldecode($paramValues[$name]); 402 | } 403 | } 404 | } 405 | 406 | return true; 407 | } 408 | 409 | /** 410 | * Convert a URL parameter (e.g. ":id", ":id+") into a regular expression 411 | * @param array $m URL parameters 412 | * @return string Regular expression for URL parameter 413 | */ 414 | protected function matchesCallback($m) 415 | { 416 | $this->paramNames[] = $m[1]; 417 | if (isset($this->conditions[$m[1]])) { 418 | return '(?P<' . $m[1] . '>' . $this->conditions[$m[1]] . ')'; 419 | } 420 | if (substr($m[0], -1) === '+') { 421 | $this->paramNamesPath[$m[1]] = 1; 422 | 423 | return '(?P<' . $m[1] . '>.+)'; 424 | } 425 | 426 | return '(?P<' . $m[1] . '>[^/]+)'; 427 | } 428 | 429 | /** 430 | * Set route name 431 | * @param string $name The name of the route 432 | * @return \Slim\Route 433 | */ 434 | public function name($name) 435 | { 436 | $this->setName($name); 437 | 438 | return $this; 439 | } 440 | 441 | /** 442 | * Merge route conditions 443 | * @param array $conditions Key-value array of URL parameter conditions 444 | * @return \Slim\Route 445 | */ 446 | public function conditions(array $conditions) 447 | { 448 | $this->conditions = array_merge($this->conditions, $conditions); 449 | 450 | return $this; 451 | } 452 | 453 | /** 454 | * Dispatch route 455 | * 456 | * This method invokes the route object's callable. If middleware is 457 | * registered for the route, each callable middleware is invoked in 458 | * the order specified. 459 | * 460 | * @return bool 461 | */ 462 | public function dispatch() 463 | { 464 | foreach ($this->middleware as $mw) { 465 | call_user_func_array($mw, array($this)); 466 | } 467 | 468 | $return = call_user_func_array($this->getCallable(), array_values($this->getParams())); 469 | return ($return === false) ? false : true; 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /api/Slim/Router.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * Router 37 | * 38 | * This class organizes, iterates, and dispatches \Slim\Route objects. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Router 45 | { 46 | /** 47 | * @var Route The current route (most recently dispatched) 48 | */ 49 | protected $currentRoute; 50 | 51 | /** 52 | * @var array Lookup hash of all route objects 53 | */ 54 | protected $routes; 55 | 56 | /** 57 | * @var array Lookup hash of named route objects, keyed by route name (lazy-loaded) 58 | */ 59 | protected $namedRoutes; 60 | 61 | /** 62 | * @var array Array of route objects that match the request URI (lazy-loaded) 63 | */ 64 | protected $matchedRoutes; 65 | 66 | /** 67 | * @var array Array containing all route groups 68 | */ 69 | protected $routeGroups; 70 | 71 | /** 72 | * Constructor 73 | */ 74 | public function __construct() 75 | { 76 | $this->routes = array(); 77 | $this->routeGroups = array(); 78 | } 79 | 80 | /** 81 | * Get Current Route object or the first matched one if matching has been performed 82 | * @return \Slim\Route|null 83 | */ 84 | public function getCurrentRoute() 85 | { 86 | if ($this->currentRoute !== null) { 87 | return $this->currentRoute; 88 | } 89 | 90 | if (is_array($this->matchedRoutes) && count($this->matchedRoutes) > 0) { 91 | return $this->matchedRoutes[0]; 92 | } 93 | 94 | return null; 95 | } 96 | 97 | /** 98 | * Return route objects that match the given HTTP method and URI 99 | * @param string $httpMethod The HTTP method to match against 100 | * @param string $resourceUri The resource URI to match against 101 | * @param bool $reload Should matching routes be re-parsed? 102 | * @return array[\Slim\Route] 103 | */ 104 | public function getMatchedRoutes($httpMethod, $resourceUri, $reload = false) 105 | { 106 | if ($reload || is_null($this->matchedRoutes)) { 107 | $this->matchedRoutes = array(); 108 | foreach ($this->routes as $route) { 109 | if (!$route->supportsHttpMethod($httpMethod) && !$route->supportsHttpMethod("ANY")) { 110 | continue; 111 | } 112 | 113 | if ($route->matches($resourceUri)) { 114 | $this->matchedRoutes[] = $route; 115 | } 116 | } 117 | } 118 | 119 | return $this->matchedRoutes; 120 | } 121 | 122 | /** 123 | * Add a route object to the router 124 | * @param \Slim\Route $route The Slim Route 125 | */ 126 | public function map(\Slim\Route $route) 127 | { 128 | list($groupPattern, $groupMiddleware) = $this->processGroups(); 129 | 130 | $route->setPattern($groupPattern . $route->getPattern()); 131 | $this->routes[] = $route; 132 | 133 | 134 | foreach ($groupMiddleware as $middleware) { 135 | $route->setMiddleware($middleware); 136 | } 137 | } 138 | 139 | /** 140 | * A helper function for processing the group's pattern and middleware 141 | * @return array Returns an array with the elements: pattern, middlewareArr 142 | */ 143 | protected function processGroups() 144 | { 145 | $pattern = ""; 146 | $middleware = array(); 147 | foreach ($this->routeGroups as $group) { 148 | $k = key($group); 149 | $pattern .= $k; 150 | if (is_array($group[$k])) { 151 | $middleware = array_merge($middleware, $group[$k]); 152 | } 153 | } 154 | return array($pattern, $middleware); 155 | } 156 | 157 | /** 158 | * Add a route group to the array 159 | * @param string $group The group pattern (ie. "/books/:id") 160 | * @param array|null $middleware Optional parameter array of middleware 161 | * @return int The index of the new group 162 | */ 163 | public function pushGroup($group, $middleware = array()) 164 | { 165 | return array_push($this->routeGroups, array($group => $middleware)); 166 | } 167 | 168 | /** 169 | * Removes the last route group from the array 170 | * @return bool True if successful, else False 171 | */ 172 | public function popGroup() 173 | { 174 | return (array_pop($this->routeGroups) !== null); 175 | } 176 | 177 | /** 178 | * Get URL for named route 179 | * @param string $name The name of the route 180 | * @param array $params Associative array of URL parameter names and replacement values 181 | * @throws \RuntimeException If named route not found 182 | * @return string The URL for the given route populated with provided replacement values 183 | */ 184 | public function urlFor($name, $params = array()) 185 | { 186 | if (!$this->hasNamedRoute($name)) { 187 | throw new \RuntimeException('Named route not found for name: ' . $name); 188 | } 189 | $search = array(); 190 | foreach ($params as $key => $value) { 191 | $search[] = '#:' . preg_quote($key, '#') . '\+?(?!\w)#'; 192 | } 193 | $pattern = preg_replace($search, $params, $this->getNamedRoute($name)->getPattern()); 194 | 195 | //Remove remnants of unpopulated, trailing optional pattern segments, escaped special characters 196 | return preg_replace('#\(/?:.+\)|\(|\)|\\\\#', '', $pattern); 197 | } 198 | 199 | /** 200 | * Add named route 201 | * @param string $name The route name 202 | * @param \Slim\Route $route The route object 203 | * @throws \RuntimeException If a named route already exists with the same name 204 | */ 205 | public function addNamedRoute($name, \Slim\Route $route) 206 | { 207 | if ($this->hasNamedRoute($name)) { 208 | throw new \RuntimeException('Named route already exists with name: ' . $name); 209 | } 210 | $this->namedRoutes[(string) $name] = $route; 211 | } 212 | 213 | /** 214 | * Has named route 215 | * @param string $name The route name 216 | * @return bool 217 | */ 218 | public function hasNamedRoute($name) 219 | { 220 | $this->getNamedRoutes(); 221 | 222 | return isset($this->namedRoutes[(string) $name]); 223 | } 224 | 225 | /** 226 | * Get named route 227 | * @param string $name 228 | * @return \Slim\Route|null 229 | */ 230 | public function getNamedRoute($name) 231 | { 232 | $this->getNamedRoutes(); 233 | if ($this->hasNamedRoute($name)) { 234 | return $this->namedRoutes[(string) $name]; 235 | } 236 | 237 | return null; 238 | } 239 | 240 | /** 241 | * Get named routes 242 | * @return \ArrayIterator 243 | */ 244 | public function getNamedRoutes() 245 | { 246 | if (is_null($this->namedRoutes)) { 247 | $this->namedRoutes = array(); 248 | foreach ($this->routes as $route) { 249 | if ($route->getName() !== null) { 250 | $this->addNamedRoute($route->getName(), $route); 251 | } 252 | } 253 | } 254 | 255 | return new \ArrayIterator($this->namedRoutes); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /api/Slim/View.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 2.6.1 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | namespace Slim; 34 | 35 | /** 36 | * View 37 | * 38 | * The view is responsible for rendering a template. The view 39 | * should subclass \Slim\View and implement this interface: 40 | * 41 | * public render(string $template); 42 | * 43 | * This method should render the specified template and return 44 | * the resultant string. 45 | * 46 | * @package Slim 47 | * @author Josh Lockhart 48 | * @since 1.0.0 49 | */ 50 | class View 51 | { 52 | /** 53 | * Data available to the view templates 54 | * @var \Slim\Helper\Set 55 | */ 56 | protected $data; 57 | 58 | /** 59 | * Path to templates base directory (without trailing slash) 60 | * @var string 61 | */ 62 | protected $templatesDirectory; 63 | 64 | /** 65 | * Constructor 66 | */ 67 | public function __construct() 68 | { 69 | $this->data = new \Slim\Helper\Set(); 70 | } 71 | 72 | /******************************************************************************** 73 | * Data methods 74 | *******************************************************************************/ 75 | 76 | /** 77 | * Does view data have value with key? 78 | * @param string $key 79 | * @return boolean 80 | */ 81 | public function has($key) 82 | { 83 | return $this->data->has($key); 84 | } 85 | 86 | /** 87 | * Return view data value with key 88 | * @param string $key 89 | * @return mixed 90 | */ 91 | public function get($key) 92 | { 93 | return $this->data->get($key); 94 | } 95 | 96 | /** 97 | * Set view data value with key 98 | * @param string $key 99 | * @param mixed $value 100 | */ 101 | public function set($key, $value) 102 | { 103 | $this->data->set($key, $value); 104 | } 105 | 106 | /** 107 | * Set view data value as Closure with key 108 | * @param string $key 109 | * @param mixed $value 110 | */ 111 | public function keep($key, \Closure $value) 112 | { 113 | $this->data->keep($key, $value); 114 | } 115 | 116 | /** 117 | * Return view data 118 | * @return array 119 | */ 120 | public function all() 121 | { 122 | return $this->data->all(); 123 | } 124 | 125 | /** 126 | * Replace view data 127 | * @param array $data 128 | */ 129 | public function replace(array $data) 130 | { 131 | $this->data->replace($data); 132 | } 133 | 134 | /** 135 | * Clear view data 136 | */ 137 | public function clear() 138 | { 139 | $this->data->clear(); 140 | } 141 | 142 | /******************************************************************************** 143 | * Legacy data methods 144 | *******************************************************************************/ 145 | 146 | /** 147 | * DEPRECATION WARNING! This method will be removed in the next major point release 148 | * 149 | * Get data from view 150 | */ 151 | public function getData($key = null) 152 | { 153 | if (!is_null($key)) { 154 | return isset($this->data[$key]) ? $this->data[$key] : null; 155 | } 156 | 157 | return $this->data->all(); 158 | } 159 | 160 | /** 161 | * DEPRECATION WARNING! This method will be removed in the next major point release 162 | * 163 | * Set data for view 164 | */ 165 | public function setData() 166 | { 167 | $args = func_get_args(); 168 | if (count($args) === 1 && is_array($args[0])) { 169 | $this->data->replace($args[0]); 170 | } elseif (count($args) === 2) { 171 | // Ensure original behavior is maintained. DO NOT invoke stored Closures. 172 | if (is_object($args[1]) && method_exists($args[1], '__invoke')) { 173 | $this->data->set($args[0], $this->data->protect($args[1])); 174 | } else { 175 | $this->data->set($args[0], $args[1]); 176 | } 177 | } else { 178 | throw new \InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`'); 179 | } 180 | } 181 | 182 | /** 183 | * DEPRECATION WARNING! This method will be removed in the next major point release 184 | * 185 | * Append data to view 186 | * @param array $data 187 | */ 188 | public function appendData($data) 189 | { 190 | if (!is_array($data)) { 191 | throw new \InvalidArgumentException('Cannot append view data. Expected array argument.'); 192 | } 193 | $this->data->replace($data); 194 | } 195 | 196 | /******************************************************************************** 197 | * Resolve template paths 198 | *******************************************************************************/ 199 | 200 | /** 201 | * Set the base directory that contains view templates 202 | * @param string $directory 203 | * @throws \InvalidArgumentException If directory is not a directory 204 | */ 205 | public function setTemplatesDirectory($directory) 206 | { 207 | $this->templatesDirectory = rtrim($directory, DIRECTORY_SEPARATOR); 208 | } 209 | 210 | /** 211 | * Get templates base directory 212 | * @return string 213 | */ 214 | public function getTemplatesDirectory() 215 | { 216 | return $this->templatesDirectory; 217 | } 218 | 219 | /** 220 | * Get fully qualified path to template file using templates base directory 221 | * @param string $file The template file pathname relative to templates base directory 222 | * @return string 223 | */ 224 | public function getTemplatePathname($file) 225 | { 226 | return $this->templatesDirectory . DIRECTORY_SEPARATOR . ltrim($file, DIRECTORY_SEPARATOR); 227 | } 228 | 229 | /******************************************************************************** 230 | * Rendering 231 | *******************************************************************************/ 232 | 233 | /** 234 | * Display template 235 | * 236 | * This method echoes the rendered template to the current output buffer 237 | * 238 | * @param string $template Pathname of template file relative to templates directory 239 | * @param array $data Any additonal data to be passed to the template. 240 | */ 241 | public function display($template, $data = null) 242 | { 243 | echo $this->fetch($template, $data); 244 | } 245 | 246 | /** 247 | * Return the contents of a rendered template file 248 | * 249 | * @param string $template The template pathname, relative to the template base directory 250 | * @param array $data Any additonal data to be passed to the template. 251 | * @return string The rendered template 252 | */ 253 | public function fetch($template, $data = null) 254 | { 255 | return $this->render($template, $data); 256 | } 257 | 258 | /** 259 | * Render a template file 260 | * 261 | * NOTE: This method should be overridden by custom view subclasses 262 | * 263 | * @param string $template The template pathname, relative to the template base directory 264 | * @param array $data Any additonal data to be passed to the template. 265 | * @return string The rendered template 266 | * @throws \RuntimeException If resolved template pathname is not a valid file 267 | */ 268 | protected function render($template, $data = null) 269 | { 270 | $templatePathname = $this->getTemplatePathname($template); 271 | if (!is_file($templatePathname)) { 272 | throw new \RuntimeException("View cannot render `$template` because the template does not exist"); 273 | } 274 | 275 | $data = array_merge($this->data->all(), (array) $data); 276 | extract($data); 277 | ob_start(); 278 | require $templatePathname; 279 | 280 | return ob_get_clean(); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /api/index.php: -------------------------------------------------------------------------------- 1 | post( '/do_login', 'doLogin' ); //login 8 | $app->get( '/is_login', 'isLogin' ); //check if login\ 9 | $app->get( '/logout', 'logout' ); // logout 10 | $app->get( '/products', 'getProducts');// get all the products 11 | $app->post( '/add_product', 'addProduct'); // add product 12 | $app->put( '/delete_product/:id', 'deleteProduct' );// dekete specifi product 13 | $app->get( '/get_product/:id', 'getProduct'); // get product by id 14 | $app->put( '/edit_product/:id', 'updateProduct' ); 15 | 16 | $app->run(); 17 | function isLogin() { 18 | session_start(); 19 | if( isset($_SESSION['username']) && !empty($_SESSION['username'])) 20 | echo '{"isLogin": true}'; 21 | else 22 | echo '{"isLogin": false}'; 23 | } 24 | function logout() { 25 | session_start(); 26 | session_destroy(); 27 | } 28 | function doLogin() { 29 | 30 | $request = \Slim\Slim::getInstance()->request(); 31 | $user = json_decode($request->getBody()); 32 | 33 | $sql = "SELECT * FROM users WHERE username=:username AND password=:password"; 34 | try { 35 | $db = getConnection(); 36 | $stmt = $db->prepare($sql); 37 | $stmt->bindParam("username", $user->username); 38 | $stmt->bindParam("password", $user->password); 39 | $stmt->execute(); 40 | $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); 41 | $db = null; 42 | if( count($rows) ) { 43 | session_start(); 44 | $_SESSION['username'] = $user->username; 45 | 46 | echo '{"status": "success"}'; 47 | } 48 | else { 49 | echo '{"status": "failed"}'; 50 | } 51 | } catch(PDOException $e) { 52 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 53 | } 54 | } 55 | 56 | function getProducts() { 57 | $sql = "select * FROM products WHERE deleted=0 ORDER BY product_id"; 58 | try { 59 | $db = getConnection(); 60 | $stmt = $db->query($sql); 61 | $products = $stmt->fetchAll(PDO::FETCH_OBJ); 62 | $db = null; 63 | echo json_encode($products); 64 | } catch(PDOException $e) { 65 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 66 | } 67 | } 68 | function getProduct( $id ) { 69 | $sql = "select * FROM products WHERE product_id=".$id." ORDER BY product_id"; 70 | try { 71 | $db = getConnection(); 72 | $stmt = $db->query($sql); 73 | $product = $stmt->fetchAll(PDO::FETCH_OBJ); 74 | $db = null; 75 | echo json_encode($product); 76 | } catch(PDOException $e) { 77 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 78 | } 79 | } 80 | 81 | function addProduct() { 82 | $request = \Slim\Slim::getInstance()->request(); 83 | $product = json_decode($request->getBody()); 84 | $sql = "INSERT INTO products (product_name, product_description, product_price, product_stock) VALUES (:product_name, :product_description, :product_price, :product_stock)"; 85 | try { 86 | $db = getConnection(); 87 | $stmt = $db->prepare($sql); 88 | $stmt->bindParam("product_name", $product->name); 89 | $stmt->bindParam("product_description", $product->description); 90 | $stmt->bindParam("product_price", $product->price); 91 | $stmt->bindParam("product_stock", $product->stock); 92 | $status = $stmt->execute(); 93 | $db = null; 94 | echo '{"status":'.$status.'}'; 95 | } catch(PDOException $e) { 96 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 97 | } 98 | } 99 | 100 | function deleteProduct($id) { 101 | $sql = "UPDATE products SET deleted=1 WHERE product_id=".$id; 102 | try { 103 | $db = getConnection(); 104 | $stmt = $db->query($sql); 105 | $db = null; 106 | getProducts(); 107 | } catch(PDOException $e) { 108 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 109 | } 110 | } 111 | 112 | function updateProduct($id) { 113 | $request = \Slim\Slim::getInstance()->request(); 114 | $product = json_decode($request->getBody()); 115 | $sql = "UPDATE products SET product_name=:name, product_description=:description, product_price=:price, product_stock=:stock WHERE product_id=:id"; 116 | try { 117 | $db = getConnection(); 118 | $stmt = $db->prepare($sql); 119 | $stmt->bindParam("name", $product->product_name); 120 | $stmt->bindParam("description", $product->product_description); 121 | $stmt->bindParam("price", $product->product_price); 122 | $stmt->bindParam("stock", $product->product_stock); 123 | $stmt->bindParam("id", $id); 124 | $stmt->execute(); 125 | $db = null; 126 | echo json_encode($product); 127 | } catch(PDOException $e) { 128 | echo '{"error":{"text":'. $e->getMessage() .'}}'; 129 | } 130 | } 131 | 132 | function getConnection() { 133 | $dbhost="localhost"; 134 | $dbuser="angular"; 135 | $dbpass="angular"; 136 | $dbname="angular-crud"; 137 | $dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass); 138 | $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 139 | return $dbh; 140 | } 141 | 142 | ?> -------------------------------------------------------------------------------- /assets/js/add/add.controller.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 'use strict'; 3 | 4 | function AddCtrl( $http, $state , BASE_URL) { 5 | var vm = this; 6 | vm.addNew = addNew; 7 | 8 | function addNew( product ) { 9 | $http.post( BASE_URL + 'api/add_product', product ) 10 | .success( function( data) { 11 | $state.go( 'home' ); 12 | }); 13 | } 14 | } 15 | 16 | AddCtrl.$inject = [ '$http', '$state', 'BASE_URL' ]; 17 | 18 | angular.module( 'app.add' ) 19 | .controller( 'AddCtrl', AddCtrl ); 20 | })(); -------------------------------------------------------------------------------- /assets/js/add/add.html: -------------------------------------------------------------------------------- 1 |

Add new Product

2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 | 22 | Cancel 23 |
24 |
25 |
-------------------------------------------------------------------------------- /assets/js/add/add.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module( 'app.add', [] ); 5 | })(); -------------------------------------------------------------------------------- /assets/js/app.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module( 'app', [ 'app.config', 'app.home', 'app.add', 'app.edit' ] ); 6 | })(); -------------------------------------------------------------------------------- /assets/js/config/config.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module( 'app.config', [ 'ui.router', 'angular-loading-bar', 'ui.bootstrap' ] ) 5 | .constant('BASE_URL', 'http://localhost/php-crud/'); 6 | })(); -------------------------------------------------------------------------------- /assets/js/config/config.routes.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 'use strict'; 3 | function configRoutes( $stateProvider, $urlRouterProvider ) { 4 | $stateProvider 5 | .state( 'home', { 6 | url: '/home', 7 | templateUrl: 'assets/js/home/home.html', 8 | controller: 'HomeCtrl', 9 | controllerAs: 'vm' 10 | }) 11 | 12 | .state('add', { 13 | url: '/add', 14 | templateUrl: 'assets/js/add/add.html', 15 | controller: 'AddCtrl', 16 | controllerAs: 'vm' 17 | }) 18 | 19 | .state('edit', { 20 | url: '/edit/:id', 21 | templateUrl: 'assets/js/edit/edit.html', 22 | controller: 'EditCtrl', 23 | controllerAs: 'vm' 24 | }) 25 | 26 | $urlRouterProvider.otherwise('home'); 27 | } 28 | 29 | angular.module( 'app.config' ) 30 | .config( configRoutes ) 31 | })(); -------------------------------------------------------------------------------- /assets/js/edit/edit.controller.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 'use strict'; 3 | 4 | function EditCtrl( $http, $stateParams, $state, BASE_URL ) { 5 | var vm = this; 6 | var id = $stateParams.id; 7 | vm.update = update; 8 | $http.get( BASE_URL + 'api/get_product/'+ id ) 9 | .success( function(data) { 10 | vm.product = data[0]; 11 | }); 12 | 13 | function update( product ) { 14 | $http.put( BASE_URL + 'api/edit_product/' + id, product ) 15 | .success( function ( data ) { 16 | console.log( data ); 17 | $state.go( 'home' ); 18 | } ); 19 | } 20 | } 21 | 22 | EditCtrl.$inject = [ '$http', '$stateParams', '$state', 'BASE_URL' ]; 23 | angular.module( 'app.edit' ) 24 | .controller( 'EditCtrl', EditCtrl ); 25 | })(); -------------------------------------------------------------------------------- /assets/js/edit/edit.html: -------------------------------------------------------------------------------- 1 |

Edit Product

2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 | 22 | Cancel 23 |
24 |
25 |
-------------------------------------------------------------------------------- /assets/js/edit/edit.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module( 'app.edit', [] ); 5 | })(); -------------------------------------------------------------------------------- /assets/js/home/home.controller.js: -------------------------------------------------------------------------------- 1 | ( function () { 2 | 'use strict'; 3 | 4 | function HomeCtrl( $http, BASE_URL ) { 5 | var vm = this; 6 | vm.deleteProduct= deleteProduct; 7 | vm.isAuthenticated = false; 8 | vm.login = login; 9 | vm.logout = logout; 10 | vm.user; 11 | 12 | 13 | $http.get( BASE_URL + 'api/is_login' ) 14 | .success( function ( data ) { 15 | if( data.isLogin === true ) { 16 | vm.isAuthenticated = true; 17 | loadData(); 18 | } 19 | } ) 20 | 21 | function login() { 22 | $http.post( BASE_URL + 'api/do_login', vm.user ) 23 | .then( function ( response ) { 24 | if( response.data.status === 'success' ) { 25 | vm.isAuthenticated = true; 26 | loadData(); 27 | } 28 | } ) 29 | } 30 | 31 | function loadData() { 32 | $http.get( BASE_URL +'api/products' ) 33 | .success( function(data) { 34 | vm.products = data; 35 | }); 36 | } 37 | 38 | function deleteProduct( id ) { 39 | var deleteIt = confirm('Are you absolutely sure you want to delete?'); 40 | if ( deleteIt) { 41 | $http.put( BASE_URL +'api/delete_product/'+ id ) 42 | .success( function ( data ) { 43 | vm.products= data; 44 | }); 45 | } 46 | } 47 | 48 | function logout() { 49 | if(confirm('Are you sure want to logout?')) { 50 | $http.get( BASE_URL + 'api/logout' ) 51 | .success( function ( ) { 52 | vm.isAuthenticated = false; 53 | } ) 54 | } 55 | } 56 | } 57 | 58 | HomeCtrl.$inject = [ '$http', 'BASE_URL' ]; 59 | angular.module( 'app.home' ) 60 | .controller( 'HomeCtrl', HomeCtrl ); 61 | })(); -------------------------------------------------------------------------------- /assets/js/home/home.html: -------------------------------------------------------------------------------- 1 | 30 | 31 |
32 |

Products

33 | Add New Product 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 |
NameDescriptionPriceAvaible StocksActions
{{product.product_name}}{{product.product_description}}{{product.product_price}}{{product.product_stock}} 52 |
56 |
57 |
58 |
59 |
60 |
61 |

Login 62 |
63 |

64 |
65 | 66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 |
{{login.errorMessage.username}}
74 |
75 |
76 | 77 |
78 | 79 | 80 |
81 |
Please enter your password
82 |
{{login.errorMessage.password}}
83 |
84 |
85 | 86 | 87 |
88 |
89 |
90 |
-------------------------------------------------------------------------------- /assets/js/home/home.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module( 'app.home', [] ); 5 | })(); -------------------------------------------------------------------------------- /assets/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 2000px; 3 | padding-top: 70px; 4 | } 5 | footer { 6 | bottom: 0; 7 | height: 78px; 8 | position: absolute; 9 | width: 100%; 10 | background-color: #ebf1f7; 11 | border-top: 1px solid #e2e6ed; 12 | color: #96a1a4; 13 | font-size: 14px; 14 | min-height: 78px; 15 | padding-top: 20px; 16 | text-align: center; 17 | } -------------------------------------------------------------------------------- /assets/vendor/angular-loading/loading-bar.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * angular-loading-bar v0.7.1 3 | * https://chieffancypants.github.io/angular-loading-bar 4 | * Copyright (c) 2015 Wes Cruver 5 | * License: MIT 6 | */ 7 | 8 | #loading-bar,#loading-bar-spinner{pointer-events:none;-webkit-pointer-events:none;-webkit-transition:350ms linear all;-moz-transition:350ms linear all;-o-transition:350ms linear all;transition:350ms linear all}#loading-bar.ng-enter,#loading-bar.ng-leave.ng-leave-active,#loading-bar-spinner.ng-enter,#loading-bar-spinner.ng-leave.ng-leave-active{opacity:0}#loading-bar.ng-enter.ng-enter-active,#loading-bar.ng-leave,#loading-bar-spinner.ng-enter.ng-enter-active,#loading-bar-spinner.ng-leave{opacity:1}#loading-bar .bar{-webkit-transition:width 350ms;-moz-transition:width 350ms;-o-transition:width 350ms;transition:width 350ms;background:#29d;position:fixed;z-index:10002;top:0;left:0;width:100%;height:2px;border-bottom-right-radius:1px;border-top-right-radius:1px}#loading-bar .peg{position:absolute;width:70px;right:0;top:0;height:2px;opacity:.45;-moz-box-shadow:#29d 1px 0 6px 1px;-ms-box-shadow:#29d 1px 0 6px 1px;-webkit-box-shadow:#29d 1px 0 6px 1px;box-shadow:#29d 1px 0 6px 1px;-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}#loading-bar-spinner{display:block;position:fixed;z-index:10002;top:10px;left:10px}#loading-bar-spinner .spinner-icon{width:14px;height:14px;border:solid 2px transparent;border-top-color:#29d;border-left-color:#29d;border-radius:10px;-webkit-animation:loading-bar-spinner 400ms linear infinite;-moz-animation:loading-bar-spinner 400ms linear infinite;-ms-animation:loading-bar-spinner 400ms linear infinite;-o-animation:loading-bar-spinner 400ms linear infinite;animation:loading-bar-spinner 400ms linear infinite}@-webkit-keyframes loading-bar-spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes loading-bar-spinner{0%{-moz-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes loading-bar-spinner{0%{-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes loading-bar-spinner{0%{-ms-transform:rotate(0deg);transform:rotate(0deg)}100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-bar-spinner{0%{transform:rotate(0deg);transform:rotate(0deg)}100%{transform:rotate(360deg);transform:rotate(360deg)}} -------------------------------------------------------------------------------- /assets/vendor/angular-loading/loading-bar.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * angular-loading-bar v0.7.1 3 | * https://chieffancypants.github.io/angular-loading-bar 4 | * Copyright (c) 2015 Wes Cruver 5 | * License: MIT 6 | */ 7 | !function(){"use strict";angular.module("angular-loading-bar",["cfp.loadingBarInterceptor"]),angular.module("chieffancypants.loadingBar",["cfp.loadingBarInterceptor"]),angular.module("cfp.loadingBarInterceptor",["cfp.loadingBar"]).config(["$httpProvider",function(a){var b=["$q","$cacheFactory","$timeout","$rootScope","$log","cfpLoadingBar",function(b,c,d,e,f,g){function h(){d.cancel(j),g.complete(),l=0,k=0}function i(b){var d,e=c.get("$http"),f=a.defaults;!b.cache&&!f.cache||b.cache===!1||"GET"!==b.method&&"JSONP"!==b.method||(d=angular.isObject(b.cache)?b.cache:angular.isObject(f.cache)?f.cache:e);var g=void 0!==d?void 0!==d.get(b.url):!1;return void 0!==b.cached&&g!==b.cached?b.cached:(b.cached=g,g)}var j,k=0,l=0,m=g.latencyThreshold;return{request:function(a){return a.ignoreLoadingBar||i(a)||(e.$broadcast("cfpLoadingBar:loading",{url:a.url}),0===k&&(j=d(function(){g.start()},m)),k++,g.set(l/k)),a},response:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),l>=k?h():g.set(l/k)),a):(f.error("Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),a)},responseError:function(a){return a&&a.config?(a.config.ignoreLoadingBar||i(a.config)||(l++,e.$broadcast("cfpLoadingBar:loaded",{url:a.config.url,result:a}),l>=k?h():g.set(l/k)),b.reject(a)):(f.error("Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),b.reject(a))}}}];a.interceptors.push(b)}]),angular.module("cfp.loadingBar",[]).provider("cfpLoadingBar",function(){this.includeSpinner=!0,this.includeBar=!0,this.latencyThreshold=100,this.startSize=.02,this.parentSelector="body",this.spinnerTemplate='
',this.loadingBarTemplate='
',this.$get=["$injector","$document","$timeout","$rootScope",function(a,b,c,d){function e(){k||(k=a.get("$animate"));var e=b.find(n).eq(0);c.cancel(m),r||(d.$broadcast("cfpLoadingBar:started"),r=!0,u&&k.enter(o,e,angular.element(e[0].lastChild)),t&&k.enter(q,e,angular.element(e[0].lastChild)),f(v))}function f(a){if(r){var b=100*a+"%";p.css("width",b),s=a,c.cancel(l),l=c(function(){g()},250)}}function g(){if(!(h()>=1)){var a=0,b=h();a=b>=0&&.25>b?(3*Math.random()+3)/100:b>=.25&&.65>b?3*Math.random()/100:b>=.65&&.9>b?2*Math.random()/100:b>=.9&&.99>b?.005:0;var c=h()+a;f(c)}}function h(){return s}function i(){s=0,r=!1}function j(){k||(k=a.get("$animate")),d.$broadcast("cfpLoadingBar:completed"),f(1),c.cancel(m),m=c(function(){var a=k.leave(o,i);a&&a.then&&a.then(i),k.leave(q)},500)}var k,l,m,n=this.parentSelector,o=angular.element(this.loadingBarTemplate),p=o.find("div").eq(0),q=angular.element(this.spinnerTemplate),r=!1,s=0,t=this.includeSpinner,u=this.includeBar,v=this.startSize;return{start:e,set:f,status:h,inc:g,complete:j,includeSpinner:this.includeSpinner,latencyThreshold:this.latencyThreshold,parentSelector:this.parentSelector,startSize:this.startSize}}]})}(); -------------------------------------------------------------------------------- /assets/vendor/boostrap/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.4 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn-default .badge, 33 | .btn-primary .badge, 34 | .btn-success .badge, 35 | .btn-info .badge, 36 | .btn-warning .badge, 37 | .btn-danger .badge { 38 | text-shadow: none; 39 | } 40 | .btn:active, 41 | .btn.active { 42 | background-image: none; 43 | } 44 | .btn-default { 45 | text-shadow: 0 1px 0 #fff; 46 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 47 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 48 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 49 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 50 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 51 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 52 | background-repeat: repeat-x; 53 | border-color: #dbdbdb; 54 | border-color: #ccc; 55 | } 56 | .btn-default:hover, 57 | .btn-default:focus { 58 | background-color: #e0e0e0; 59 | background-position: 0 -15px; 60 | } 61 | .btn-default:active, 62 | .btn-default.active { 63 | background-color: #e0e0e0; 64 | border-color: #dbdbdb; 65 | } 66 | .btn-default.disabled, 67 | .btn-default:disabled, 68 | .btn-default[disabled] { 69 | background-color: #e0e0e0; 70 | background-image: none; 71 | } 72 | .btn-primary { 73 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 74 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 75 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 76 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 77 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 78 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 79 | background-repeat: repeat-x; 80 | border-color: #245580; 81 | } 82 | .btn-primary:hover, 83 | .btn-primary:focus { 84 | background-color: #265a88; 85 | background-position: 0 -15px; 86 | } 87 | .btn-primary:active, 88 | .btn-primary.active { 89 | background-color: #265a88; 90 | border-color: #245580; 91 | } 92 | .btn-primary.disabled, 93 | .btn-primary:disabled, 94 | .btn-primary[disabled] { 95 | background-color: #265a88; 96 | background-image: none; 97 | } 98 | .btn-success { 99 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 100 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 101 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 102 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 103 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 104 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 105 | background-repeat: repeat-x; 106 | border-color: #3e8f3e; 107 | } 108 | .btn-success:hover, 109 | .btn-success:focus { 110 | background-color: #419641; 111 | background-position: 0 -15px; 112 | } 113 | .btn-success:active, 114 | .btn-success.active { 115 | background-color: #419641; 116 | border-color: #3e8f3e; 117 | } 118 | .btn-success.disabled, 119 | .btn-success:disabled, 120 | .btn-success[disabled] { 121 | background-color: #419641; 122 | background-image: none; 123 | } 124 | .btn-info { 125 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 126 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 127 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 128 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 129 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 130 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 131 | background-repeat: repeat-x; 132 | border-color: #28a4c9; 133 | } 134 | .btn-info:hover, 135 | .btn-info:focus { 136 | background-color: #2aabd2; 137 | background-position: 0 -15px; 138 | } 139 | .btn-info:active, 140 | .btn-info.active { 141 | background-color: #2aabd2; 142 | border-color: #28a4c9; 143 | } 144 | .btn-info.disabled, 145 | .btn-info:disabled, 146 | .btn-info[disabled] { 147 | background-color: #2aabd2; 148 | background-image: none; 149 | } 150 | .btn-warning { 151 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 152 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 153 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 154 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 155 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 156 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 157 | background-repeat: repeat-x; 158 | border-color: #e38d13; 159 | } 160 | .btn-warning:hover, 161 | .btn-warning:focus { 162 | background-color: #eb9316; 163 | background-position: 0 -15px; 164 | } 165 | .btn-warning:active, 166 | .btn-warning.active { 167 | background-color: #eb9316; 168 | border-color: #e38d13; 169 | } 170 | .btn-warning.disabled, 171 | .btn-warning:disabled, 172 | .btn-warning[disabled] { 173 | background-color: #eb9316; 174 | background-image: none; 175 | } 176 | .btn-danger { 177 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 178 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 179 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 180 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 181 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 182 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 183 | background-repeat: repeat-x; 184 | border-color: #b92c28; 185 | } 186 | .btn-danger:hover, 187 | .btn-danger:focus { 188 | background-color: #c12e2a; 189 | background-position: 0 -15px; 190 | } 191 | .btn-danger:active, 192 | .btn-danger.active { 193 | background-color: #c12e2a; 194 | border-color: #b92c28; 195 | } 196 | .btn-danger.disabled, 197 | .btn-danger:disabled, 198 | .btn-danger[disabled] { 199 | background-color: #c12e2a; 200 | background-image: none; 201 | } 202 | .thumbnail, 203 | .img-thumbnail { 204 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 205 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 206 | } 207 | .dropdown-menu > li > a:hover, 208 | .dropdown-menu > li > a:focus { 209 | background-color: #e8e8e8; 210 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 211 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 212 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 213 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 214 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 215 | background-repeat: repeat-x; 216 | } 217 | .dropdown-menu > .active > a, 218 | .dropdown-menu > .active > a:hover, 219 | .dropdown-menu > .active > a:focus { 220 | background-color: #2e6da4; 221 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 222 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 223 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 224 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 225 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 226 | background-repeat: repeat-x; 227 | } 228 | .navbar-default { 229 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 230 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 231 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 232 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 233 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 234 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 235 | background-repeat: repeat-x; 236 | border-radius: 4px; 237 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 238 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 239 | } 240 | .navbar-default .navbar-nav > .open > a, 241 | .navbar-default .navbar-nav > .active > a { 242 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 243 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 244 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 245 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 246 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 247 | background-repeat: repeat-x; 248 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 249 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 250 | } 251 | .navbar-brand, 252 | .navbar-nav > li > a { 253 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 254 | } 255 | .navbar-inverse { 256 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 257 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 258 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 259 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 260 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 261 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 262 | background-repeat: repeat-x; 263 | } 264 | .navbar-inverse .navbar-nav > .open > a, 265 | .navbar-inverse .navbar-nav > .active > a { 266 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 267 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 268 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 269 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 270 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 271 | background-repeat: repeat-x; 272 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 273 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 274 | } 275 | .navbar-inverse .navbar-brand, 276 | .navbar-inverse .navbar-nav > li > a { 277 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 278 | } 279 | .navbar-static-top, 280 | .navbar-fixed-top, 281 | .navbar-fixed-bottom { 282 | border-radius: 0; 283 | } 284 | @media (max-width: 767px) { 285 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 286 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 287 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 288 | color: #fff; 289 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 290 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 291 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 292 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 293 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 294 | background-repeat: repeat-x; 295 | } 296 | } 297 | .alert { 298 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 299 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 300 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 301 | } 302 | .alert-success { 303 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 304 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 305 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 306 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 307 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 308 | background-repeat: repeat-x; 309 | border-color: #b2dba1; 310 | } 311 | .alert-info { 312 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 313 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 314 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 315 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 316 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 317 | background-repeat: repeat-x; 318 | border-color: #9acfea; 319 | } 320 | .alert-warning { 321 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 322 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 323 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 324 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 325 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 326 | background-repeat: repeat-x; 327 | border-color: #f5e79e; 328 | } 329 | .alert-danger { 330 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 331 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 332 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 333 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 334 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 335 | background-repeat: repeat-x; 336 | border-color: #dca7a7; 337 | } 338 | .progress { 339 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 340 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 342 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 344 | background-repeat: repeat-x; 345 | } 346 | .progress-bar { 347 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 348 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 349 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 350 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 351 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 352 | background-repeat: repeat-x; 353 | } 354 | .progress-bar-success { 355 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 356 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 357 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 358 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 359 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 360 | background-repeat: repeat-x; 361 | } 362 | .progress-bar-info { 363 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 364 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 365 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 366 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 367 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 368 | background-repeat: repeat-x; 369 | } 370 | .progress-bar-warning { 371 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 372 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 374 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 376 | background-repeat: repeat-x; 377 | } 378 | .progress-bar-danger { 379 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 380 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 381 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 382 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 383 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 384 | background-repeat: repeat-x; 385 | } 386 | .progress-bar-striped { 387 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 388 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 389 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 390 | } 391 | .list-group { 392 | border-radius: 4px; 393 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 394 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 395 | } 396 | .list-group-item.active, 397 | .list-group-item.active:hover, 398 | .list-group-item.active:focus { 399 | text-shadow: 0 -1px 0 #286090; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 405 | background-repeat: repeat-x; 406 | border-color: #2b669a; 407 | } 408 | .list-group-item.active .badge, 409 | .list-group-item.active:hover .badge, 410 | .list-group-item.active:focus .badge { 411 | text-shadow: none; 412 | } 413 | .panel { 414 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 415 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 416 | } 417 | .panel-default > .panel-heading { 418 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 419 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 420 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 421 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 422 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 423 | background-repeat: repeat-x; 424 | } 425 | .panel-primary > .panel-heading { 426 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 427 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 428 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 429 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 430 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 431 | background-repeat: repeat-x; 432 | } 433 | .panel-success > .panel-heading { 434 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 435 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 436 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 437 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 438 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 439 | background-repeat: repeat-x; 440 | } 441 | .panel-info > .panel-heading { 442 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 443 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 444 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 445 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 446 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 447 | background-repeat: repeat-x; 448 | } 449 | .panel-warning > .panel-heading { 450 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 451 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 453 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .panel-danger > .panel-heading { 458 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 459 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 461 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .well { 466 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 467 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 469 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 471 | background-repeat: repeat-x; 472 | border-color: #dcdcdc; 473 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 474 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 475 | } 476 | /*# sourceMappingURL=bootstrap-theme.css.map */ 477 | -------------------------------------------------------------------------------- /assets/vendor/boostrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mouthzipper/php-angular-mysql-CRUD/f97adfc3ce1353a5ce8f2ee3343fa026a3f592d5/assets/vendor/boostrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /assets/vendor/boostrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mouthzipper/php-angular-mysql-CRUD/f97adfc3ce1353a5ce8f2ee3343fa026a3f592d5/assets/vendor/boostrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /assets/vendor/boostrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mouthzipper/php-angular-mysql-CRUD/f97adfc3ce1353a5ce8f2ee3343fa026a3f592d5/assets/vendor/boostrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /assets/vendor/boostrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mouthzipper/php-angular-mysql-CRUD/f97adfc3ce1353a5ce8f2ee3343fa026a3f592d5/assets/vendor/boostrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PHPCRUD 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 | 17 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | --------------------------------------------------------------------------------