├── README.md
├── aprs_func.php
├── index.php
├── templates
├── passcode.php
└── main.php
└── Slim
├── Exception
├── Stop.php
├── Pass.php
└── RequestSlash.php
├── Session
├── Handler
│ └── Cookies.php
├── Handler.php
└── Flash.php
├── Http
├── Uri.php
├── Cookie.php
├── Response.php
├── Request.php
└── CookieJar.php
├── Log.php
├── View.php
├── Logger.php
├── Router.php
├── Route.php
└── Slim.php
/README.md:
--------------------------------------------------------------------------------
1 | PHP-APRS-Passcode
2 | =================
3 |
4 | Technical example on how to generate APRS network passcodes required for mobile applications using PHP an [Example](http://apps.magicbug.co.uk/passcode/) is available to try it out.
--------------------------------------------------------------------------------
/aprs_func.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | get('/', function () {
12 |
13 | // Require HTML Template
14 | require('templates/main.php');
15 | });
16 |
17 | // Generate Passcode
18 | $app->post('/passcode', function () {
19 | // Include function to generate APRS Code
20 | require('aprs_func.php');
21 |
22 | // Store Passcode
23 | $passcode = aprspass($_POST['callsign']);
24 |
25 | // Load Page
26 | require('templates/passcode.php');
27 | });
28 |
29 |
30 | // Run slim
31 | $app->run();
32 |
33 | ?>
--------------------------------------------------------------------------------
/templates/passcode.php:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | APRS Passcode Generator - Passcode
7 |
29 |
30 |
31 |
32 |
33 |
34 |
APRS Passcode Generator
35 |
36 |
Your Passcode:
37 |
38 |
Generate a new Passcode
39 |
40 |
Techical Example of Passcode Generation using PHP
41 |
Source code available on Github
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/templates/main.php:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | APRS Passcode Generator
6 |
25 |
26 |
27 |
28 |
29 |
30 |
APRS Passcode Generator
31 |
32 |
33 |
38 |
39 |
40 |
Technical Example of Passcode Generation using PHP
41 |
Source code available on Github
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/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 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Stop Exception
35 | *
36 | * This Exception is thrown when the Slim application needs to abort
37 | * processing and return control flow to the outer PHP script.
38 | *
39 | * @package Slim
40 | * @author Josh Lockhart
41 | * @since Version 1.0
42 | */
43 | class Slim_Exception_Stop extends Exception {}
--------------------------------------------------------------------------------
/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 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Pass Exception
35 | *
36 | * This Exception will cause the Router::dispatch method
37 | * to skip the current matching route and continue to the next
38 | * matching route. If no subsequent routes are found, a
39 | * HTTP 404 Not Found response will be sent to the client.
40 | *
41 | * @package Slim
42 | * @author Josh Lockhart
43 | * @since Version 1.0
44 | */
45 | class Slim_Exception_Pass extends Exception {}
--------------------------------------------------------------------------------
/Slim/Exception/RequestSlash.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Request Slash Exception
35 | *
36 | * This Exception is thrown when Slim detects a matching route
37 | * (defined with a trailing slash) and the HTTP request
38 | * matches the route but does not have a trailing slash. This
39 | * exception will be caught in `Slim::run` and trigger a 301 redirect
40 | * to the same resource URI with a trailing slash.
41 | *
42 | * @package Slim
43 | * @author Josh Lockhart
44 | * @since Version 1.0
45 | */
46 | class Slim_Exception_RequestSlash extends Exception {}
--------------------------------------------------------------------------------
/Slim/Session/Handler/Cookies.php:
--------------------------------------------------------------------------------
1 | app->getEncryptedCookie($id);
57 | }
58 |
59 | public function write( $id, $sessionData ) {
60 | $this->app->setEncryptedCookie($id, $sessionData, 0);
61 | }
62 |
63 | public function destroy( $id ) {
64 | $this->app->deleteCookie($id);
65 | }
66 |
67 | public function gc( $maxLifetime ) {
68 | return true; //Not used
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/Slim/Session/Handler.php:
--------------------------------------------------------------------------------
1 | app = $app;
58 | return session_set_save_handler(
59 | array($this, 'open'),
60 | array($this, 'close'),
61 | array($this, 'read'),
62 | array($this, 'write'),
63 | array($this, 'destroy'),
64 | array($this, 'gc')
65 | );
66 | }
67 |
68 | /**
69 | * Open session
70 | *
71 | * @param string $savePath
72 | * @param string $sessionName
73 | * @return mixed
74 | */
75 | abstract public function open( $savePath, $sessionName );
76 |
77 | /**
78 | * Close session
79 | *
80 | * @return mixed
81 | */
82 | abstract public function close();
83 |
84 | /**
85 | * Read session data with ID
86 | *
87 | * @param string $id The session identifier
88 | * @return string
89 | */
90 | abstract public function read( $id );
91 |
92 | /**
93 | * Write session data with ID
94 | *
95 | * The "write" handler is not executed until after the output stream is
96 | * closed. Thus, output from debugging statements in the "write" handler
97 | * will never be seen in the browser. If debugging output is necessary, it
98 | * is suggested that the debug output be written to a file instead.
99 | *
100 | * @param string $id The session identifier
101 | * @param mixed $sessionData The session data
102 | * @return mixed
103 | */
104 | abstract public function write( $id, $sessionData );
105 |
106 | /**
107 | * Destroy session with ID
108 | *
109 | * @param string $id The session identifier
110 | * @return mixed
111 | */
112 | abstract public function destroy( $id );
113 |
114 | /**
115 | * Session garbage collection
116 | *
117 | * Executed when the PHP session garbage collector is invoked; should
118 | * remove all session data older than the `$maxLifetime`.
119 | *
120 | * @param int $maxLifetime
121 | * @return mixed
122 | */
123 | abstract public function gc( $maxLifetime );
124 |
125 | }
--------------------------------------------------------------------------------
/Slim/Http/Uri.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Uri
35 | *
36 | * Parses base uri and application uri from Request.
37 | *
38 | * @package Slim
39 | * @author Josh Lockhart
40 | * @since Version 1.0
41 | */
42 | class Slim_Http_Uri {
43 |
44 | /**
45 | * @var string "https" or "http"
46 | */
47 | protected static $scheme;
48 |
49 | /**
50 | * @var string
51 | */
52 | protected static $baseUri;
53 |
54 | /**
55 | * @var string
56 | */
57 | protected static $uri;
58 |
59 | /**
60 | * @var string The URI query string, excluding leading "?"
61 | */
62 | protected static $queryString;
63 |
64 | /**
65 | * Get Base URI without trailing slash
66 | * @param bool $reload Force reparse the base URI?
67 | * @return string
68 | */
69 | public static function getBaseUri( $reload = false ) {
70 | if ( $reload || is_null(self::$baseUri) ) {
71 | $requestUri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF']; //Full Request URI
72 | $scriptName = $_SERVER['SCRIPT_NAME']; //Script path from docroot
73 | $baseUri = strpos($requestUri, $scriptName) === 0 ? $scriptName : str_replace('\\', '/', dirname($scriptName));
74 | self::$baseUri = rtrim($baseUri, '/');
75 | }
76 | return self::$baseUri;
77 | }
78 |
79 | /**
80 | * Get URI with leading slash
81 | * @param bool $reload Force reparse the URI?
82 | * @return string
83 | * @throws RuntimeException If unable if unable to determine URI
84 | */
85 | public static function getUri( $reload = false ) {
86 | if ( $reload || is_null(self::$uri) ) {
87 | $uri = '';
88 | if ( !empty($_SERVER['PATH_INFO']) ) {
89 | $uri = $_SERVER['PATH_INFO'];
90 | } else {
91 | if ( isset($_SERVER['REQUEST_URI']) ) {
92 | $uri = parse_url(self::getScheme() . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
93 | } else if ( isset($_SERVER['PHP_SELF']) ) {
94 | $uri = $_SERVER['PHP_SELF'];
95 | } else {
96 | throw new RuntimeException('Unable to detect request URI');
97 | }
98 | }
99 | if ( self::getBaseUri() !== '' && strpos($uri, self::getBaseUri()) === 0 ) {
100 | $uri = substr($uri, strlen(self::getBaseUri()));
101 | }
102 | self::$uri = '/' . ltrim($uri, '/');
103 | }
104 | return self::$uri;
105 | }
106 |
107 | /**
108 | * Get URI Scheme
109 | * @param bool $reload For reparse the URL scheme?
110 | * @return string "https" or "http"
111 | */
112 | public static function getScheme( $reload = false ) {
113 | if ( $reload || is_null(self::$scheme) ) {
114 | self::$scheme = ( empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ) ? 'http' : 'https';
115 | }
116 | return self::$scheme;
117 | }
118 |
119 | /**
120 | * Get URI Query String
121 | * @param bool $reload For reparse the URL query string?
122 | * @return string
123 | */
124 | public static function getQueryString( $reload = false ) {
125 | if ( $reload || is_null(self::$queryString) ) {
126 | self::$queryString = $_SERVER['QUERY_STRING'];
127 | }
128 | return self::$queryString;
129 | }
130 |
131 | }
--------------------------------------------------------------------------------
/Slim/Log.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Log Adapter
35 | *
36 | * This is an adapter for your own custom Logger. This adapter assumes
37 | * your custom Logger provides the following public instance methods:
38 | *
39 | * debug( mixed $object )
40 | * info( mixed $object )
41 | * warn( mixed $object )
42 | * error( mixed $object )
43 | * fatal( mixed $object )
44 | *
45 | * This class assumes nothing else about your custom Logger, so you are free
46 | * to use Apache's Log4PHP logger or any other log class that, at the
47 | * very least, implements the five public instance methods shown above.
48 | *
49 | * @package Slim
50 | * @author Josh Lockhart
51 | * @since Version 1.0
52 | */
53 | class Slim_Log {
54 |
55 | /**
56 | * @var mixed An object that implements expected Logger interface
57 | */
58 | protected $logger;
59 |
60 | /**
61 | * @var bool Enable logging?
62 | */
63 | protected $enabled;
64 |
65 | /**
66 | * Constructor
67 | */
68 | public function __construct() {
69 | $this->enabled = true;
70 | }
71 |
72 | /**
73 | * Enable or disable logging
74 | * @param bool $enabled
75 | * @return void
76 | */
77 | public function setEnabled( $enabled ) {
78 | if ( $enabled ) {
79 | $this->enabled = true;
80 | } else {
81 | $this->enabled = false;
82 | }
83 | }
84 |
85 | /**
86 | * Is logging enabled?
87 | * @return bool
88 | */
89 | public function isEnabled() {
90 | return $this->enabled;
91 | }
92 |
93 | /**
94 | * Log debug message
95 | * @param mixed $object
96 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
97 | */
98 | public function debug( $object ) {
99 | return isset($this->logger) && $this->isEnabled() ? $this->logger->debug($object) : false;
100 | }
101 |
102 | /**
103 | * Log info message
104 | * @param mixed $object
105 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
106 | */
107 | public function info( $object ) {
108 | return isset($this->logger) && $this->isEnabled() ? $this->logger->info($object) : false;
109 | }
110 |
111 | /**
112 | * Log warn message
113 | * @param mixed $object
114 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
115 | */
116 | public function warn( $object ) {
117 | return isset($this->logger) && $this->isEnabled() ? $this->logger->warn($object) : false;
118 | }
119 |
120 | /**
121 | * Log error message
122 | * @param mixed $object
123 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
124 | */
125 | public function error( $object ) {
126 | return isset($this->logger) && $this->isEnabled() ? $this->logger->error($object) : false;
127 | }
128 |
129 | /**
130 | * Log fatal message
131 | * @param mixed $object
132 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
133 | */
134 | public function fatal( $object ) {
135 | return isset($this->logger) && $this->isEnabled() ? $this->logger->fatal($object) : false;
136 | }
137 |
138 | /**
139 | * Set Logger
140 | * @param mixed $logger
141 | * @return void
142 | */
143 | public function setLogger( $logger ) {
144 | $this->logger = $logger;
145 | }
146 |
147 | /**
148 | * Get Logger
149 | * @return mixed
150 | */
151 | public function getLogger() {
152 | return $this->logger;
153 | }
154 |
155 | }
--------------------------------------------------------------------------------
/Slim/View.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Slim View
35 | *
36 | * The View is responsible for rendering and/or displaying a template.
37 | * It is recommended that you subclass View and re-implement the
38 | * `View::render` method to use a custom templating engine such as
39 | * Smarty, Twig, Mustache, etc. It is important that `View::render`
40 | * `return` the final template output. Do not `echo` the output.
41 | *
42 | * @package Slim
43 | * @author Josh Lockhart
44 | * @since Version 1.0
45 | */
46 | class Slim_View {
47 |
48 | /**
49 | * @var array Key-value array of data available to the template
50 | */
51 | protected $data = array();
52 |
53 | /**
54 | * @var string Absolute or relative path to the templates directory
55 | */
56 | protected $templatesDirectory;
57 |
58 | /**
59 | * Constructor
60 | *
61 | * This is empty but may be overridden in a subclass
62 | */
63 | public function __construct() {}
64 |
65 | /**
66 | * Get data
67 | * @param string $key
68 | * @return array|mixed|null All View data if no $key, value of datum
69 | * if $key, or NULL if $key but datum
70 | * does not exist.
71 | */
72 | public function getData( $key = null ) {
73 | if ( !is_null($key) ) {
74 | return isset($this->data[$key]) ? $this->data[$key] : null;
75 | } else {
76 | return $this->data;
77 | }
78 | }
79 |
80 | /**
81 | * Set data
82 | *
83 | * This method is overloaded to accept two different method signatures.
84 | * You may use this to set a specific key with a specfic value,
85 | * or you may use this to set all data to a specific array.
86 | *
87 | * USAGE:
88 | *
89 | * View::setData('color', 'red');
90 | * View::setData(array('color' => 'red', 'number' => 1));
91 | *
92 | * @param string|array
93 | * @param mixed Optional. Only use if first argument is a string.
94 | * @return void
95 | * @throws InvalidArgumentException If incorrect method signature
96 | */
97 | public function setData() {
98 | $args = func_get_args();
99 | if ( count($args) === 1 && is_array($args[0]) ) {
100 | $this->data = $args[0];
101 | } else if ( count($args) === 2 ) {
102 | $this->data[(string)$args[0]] = $args[1];
103 | } else {
104 | throw new InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`');
105 | }
106 | }
107 |
108 | /**
109 | * Append data to existing View data
110 | * @param array $data
111 | * @return void
112 | */
113 | public function appendData( array $data ) {
114 | $this->data = array_merge($this->data, $data);
115 | }
116 |
117 | /**
118 | * Get templates directory
119 | * @return string|null Path to templates directory without trailing slash
120 | */
121 | public function getTemplatesDirectory() {
122 | return $this->templatesDirectory;
123 | }
124 |
125 | /**
126 | * Set templates directory
127 | * @param string $dir
128 | * @return void
129 | * @throws RuntimeException If directory is not a directory or does not exist
130 | */
131 | public function setTemplatesDirectory( $dir ) {
132 | if ( !is_dir($dir) ) {
133 | throw new RuntimeException('Cannot set View templates directory to: ' . $dir . '. Directory does not exist.');
134 | }
135 | $this->templatesDirectory = rtrim($dir, '/');
136 | }
137 |
138 | /**
139 | * Display template
140 | *
141 | * This method echoes the rendered template to the current output buffer
142 | *
143 | * @param string $template Path to template file relative to templates directoy
144 | * @return void
145 | */
146 | public function display( $template ) {
147 | echo $this->render($template);
148 | }
149 |
150 | /**
151 | * Render template
152 | * @param string $template Path to template file relative to templates directory
153 | * @return string Rendered template
154 | * @throws RuntimeException If template does not exist
155 | */
156 | public function render( $template ) {
157 | extract($this->data);
158 | $templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
159 | if ( !file_exists($templatePath) ) {
160 | throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.');
161 | }
162 | ob_start();
163 | require $templatePath;
164 | return ob_get_clean();
165 | }
166 |
167 | }
--------------------------------------------------------------------------------
/Slim/Logger.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Logger
35 | *
36 | * A simple Logger that writes to a daily-unique log file in
37 | * a user-specified directory. By default, this class will write log
38 | * messages for all log levels; the log level may be changed to filter
39 | * unwanted log messages from the log file.
40 | *
41 | * @package Slim
42 | * @author Josh Lockhart
43 | * @since Version 1.0
44 | */
45 | class Slim_Logger {
46 |
47 | /**
48 | * @var array Log levels
49 | */
50 | protected $levels = array(
51 | 0 => 'FATAL',
52 | 1 => 'ERROR',
53 | 2 => 'WARN',
54 | 3 => 'INFO',
55 | 4 => 'DEBUG'
56 | );
57 |
58 | /**
59 | * @var string Absolute path to log directory with trailing slash
60 | */
61 | protected $directory;
62 |
63 | /**
64 | * Constructor
65 | * @param string $directory Absolute or relative path to log directory
66 | * @param int $level The maximum log level reported by this Logger
67 | */
68 | public function __construct( $directory, $level = 4 ) {
69 | $this->setDirectory($directory);
70 | $this->setLevel($level);
71 | }
72 |
73 | /**
74 | * Set log directory
75 | * @param string $directory Absolute or relative path to log directory
76 | * @return void
77 | */
78 | public function setDirectory( $directory ) {
79 | $realPath = realpath($directory);
80 | if ( $realPath ) {
81 | $this->directory = rtrim($realPath, '/') . '/';
82 | } else {
83 | $this->directory = false;
84 | }
85 | }
86 |
87 | /**
88 | * Get log directory
89 | * @return string|false Absolute path to log directory with trailing slash
90 | */
91 | public function getDirectory() {
92 | return $this->directory;
93 | }
94 |
95 | /**
96 | * Set log level
97 | * @param int The maximum log level reported by this Logger
98 | * @return void
99 | * @throws InvalidArgumentException If level specified is not 0, 1, 2, 3, 4
100 | */
101 | public function setLevel( $level ) {
102 | $theLevel = (int)$level;
103 | if ( $theLevel >= 0 && $theLevel <= 4 ) {
104 | $this->level = $theLevel;
105 | } else {
106 | throw new InvalidArgumentException('Invalid Log Level. Must be one of: 0, 1, 2, 3, 4.');
107 | }
108 | }
109 |
110 | /**
111 | * Get log level
112 | * @return int
113 | */
114 | public function getLevel() {
115 | return $this->level;
116 | }
117 |
118 | /**
119 | * Log debug data
120 | * @param mixed $data
121 | * @return void
122 | */
123 | public function debug( $data ) {
124 | $this->log($data, 4);
125 | }
126 |
127 | /**
128 | * Log info data
129 | * @param mixed $data
130 | * @return void
131 | */
132 | public function info( $data ) {
133 | $this->log($data, 3);
134 | }
135 |
136 | /**
137 | * Log warn data
138 | * @param mixed $data
139 | * @return void
140 | */
141 | public function warn( $data ) {
142 | $this->log($data, 2);
143 | }
144 |
145 | /**
146 | * Log error data
147 | * @param mixed $data
148 | * @return void
149 | */
150 | public function error( $data ) {
151 | $this->log($data, 1);
152 | }
153 |
154 | /**
155 | * Log fatal data
156 | * @param mixed $data
157 | * @return void
158 | */
159 | public function fatal( $data ) {
160 | $this->log($data, 0);
161 | }
162 |
163 | /**
164 | * Get absolute path to current daily log file
165 | * @return string
166 | */
167 | public function getFile() {
168 | return $this->getDirectory() . strftime('%Y-%m-%d') . '.log';
169 | }
170 |
171 | /**
172 | * Log data to file
173 | * @param mixed $data
174 | * @param int $level
175 | * @return void
176 | * @throws RuntimeException If log directory not found or not writable
177 | */
178 | protected function log( $data, $level ) {
179 | $dir = $this->getDirectory();
180 | if ( $dir == false || !is_dir($dir) ) {
181 | throw new RuntimeException("Log directory '$dir' invalid.");
182 | }
183 | if ( !is_writable($dir) ) {
184 | throw new RuntimeException("Log directory '$dir' not writable.");
185 | }
186 | if ( $level <= $this->getLevel() ) {
187 | $this->write(sprintf("[%s] %s - %s\r\n", $this->levels[$level], date('c'), (string)$data));
188 | }
189 | }
190 |
191 | /**
192 | * Persist data to log
193 | * @param string Log message
194 | * @return void
195 | */
196 | protected function write( $data ) {
197 | @file_put_contents($this->getFile(), $data, FILE_APPEND | LOCK_EX);
198 | }
199 |
200 | }
--------------------------------------------------------------------------------
/Slim/Session/Flash.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Flash Messaging
35 | *
36 | * This class enables Flash messaging. Messages are persisted in $_SESSION
37 | * with a user-defined key.
38 | *
39 | * USAGE:
40 | *
41 | * 1. Set Flash message to be shown on the next request
42 | *
43 | * Slim::flash('error', 'The object could not be saved');
44 | *
45 | * 2. Set Flash message to be shown on the current request
46 | *
47 | * Slim::flashNow('error', 'The object could not be saved');
48 | *
49 | * 3. Keep old Flash messages for the next request
50 | *
51 | * Slim::flashKeep();
52 | *
53 | * @package Slim
54 | * @author Josh Lockhart
55 | * @since Version 1.3
56 | */
57 | class Slim_Session_Flash implements ArrayAccess {
58 |
59 | /**
60 | * @var string Key used to identify flash information in $_SESSION array
61 | */
62 | protected $sessionKey = 'flash';
63 |
64 | /**
65 | * @var array[array] Storage for flash messages
66 | */
67 | protected $messages = array(
68 | 'prev' => array(), //flash messages from prev request
69 | 'next' => array(), //flash messages for next request
70 | 'now' => array() //flash messages for current request
71 | );
72 |
73 | /**
74 | * Constructor
75 | *
76 | * Establishes Flash session key and loads existing
77 | * Flash messages from the $_SESSION.
78 | *
79 | * @param string $sessionKey
80 | * @return void
81 | */
82 | public function __construct( $sessionKey = null ) {
83 | if ( !is_null($sessionKey) ) {
84 | $this->setSessionKey($sessionKey);
85 | }
86 | $this->load();
87 | }
88 |
89 | /**
90 | * Set the $_SESSION key used to access Flash messages
91 | * @param string $key
92 | * @throws RuntimeException If session key is null
93 | * @return Slim_Session_Flash
94 | */
95 | public function setSessionKey( $key ) {
96 | if ( is_null($key) ) {
97 | throw new RuntimeException('Session key cannot be null');
98 | }
99 | $this->sessionKey = (string)$key;
100 | return $this;
101 | }
102 |
103 | /**
104 | * Get the $_SESSION key used to access Flash messages
105 | * @return string
106 | */
107 | public function getSessionKey() {
108 | return $this->sessionKey;
109 | }
110 |
111 | /**
112 | * Set a Flash message for the current request
113 | * @param string $key
114 | * @param string $value
115 | * @return Slim_Session_Flash
116 | */
117 | public function now( $key, $value ) {
118 | $this->messages['now'][(string)$key] = $value;
119 | return $this->save();
120 | }
121 |
122 | /**
123 | * Set a Flash message for the next request
124 | * @param string $key
125 | * @param string $value
126 | * @return Slim_Session_Flash
127 | */
128 | public function set( $key, $value ) {
129 | $this->messages['next'][(string)$key] = $value;
130 | return $this->save();
131 | }
132 |
133 | /**
134 | * Get Flash messages intended for the current request's View
135 | * @return array[String]
136 | */
137 | public function getMessages() {
138 | return array_merge($this->messages['prev'], $this->messages['now']);
139 | }
140 |
141 | /**
142 | * Load Flash messages from $_SESSION
143 | * @return Slim_Session_Flash
144 | */
145 | public function load() {
146 | $this->messages['prev'] = isset($_SESSION[$this->sessionKey]) ? $_SESSION[$this->sessionKey] : array();
147 | return $this;
148 | }
149 |
150 | /**
151 | * Transfer Flash messages from the previous request
152 | * so they are available to the next request.
153 | * @return Slim_Session_Flash
154 | */
155 | public function keep() {
156 | foreach ( $this->messages['prev'] as $key => $val ) {
157 | $this->messages['next'][$key] = $val;
158 | }
159 | return $this->save();
160 | }
161 |
162 | /**
163 | * Save Flash messages to $_SESSION
164 | * @return Slim_Session_Flash
165 | */
166 | public function save() {
167 | $_SESSION[$this->sessionKey] = $this->messages['next'];
168 | return $this;
169 | }
170 |
171 | /***** ARRAY ACCESS INTERFACE *****/
172 |
173 | public function offsetExists( $offset ) {
174 | $messages = $this->getMessages();
175 | return isset($messages[$offset]);
176 | }
177 |
178 | public function offsetGet( $offset ) {
179 | $messages = $this->getMessages();
180 | return isset($messages[$offset]) ? $messages[$offset] : null;
181 | }
182 |
183 | public function offsetSet( $offset, $value ) {
184 | $this->now($offset, $value);
185 | }
186 |
187 | public function offsetUnset( $offset ) {
188 | unset($this->messages['prev'][$offset]);
189 | unset($this->messages['now'][$offset]);
190 | }
191 |
192 | }
--------------------------------------------------------------------------------
/Slim/Http/Cookie.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Cookie
35 | *
36 | * Object-oriented representation of a Cookie to be sent in an HTTP response
37 | *
38 | * @package Slim
39 | * @author Josh Lockhart
40 | * @since Version 1.0
41 | */
42 | class Slim_Http_Cookie {
43 |
44 | /**
45 | * @var string
46 | */
47 | protected $name;
48 |
49 | /**
50 | * @var string
51 | */
52 | protected $value;
53 |
54 | /**
55 | * @var int UNIX timestamp
56 | */
57 | protected $expires;
58 |
59 | /**
60 | * @var string
61 | */
62 | protected $path;
63 |
64 | /**
65 | * @var string
66 | */
67 | protected $domain;
68 |
69 | /**
70 | * @var bool
71 | */
72 | protected $secure;
73 |
74 | /**
75 | * @var bool
76 | */
77 | protected $httponly;
78 |
79 | /**
80 | * Constructor
81 | * @param string $name The cookie name
82 | * @param string $value The cookie value
83 | * @param mixed $time The duration of the cookie;
84 | * If integer, should be a UNIX timestamp;
85 | * If string, converted to UNIX timestamp with `strtotime`;
86 | * @param string $path The path on the server in which the cookie will be available on
87 | * @param string $domain The domain that the cookie is available to
88 | * @param bool $secure Indicates that the cookie should only be transmitted over a secure
89 | * HTTPS connection from the client
90 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
91 | * @return void
92 | */
93 | public function __construct( $name, $value = null, $expires = 0, $path = null, $domain = null, $secure = false, $httponly = false ) {
94 | $this->setName($name);
95 | $this->setValue($value);
96 | $this->setExpires($expires);
97 | $this->setPath($path);
98 | $this->setDomain($domain);
99 | $this->setSecure($secure);
100 | $this->setHttpOnly($httponly);
101 | }
102 |
103 | /**
104 | * Get cookie name
105 | * @return string
106 | */
107 | public function getName() {
108 | return $this->name;
109 | }
110 |
111 | /**
112 | * Set cookie name
113 | * @param string $name
114 | * @return void
115 | */
116 | public function setName( $name ) {
117 | $this->name = (string)$name;
118 | }
119 |
120 | /**
121 | * Get cookie value
122 | * @return string
123 | */
124 | public function getValue() {
125 | return $this->value;
126 | }
127 |
128 | /**
129 | * Set cookie value
130 | * @param string $value
131 | * @return void
132 | */
133 | public function setValue( $value ) {
134 | $this->value = (string)$value;
135 | }
136 |
137 | /**
138 | * Get cookie expiration time
139 | * @return int UNIX timestamp
140 | */
141 | public function getExpires() {
142 | return $this->expires;
143 | }
144 |
145 | /**
146 | * Set cookie expiration time
147 | * @param string|int Cookie expiration time
148 | * @return void
149 | */
150 | public function setExpires( $time ) {
151 | $this->expires = is_string($time) ? strtotime($time) : (int)$time;
152 | }
153 |
154 | /**
155 | * Get cookie path
156 | * @return string
157 | */
158 | public function getPath() {
159 | return $this->path;
160 | }
161 |
162 | /**
163 | * Set cookie path
164 | * @param string $path
165 | * @return void
166 | */
167 | public function setPath( $path ) {
168 | $this->path = (string)$path;
169 | }
170 |
171 | /**
172 | * Get cookie domain
173 | * @return string
174 | */
175 | public function getDomain() {
176 | return $this->domain;
177 | }
178 |
179 | /**
180 | * Set cookie domain
181 | * @param string $domain
182 | * @return void
183 | */
184 | public function setDomain( $domain ) {
185 | $this->domain = (string)$domain;
186 | }
187 |
188 | /**
189 | * Is cookie sent only if SSL/HTTPS is used?
190 | * @return bool
191 | */
192 | public function getSecure() {
193 | return $this->secure;
194 | }
195 |
196 | /**
197 | * Set whether cookie is sent only if SSL/HTTPS is used
198 | * @param bool $secure
199 | * @return void
200 | */
201 | public function setSecure( $secure ) {
202 | $this->secure = (bool)$secure;
203 | }
204 |
205 | /**
206 | * Is cookie sent with HTTP protocol only?
207 | * @return bool
208 | */
209 | public function getHttpOnly() {
210 | return $this->httponly;
211 | }
212 |
213 | /**
214 | * Set whether cookie is sent with HTTP protocol only
215 | * @param bool $httponly
216 | * @return void
217 | */
218 | public function setHttpOnly( $httponly ) {
219 | $this->httponly = (bool)$httponly;
220 | }
221 |
222 | }
--------------------------------------------------------------------------------
/Slim/Router.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Router
35 | *
36 | * Responsible for registering route paths with associated callables.
37 | * When a Slim application is run, the Router finds a matching Route for
38 | * the current HTTP request, and if a matching route is found, executes
39 | * the Route's associated callable passing it parameters from the Request URI.
40 | *
41 | * @package Slim
42 | * @author Josh Lockhart
43 | * @since Version 1.0
44 | */
45 | class Slim_Router implements IteratorAggregate {
46 |
47 | /**
48 | * @var Slim_Http_Request
49 | */
50 | protected $request;
51 |
52 | /**
53 | * @var array Lookup hash of routes, keyed by Request method
54 | */
55 | protected $routes;
56 |
57 | /**
58 | * @var array Lookup hash of named routes, keyed by route name
59 | */
60 | protected $namedRoutes;
61 |
62 | /**
63 | * @var array Array of routes that match the Request method and URL
64 | */
65 | protected $matchedRoutes;
66 |
67 | /**
68 | * @var mixed Callable to be invoked if no matching routes are found
69 | */
70 | protected $notFound;
71 |
72 | /**
73 | * @var mixed Callable to be invoked if application error
74 | */
75 | protected $error;
76 |
77 | /**
78 | * Constructor
79 | * @param Slim_Http_Request $request The HTTP request object
80 | */
81 | public function __construct( Slim_Http_Request $request ) {
82 | $this->request = $request;
83 | $this->routes = array();
84 | }
85 |
86 | /**
87 | * Get Iterator
88 | * @return ArrayIterator
89 | */
90 | public function getIterator() {
91 | return new ArrayIterator($this->getMatchedRoutes());
92 | }
93 |
94 | /**
95 | * Get Request
96 | * @return Slim_Http_Request
97 | */
98 | public function getRequest() {
99 | return $this->request;
100 | }
101 |
102 | /**
103 | * Set Request
104 | * @param Slim_Http_Request $req
105 | * @return void
106 | */
107 | public function setRequest( Slim_Http_Request $req ) {
108 | $this->request = $req;
109 | }
110 |
111 | /**
112 | * Return routes that match the current request
113 | * @return array[Slim_Route]
114 | */
115 | public function getMatchedRoutes( $reload = false ) {
116 | if ( $reload || is_null($this->matchedRoutes) ) {
117 | $this->matchedRoutes = array();
118 | foreach ( $this->routes as $route ) {
119 | if ( $route->matches($this->request->getResourceUri()) ) {
120 | $this->matchedRoutes[] = $route;
121 | }
122 | }
123 | }
124 | return $this->matchedRoutes;
125 | }
126 |
127 | /**
128 | * Map a route to a callback function
129 | * @param string $pattern The URL pattern (ie. "/books/:id")
130 | * @param mixed $callable Anything that returns TRUE for is_callable()
131 | * @return Slim_Route
132 | */
133 | public function map( $pattern, $callable ) {
134 | $route = new Slim_Route($pattern, $callable);
135 | $route->setRouter($this);
136 | $this->routes[] = $route;
137 | return $route;
138 | }
139 |
140 | /**
141 | * Cache named route
142 | * @param string $name The route name
143 | * @param Slim_Route $route The route object
144 | * @throws RuntimeException If a named route already exists with the same name
145 | * @return void
146 | */
147 | public function cacheNamedRoute( $name, Slim_Route $route ) {
148 | if ( isset($this->namedRoutes[(string)$name]) ) {
149 | throw new RuntimeException('Named route already exists with name: ' . $name);
150 | }
151 | $this->namedRoutes[$name] = $route;
152 | }
153 |
154 | /**
155 | * Get URL for named route
156 | * @param string $name The name of the route
157 | * @param array Associative array of URL parameter names and values
158 | * @throws RuntimeException If named route not found
159 | * @return string The URL for the given route populated with the given parameters
160 | */
161 | public function urlFor( $name, $params = array() ) {
162 | if ( !isset($this->namedRoutes[(string)$name]) ) {
163 | throw new RuntimeException('Named route not found for name: ' . $name);
164 | }
165 | $pattern = $this->namedRoutes[(string)$name]->getPattern();
166 | $search = $replace = array();
167 | foreach ( $params as $key => $value ) {
168 | $search[] = ':' . $key;
169 | $replace[] = $value;
170 | }
171 | $pattern = str_replace($search, $replace, $pattern);
172 | //Remove remnants of unpopulated, trailing optional pattern segments
173 | return preg_replace(array(
174 | '@\(\/?:.+\/??\)\??@',
175 | '@\?|\(|\)@'
176 | ), '', $this->request->getRootUri() . $pattern);
177 | }
178 |
179 | /**
180 | * Register a 404 Not Found callback
181 | * @param mixed $callable Anything that returns TRUE for is_callable()
182 | * @return mixed
183 | */
184 | public function notFound( $callable = null ) {
185 | if ( is_callable($callable) ) {
186 | $this->notFound = $callable;
187 | }
188 | return $this->notFound;
189 | }
190 |
191 | /**
192 | * Register a 500 Error callback
193 | * @param mixed $callable Anything that returns TRUE for is_callable()
194 | * @return mixed
195 | */
196 | public function error( $callable = null ) {
197 | if ( is_callable($callable) ) {
198 | $this->error = $callable;
199 | }
200 | return $this->error;
201 | }
202 |
203 | }
--------------------------------------------------------------------------------
/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 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Response
35 | *
36 | * Object-oriented representation of an HTTP response that is
37 | * returned to the client. This class is responsible for:
38 | *
39 | * - HTTP response status
40 | * - HTTP response body
41 | * - HTTP response headers
42 | * - HTTP response cookies
43 | *
44 | * @package Slim
45 | * @author Josh Lockhart
46 | * @author Kris Jordan
47 | * @since Version 1.0
48 | */
49 | class Slim_Http_Response {
50 |
51 | /**
52 | * @var Slim_Http_Request
53 | */
54 | protected $request;
55 |
56 | /**
57 | * @var string
58 | */
59 | protected $httpVersion = '1.1';
60 |
61 | /**
62 | * @var int HTTP status code
63 | */
64 | protected $status = 200;
65 |
66 | /**
67 | * @var array Key-value array of HTTP response headers
68 | */
69 | protected $headers = array();
70 |
71 | /**
72 | * @var string HTTP response body
73 | */
74 | protected $body = '';
75 |
76 | /**
77 | * @var int Length of HTTP response body
78 | */
79 | protected $length = 0;
80 |
81 | /**
82 | * @var array HTTP response codes and messages
83 | */
84 | protected static $messages = array(
85 | //Informational 1xx
86 | 100 => '100 Continue',
87 | 101 => '101 Switching Protocols',
88 | //Successful 2xx
89 | 200 => '200 OK',
90 | 201 => '201 Created',
91 | 202 => '202 Accepted',
92 | 203 => '203 Non-Authoritative Information',
93 | 204 => '204 No Content',
94 | 205 => '205 Reset Content',
95 | 206 => '206 Partial Content',
96 | //Redirection 3xx
97 | 300 => '300 Multiple Choices',
98 | 301 => '301 Moved Permanently',
99 | 302 => '302 Found',
100 | 303 => '303 See Other',
101 | 304 => '304 Not Modified',
102 | 305 => '305 Use Proxy',
103 | 306 => '306 (Unused)',
104 | 307 => '307 Temporary Redirect',
105 | //Client Error 4xx
106 | 400 => '400 Bad Request',
107 | 401 => '401 Unauthorized',
108 | 402 => '402 Payment Required',
109 | 403 => '403 Forbidden',
110 | 404 => '404 Not Found',
111 | 405 => '405 Method Not Allowed',
112 | 406 => '406 Not Acceptable',
113 | 407 => '407 Proxy Authentication Required',
114 | 408 => '408 Request Timeout',
115 | 409 => '409 Conflict',
116 | 410 => '410 Gone',
117 | 411 => '411 Length Required',
118 | 412 => '412 Precondition Failed',
119 | 413 => '413 Request Entity Too Large',
120 | 414 => '414 Request-URI Too Long',
121 | 415 => '415 Unsupported Media Type',
122 | 416 => '416 Requested Range Not Satisfiable',
123 | 417 => '417 Expectation Failed',
124 | 422 => '422 Unprocessable Entity',
125 | 423 => '423 Locked',
126 | //Server Error 5xx
127 | 500 => '500 Internal Server Error',
128 | 501 => '501 Not Implemented',
129 | 502 => '502 Bad Gateway',
130 | 503 => '503 Service Unavailable',
131 | 504 => '504 Gateway Timeout',
132 | 505 => '505 HTTP Version Not Supported'
133 | );
134 |
135 | /**
136 | * @var CookieJar Manages Cookies to be sent with this Response
137 | */
138 | protected $cookieJar;
139 |
140 | /**
141 | * Constructor
142 | */
143 | public function __construct( Slim_Http_Request $req ) {
144 | $this->request = $req;
145 | $this->header('Content-Type', 'text/html');
146 | }
147 |
148 | /**
149 | * Set and/or get the HTTP response version
150 | * @param string $version
151 | * @return void
152 | * @throws InvalidArgumentException If argument is not a valid HTTP version
153 | */
154 | public function httpVersion( $version = null ) {
155 | if ( $version ) {
156 | $version = (string)$version;
157 | if ( $version === '1.0' || $version === '1.1' ) {
158 | $this->httpVersion = $version;
159 | } else {
160 | throw new InvalidArgumentException('Invalid HTTP version in Response object');
161 | }
162 | }
163 | return $this->httpVersion;
164 | }
165 |
166 | /**
167 | * Set and/or get the HTTP response status code
168 | * @param int $status
169 | * @return int
170 | * @throws InvalidArgumentException If argument is not a valid HTTP status code
171 | */
172 | public function status( $status = null ) {
173 | if ( !is_null($status) ) {
174 | if ( !in_array(intval($status), array_keys(self::$messages)) ) {
175 | throw new InvalidArgumentException('Cannot set Response status. Provided status code "' . $status . '" is not a valid HTTP response code.');
176 | }
177 | $this->status = intval($status);
178 | }
179 | return $this->status;
180 | }
181 |
182 | /**
183 | * Get HTTP response headers
184 | * @return array
185 | */
186 | public function headers() {
187 | return $this->headers;
188 | }
189 |
190 | /**
191 | * Get and/or set an HTTP response header
192 | * @param string $key The header name
193 | * @param string $value The header value
194 | * @return string|null The header value, or NULL if header not set
195 | */
196 | public function header( $key, $value = null ) {
197 | if ( !is_null($value) ) {
198 | $this->headers[$key] = $value;
199 | }
200 | return isset($this->headers[$key]) ? $this->headers[$key] : null;
201 | }
202 |
203 | /**
204 | * Set the HTTP response body
205 | * @param string $body The new HTTP response body
206 | * @return string The new HTTP response body
207 | */
208 | public function body( $body = null ) {
209 | if ( !is_null($body) ) {
210 | $this->body = '';
211 | $this->length = 0;
212 | $this->write($body);
213 | }
214 | return $this->body;
215 | }
216 |
217 | /**
218 | * Append the HTTP response body
219 | * @param string $body Content to append to the current HTTP response body
220 | * @return string The updated HTTP response body
221 | */
222 | public function write( $body ) {
223 | $body = (string)$body;
224 | $this->length += strlen($body);
225 | $this->body .= $body;
226 | $this->header('Content-Length', $this->length);
227 | return $body;
228 | }
229 |
230 | /**
231 | * Set cookie jar
232 | * @param Slim_Http_CookieJar $cookieJar
233 | * @return void
234 | */
235 | public function setCookieJar( Slim_Http_CookieJar $cookieJar ) {
236 | $this->cookieJar = $cookieJar;
237 | }
238 |
239 | /**
240 | * Get cookie jar
241 | * @return Slim_Http_CookieJar
242 | */
243 | public function getCookieJar() {
244 | return $this->cookieJar;
245 | }
246 |
247 | /**
248 | * Finalize response headers before response is sent
249 | * @return void
250 | */
251 | public function finalize() {
252 | if ( in_array($this->status, array(204, 304)) ) {
253 | $this->body('');
254 | unset($this->headers['Content-Type']);
255 | }
256 | }
257 |
258 | /**
259 | * Get message for HTTP status code
260 | * @return string|null
261 | */
262 | public static function getMessageForCode( $status ) {
263 | return isset(self::$messages[$status]) ? self::$messages[$status] : null;
264 | }
265 |
266 | /**
267 | * Can this HTTP response have a body?
268 | * @return bool
269 | */
270 | public function canHaveBody() {
271 | return ( $this->status < 100 || $this->status >= 200 ) && $this->status != 204 && $this->status != 304;
272 | }
273 |
274 | /**
275 | * Send headers for HTTP response
276 | * @return void
277 | */
278 | protected function sendHeaders() {
279 | //Finalize response
280 | $this->finalize();
281 |
282 | if ( substr(PHP_SAPI, 0, 3) === 'cgi') {
283 | //Send Status header if running with fastcgi
284 | header('Status: ' . self::getMessageForCode($this->status()));
285 | } else {
286 | //Else send HTTP message
287 | header(sprintf('HTTP/%s %s', $this->httpVersion, self::getMessageForCode($this->status())));
288 | }
289 |
290 | //Send headers
291 | foreach ( $this->headers() as $name => $value ) {
292 | header("$name: $value");
293 | }
294 |
295 | //Send cookies
296 | foreach ( $this->getCookieJar()->getResponseCookies() as $name => $cookie ) {
297 | setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpires(), $cookie->getPath(), $cookie->getDomain(), $cookie->getSecure(), $cookie->getHttpOnly());
298 | }
299 |
300 | //Flush all output to client
301 | flush();
302 | }
303 |
304 | /**
305 | * Send HTTP response
306 | *
307 | * This method will set Response headers, set Response cookies,
308 | * and `echo` the Response body to the current output buffer.
309 | *
310 | * @return void
311 | */
312 | public function send() {
313 | if ( !headers_sent() ) {
314 | $this->sendHeaders();
315 | }
316 | if ( $this->canHaveBody() && $this->request->isHead() === false ) {
317 | echo $this->body;
318 | }
319 | }
320 |
321 | }
--------------------------------------------------------------------------------
/Slim/Route.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Route
35 | *
36 | * @package Slim
37 | * @author Josh Lockhart
38 | * @since Version 1.0
39 | */
40 | class Slim_Route {
41 |
42 | /**
43 | * @var string The route pattern (ie. "/books/:id")
44 | */
45 | protected $pattern;
46 |
47 | /**
48 | * @var mixed The callable associated with this route
49 | */
50 | protected $callable;
51 |
52 | /**
53 | * @var array Conditions for this route's URL parameters
54 | */
55 | protected $conditions = array();
56 |
57 | /**
58 | * @var array Default conditions applied to all Route instances
59 | */
60 | protected static $defaultConditions = array();
61 |
62 | /**
63 | * @var string The name of this route (optional)
64 | */
65 | protected $name;
66 |
67 | /**
68 | * @var array Key-value array of URL parameters
69 | */
70 | protected $params = array();
71 |
72 | /**
73 | * @var array HTTP methods supported by this Route
74 | */
75 | protected $methods = array();
76 |
77 | /**
78 | * @var Slim_Router The Router to which this Route belongs
79 | */
80 | protected $router;
81 |
82 | /**
83 | * @var array[Callable] Middleware
84 | */
85 | protected $middleware = array();
86 |
87 | /**
88 | * Constructor
89 | * @param string $pattern The URL pattern (ie. "/books/:id")
90 | * @param mixed $callable Anything that returns TRUE for is_callable()
91 | */
92 | public function __construct( $pattern, $callable ) {
93 | $this->setPattern($pattern);
94 | $this->setCallable($callable);
95 | $this->setConditions(self::getDefaultConditions());
96 | }
97 |
98 | /**
99 | * Set default route conditions for all instances
100 | * @param array $defaultConditions
101 | * @return void
102 | */
103 | public static function setDefaultConditions( array $defaultConditions ) {
104 | self::$defaultConditions = $defaultConditions;
105 | }
106 |
107 | /**
108 | * Get default route conditions for all instances
109 | * @return array
110 | */
111 | public static function getDefaultConditions() {
112 | return self::$defaultConditions;
113 | }
114 |
115 | /**
116 | * Get route pattern
117 | * @return string
118 | */
119 | public function getPattern() {
120 | return $this->pattern;
121 | }
122 |
123 | /**
124 | * Set route pattern
125 | * @param string $pattern
126 | * @return void
127 | */
128 | public function setPattern( $pattern ) {
129 | $this->pattern = str_replace(')', ')?', (string)$pattern);
130 | }
131 |
132 | /**
133 | * Get route callable
134 | * @return mixed
135 | */
136 | public function getCallable() {
137 | return $this->callable;
138 | }
139 |
140 | /**
141 | * Set route callable
142 | * @param mixed $callable
143 | * @return void
144 | */
145 | public function setCallable($callable) {
146 | $this->callable = $callable;
147 | }
148 |
149 | /**
150 | * Get route conditions
151 | * @return array
152 | */
153 | public function getConditions() {
154 | return $this->conditions;
155 | }
156 |
157 | /**
158 | * Set route conditions
159 | * @param array $conditions
160 | * @return void
161 | */
162 | public function setConditions( array $conditions ) {
163 | $this->conditions = $conditions;
164 | }
165 |
166 | /**
167 | * Get route name
168 | * @return string|null
169 | */
170 | public function getName() {
171 | return $this->name;
172 | }
173 |
174 | /**
175 | * Set route name
176 | * @param string $name
177 | * @return void
178 | */
179 | public function setName( $name ) {
180 | $this->name = (string)$name;
181 | $this->router->cacheNamedRoute($this->name, $this);
182 | }
183 |
184 | /**
185 | * Get route parameters
186 | * @return array
187 | */
188 | public function getParams() {
189 | return $this->params;
190 | }
191 |
192 | /**
193 | * Add supported HTTP method(s)
194 | * @return void
195 | */
196 | public function setHttpMethods() {
197 | $args = func_get_args();
198 | $this->methods = $args;
199 | }
200 |
201 | /**
202 | * Get supported HTTP methods
203 | * @return array
204 | */
205 | public function getHttpMethods() {
206 | return $this->methods;
207 | }
208 |
209 | /**
210 | * Append supported HTTP methods
211 | * @return void
212 | */
213 | public function appendHttpMethods() {
214 | $args = func_get_args();
215 | $this->methods = array_merge($this->methods, $args);
216 | }
217 |
218 | /**
219 | * Append supported HTTP methods (alias for Route::appendHttpMethods)
220 | * @return Slim_Route
221 | */
222 | public function via() {
223 | $args = func_get_args();
224 | $this->methods = array_merge($this->methods, $args);
225 | return $this;
226 | }
227 |
228 | /**
229 | * Detect support for an HTTP method
230 | * @return bool
231 | */
232 | public function supportsHttpMethod( $method ) {
233 | return in_array($method, $this->methods);
234 | }
235 |
236 | /**
237 | * Get router
238 | * @return Slim_Router
239 | */
240 | public function getRouter() {
241 | return $this->router;
242 | }
243 |
244 | /**
245 | * Set router
246 | * @param Slim_Router $router
247 | * @return void
248 | */
249 | public function setRouter( Slim_Router $router ) {
250 | $this->router = $router;
251 | }
252 |
253 | /**
254 | * Get middleware
255 | * @return array[Callable]
256 | */
257 | public function getMiddleware() {
258 | return $this->middleware;
259 | }
260 |
261 | /**
262 | * Set middleware
263 | *
264 | * This method allows middleware to be assigned to a specific Route.
265 | * If the method argument `is_callable` (including callable arrays!),
266 | * we directly append the argument to `$this->middleware`. Else, we
267 | * assume the argument is an array of callables and merge the array
268 | * with `$this->middleware`. Even if non-callables are included in the
269 | * argument array, we still merge them; we lazily check each item
270 | * against `is_callable` during Route::dispatch().
271 | *
272 | * @param Callable|array[Callable]
273 | * @return Slim_Route
274 | * @throws InvalidArgumentException If argument is not callable or not an array
275 | */
276 | public function setMiddleware( $middleware ) {
277 | if ( is_callable($middleware) ) {
278 | $this->middleware[] = $middleware;
279 | } else if ( is_array($middleware) ) {
280 | $this->middleware = array_merge($this->middleware, $middleware);
281 | } else {
282 | throw new InvalidArgumentException('Route middleware must be callable or an array of callables');
283 | }
284 | return $this;
285 | }
286 |
287 | /**
288 | * Matches URI?
289 | *
290 | * Parse this route's pattern, and then compare it to an HTTP resource URI
291 | * This method was modeled after the techniques demonstrated by Dan Sosedoff at:
292 | *
293 | * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/
294 | *
295 | * @param string $resourceUri A Request URI
296 | * @return bool
297 | */
298 | public function matches( $resourceUri ) {
299 | //Extract URL params
300 | preg_match_all('@:([\w]+)@', $this->pattern, $paramNames, PREG_PATTERN_ORDER);
301 | $paramNames = $paramNames[0];
302 |
303 | //Convert URL params into regex patterns, construct a regex for this route
304 | $patternAsRegex = preg_replace_callback('@:[\w]+@', array($this, 'convertPatternToRegex'), $this->pattern);
305 | if ( substr($this->pattern, -1) === '/' ) {
306 | $patternAsRegex = $patternAsRegex . '?';
307 | }
308 | $patternAsRegex = '@^' . $patternAsRegex . '$@';
309 |
310 | //Cache URL params' names and values if this route matches the current HTTP request
311 | if ( preg_match($patternAsRegex, $resourceUri, $paramValues) ) {
312 | array_shift($paramValues);
313 | foreach ( $paramNames as $index => $value ) {
314 | $val = substr($value, 1);
315 | if ( isset($paramValues[$val]) ) {
316 | $this->params[$val] = urldecode($paramValues[$val]);
317 | }
318 | }
319 | return true;
320 | } else {
321 | return false;
322 | }
323 | }
324 |
325 | /**
326 | * Convert a URL parameter (ie. ":id") into a regular expression
327 | * @param array URL parameters
328 | * @return string Regular expression for URL parameter
329 | */
330 | protected function convertPatternToRegex( $matches ) {
331 | $key = str_replace(':', '', $matches[0]);
332 | if ( array_key_exists($key, $this->conditions) ) {
333 | return '(?P<' . $key . '>' . $this->conditions[$key] . ')';
334 | } else {
335 | return '(?P<' . $key . '>[a-zA-Z0-9_\-\.\!\~\*\\\'\(\)\:\@\&\=\$\+,%]+)';
336 | }
337 | }
338 |
339 | /**
340 | * Set route name
341 | * @param string $name The name of the route
342 | * @return Slim_Route
343 | */
344 | public function name( $name ) {
345 | $this->setName($name);
346 | return $this;
347 | }
348 |
349 | /**
350 | * Merge route conditions
351 | * @param array $conditions Key-value array of URL parameter conditions
352 | * @return Slim_Route
353 | */
354 | public function conditions( array $conditions ) {
355 | $this->conditions = array_merge($this->conditions, $conditions);
356 | return $this;
357 | }
358 |
359 | /**
360 | * Dispatch route
361 | *
362 | * This method invokes this route's callable. If middleware is
363 | * registered for this route, each callable middleware is invoked in
364 | * the order specified.
365 | *
366 | * This method is smart about trailing slashes on the route pattern.
367 | * If this route's pattern is defined with a trailing slash, and if the
368 | * current request URI does not have a trailing slash but otherwise
369 | * matches this route's pattern, a Slim_Exception_RequestSlash
370 | * will be thrown triggering an HTTP 301 Permanent Redirect to the same
371 | * URI _with_ a trailing slash. This Exception is caught in the
372 | * `Slim::run` loop. If this route's pattern is defined without a
373 | * trailing slash, and if the current request URI does have a trailing
374 | * slash, this route will not be matched and a 404 Not Found
375 | * response will be sent if no subsequent matching routes are found.
376 | *
377 | * @return bool Was route callable invoked successfully?
378 | * @throws Slim_Exception_RequestSlash
379 | */
380 | public function dispatch() {
381 | if ( substr($this->pattern, -1) === '/' && substr($this->router->getRequest()->getResourceUri(), -1) !== '/' ) {
382 | throw new Slim_Exception_RequestSlash();
383 | }
384 | //Invoke middleware
385 | foreach ( $this->middleware as $mw ) {
386 | if ( is_callable($mw) ) {
387 | call_user_func($mw);
388 | }
389 | }
390 | //Invoke callable
391 | if ( is_callable($this->getCallable()) ) {
392 | call_user_func_array($this->callable, array_values($this->params));
393 | return true;
394 | }
395 | return false;
396 | }
397 |
398 | }
--------------------------------------------------------------------------------
/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 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Request
35 | *
36 | * Object-oriented representation of an HTTP request. This class
37 | * is responsible for parsing the raw HTTP request into a format
38 | * usable by the Slim application.
39 | *
40 | * This class will automatically remove slashes from GET, POST, PUT,
41 | * and Cookie data if magic quotes are enabled.
42 | *
43 | * @package Slim
44 | * @author Josh Lockhart
45 | * @author Kris Jordan
46 | * @since Version 1.0
47 | */
48 | class Slim_Http_Request {
49 |
50 | const METHOD_HEAD = 'HEAD';
51 | const METHOD_GET = 'GET';
52 | const METHOD_POST = 'POST';
53 | const METHOD_PUT = 'PUT';
54 | const METHOD_DELETE = 'DELETE';
55 | const METHOD_OPTIONS = 'OPTIONS';
56 | const METHOD_OVERRIDE = '_METHOD';
57 |
58 | /**
59 | * @var string Request method (ie. "GET", "POST", "PUT", "DELETE", "HEAD")
60 | */
61 | protected $method;
62 |
63 | /**
64 | * @var array Key-value array of HTTP request headers
65 | */
66 | protected $headers;
67 |
68 | /**
69 | * @var array Names of additional headers to parse from the current
70 | * HTTP request that are not prefixed with "HTTP_"
71 | */
72 | protected $additionalHeaders = array('content-type', 'content-length', 'php-auth-user', 'php-auth-pw', 'auth-type', 'x-requested-with');
73 |
74 | /**
75 | * @var array Key-value array of cookies sent with the
76 | * current HTTP request
77 | */
78 | protected $cookies;
79 |
80 | /**
81 | * @var array Key-value array of HTTP GET parameters
82 | */
83 | protected $get;
84 |
85 | /**
86 | * @var array Key-value array of HTTP POST parameters
87 | */
88 | protected $post;
89 |
90 | /**
91 | * @var array Key-value array of HTTP PUT parameters
92 | */
93 | protected $put;
94 |
95 | /**
96 | * @var string Raw body of HTTP request
97 | */
98 | protected $body;
99 |
100 | /**
101 | * @var string Content type of HTTP request
102 | */
103 | protected $contentType;
104 |
105 | /**
106 | * @var string Resource URI (ie. "/person/1")
107 | */
108 | protected $resource;
109 |
110 | /**
111 | * @var string The root URI of the Slim application without trailing slash.
112 | * This will be "" if the app is installed at the web
113 | * document root. If the app is installed in a
114 | * sub-directory "/foo", this will be "/foo".
115 | */
116 | protected $root;
117 |
118 | /**
119 | * Constructor
120 | */
121 | public function __construct() {
122 | $this->method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : false;
123 | $this->headers = $this->loadHttpHeaders();
124 | $this->body = @file_get_contents('php://input');
125 | $this->get = self::stripSlashesIfMagicQuotes($_GET);
126 | $this->post = self::stripSlashesIfMagicQuotes($_POST);
127 | $this->put = self::stripSlashesIfMagicQuotes($this->loadPutParameters());
128 | $this->cookies = self::stripSlashesIfMagicQuotes($_COOKIE);
129 | $this->root = Slim_Http_Uri::getBaseUri(true);
130 | $this->resource = Slim_Http_Uri::getUri(true);
131 | $this->checkForHttpMethodOverride();
132 | }
133 |
134 | /**
135 | * Is this a GET request?
136 | * @return bool
137 | */
138 | public function isGet() {
139 | return $this->method === self::METHOD_GET;
140 | }
141 |
142 | /**
143 | * Is this a POST request?
144 | * @return bool
145 | */
146 | public function isPost() {
147 | return $this->method === self::METHOD_POST;
148 | }
149 |
150 | /**
151 | * Is this a PUT request?
152 | * @return bool
153 | */
154 | public function isPut() {
155 | return $this->method === self::METHOD_PUT;
156 | }
157 |
158 | /**
159 | * Is this a DELETE request?
160 | * @return bool
161 | */
162 | public function isDelete() {
163 | return $this->method === self::METHOD_DELETE;
164 | }
165 |
166 | /**
167 | * Is this a HEAD request?
168 | * @return bool
169 | */
170 | public function isHead() {
171 | return $this->method === self::METHOD_HEAD;
172 | }
173 |
174 | /**
175 | * Is this a OPTIONS request?
176 | * @return bool
177 | */
178 | public function isOptions() {
179 | return $this->method === self::METHOD_OPTIONS;
180 | }
181 |
182 | /**
183 | * Is this a XHR request?
184 | * @return bool
185 | */
186 | public function isAjax() {
187 | return ( $this->params('isajax') || $this->headers('X_REQUESTED_WITH') === 'XMLHttpRequest' );
188 | }
189 |
190 | /**
191 | * Fetch a PUT|POST|GET parameter value
192 | *
193 | * The preferred method to fetch the value of a
194 | * PUT, POST, or GET parameter (searched in that order).
195 | *
196 | * @param string $key The paramter name
197 | * @return string|null The value of parameter, or NULL if parameter not found
198 | */
199 | public function params( $key ) {
200 | foreach ( array('put', 'post', 'get') as $dataSource ) {
201 | $source = $this->$dataSource;
202 | if ( isset($source[(string)$key]) ) {
203 | return $source[(string)$key];
204 | }
205 | }
206 | return null;
207 | }
208 |
209 | /**
210 | * Fetch GET parameter(s)
211 | * @param string $key Name of parameter
212 | * @return array|string|null All parameters, parameter value if $key
213 | * and parameter exists, or NULL if $key
214 | * and parameter does not exist.
215 | */
216 | public function get( $key = null ) {
217 | return $this->arrayOrArrayValue($this->get, $key);
218 | }
219 |
220 | /**
221 | * Fetch POST parameter(s)
222 | * @param string $key Name of parameter
223 | * @return array|string|null All parameters, parameter value if $key
224 | * and parameter exists, or NULL if $key
225 | * and parameter does not exist.
226 | */
227 | public function post( $key = null ) {
228 | return $this->arrayOrArrayValue($this->post, $key);
229 | }
230 |
231 | /**
232 | * Fetch PUT parameter(s)
233 | * @param string $key Name of parameter
234 | * @return array|string|null All parameters, parameter value if $key
235 | * and parameter exists, or NULL if $key
236 | * and parameter does not exist.
237 | */
238 | public function put( $key = null ) {
239 | return $this->arrayOrArrayValue($this->put, $key);
240 | }
241 |
242 | /**
243 | * Fetch COOKIE value(s)
244 | * @param string $key The cookie name
245 | * @return array|string|null All parameters, parameter value if $key
246 | * and parameter exists, or NULL if $key
247 | * and parameter does not exist.
248 | */
249 | public function cookies( $key = null ) {
250 | return $this->arrayOrArrayValue($this->cookies, $key);
251 | }
252 |
253 | /**
254 | * Get HTTP request header
255 | * @param string $key The header name
256 | * @return array|string|null All parameters, parameter value if $key
257 | * and parameter exists, or NULL if $key
258 | * and parameter does not exist.
259 | */
260 | public function headers( $key = null ) {
261 | return is_null($key) ? $this->headers : $this->arrayOrArrayValue($this->headers, $this->convertHttpHeaderName($key));
262 | }
263 |
264 | /**
265 | * Get HTTP request body
266 | * @return string|false String, or FALSE if body could not be read
267 | */
268 | public function getBody() {
269 | return $this->body;
270 | }
271 |
272 | /**
273 | * Get HTTP method
274 | * @return string
275 | */
276 | public function getMethod() {
277 | return $this->method;
278 | }
279 |
280 | /**
281 | * Get HTTP request content type
282 | * @return string
283 | */
284 | public function getContentType() {
285 | if ( !isset($this->contentType) ) {
286 | $contentType = 'application/x-www-form-urlencoded';
287 | $header = $this->headers('CONTENT_TYPE');
288 | if ( !is_null($header) ) {
289 | $headerParts = preg_split('/\s*;\s*/', $header);
290 | $contentType = $headerParts[0];
291 | }
292 | $this->contentType = $contentType;
293 | }
294 | return $this->contentType;
295 | }
296 |
297 | /**
298 | * Get HTTP request resource URI
299 | * @return string
300 | */
301 | public function getResourceUri() {
302 | return $this->resource;
303 | }
304 |
305 | /**
306 | * Get HTTP request root URI
307 | * @return string
308 | */
309 | public function getRootUri() {
310 | return $this->root;
311 | }
312 |
313 | /**
314 | * Fetch array or array value
315 | * @param array $array
316 | * @param string $key
317 | * @return array|mixed Array if key is null, else array value
318 | */
319 | protected function arrayOrArrayValue( array &$array, $key = null ) {
320 | return is_null($key) ? $array : $this->arrayValueForKey($array, $key);
321 | }
322 |
323 | /**
324 | * Fetch value from array
325 | * @return mixed|null
326 | */
327 | protected function arrayValueForKey( array &$array, $key ) {
328 | return isset($array[(string)$key]) ? $array[(string)$key] : null;
329 | }
330 |
331 | /**
332 | * Strip slashes from string or array of strings
333 | * @param array|string $rawData
334 | * @return array|string
335 | */
336 | public static function stripSlashesIfMagicQuotes( $rawData ) {
337 | if ( get_magic_quotes_gpc() ) {
338 | return is_array($rawData) ? array_map(array('self', 'stripSlashesIfMagicQuotes'), $rawData) : stripslashes($rawData);
339 | } else {
340 | return $rawData;
341 | }
342 | }
343 |
344 | /**
345 | * Get PUT parameters
346 | * @return array Key-value array of HTTP request PUT parameters
347 | */
348 | protected function loadPutParameters() {
349 | if ( $this->getContentType() === 'application/x-www-form-urlencoded' ) {
350 | $input = is_string($this->body) ? $this->body : '';
351 | if ( function_exists('mb_parse_str') ) {
352 | mb_parse_str($input, $output);
353 | } else {
354 | parse_str($input, $output);
355 | }
356 | return $output;
357 | } else {
358 | return array();
359 | }
360 | }
361 |
362 | /**
363 | * Get HTTP request headers
364 | * @return array Key-value array of HTTP request headers
365 | */
366 | protected function loadHttpHeaders() {
367 | $headers = array();
368 | foreach ( $_SERVER as $key => $value ) {
369 | $key = $this->convertHttpHeaderName($key);
370 | if ( strpos($key, 'http-') === 0 || in_array($key, $this->additionalHeaders) ) {
371 | $name = str_replace('http-', '', $key);
372 | $headers[$name] = $value;
373 | }
374 | }
375 | return $headers;
376 | }
377 |
378 | /**
379 | * Convert HTTP header name
380 | * @return string
381 | */
382 | protected function convertHttpHeaderName( $name ) {
383 | return str_replace('_', '-', strtolower($name));
384 | }
385 |
386 | /**
387 | * Check for HTTP request method override
388 | *
389 | * Because traditional web browsers do not support PUT and DELETE
390 | * HTTP methods, we use a hidden form input field to
391 | * mimic PUT and DELETE requests. We check for this override here.
392 | *
393 | * @return void
394 | */
395 | protected function checkForHttpMethodOverride() {
396 | if ( isset($this->post[self::METHOD_OVERRIDE]) ) {
397 | $this->method = $this->post[self::METHOD_OVERRIDE];
398 | unset($this->post[self::METHOD_OVERRIDE]);
399 | if ( $this->isPut() ) {
400 | $this->put = $this->post;
401 | }
402 | }
403 | }
404 |
405 | }
--------------------------------------------------------------------------------
/Slim/Http/CookieJar.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | /**
34 | * Cooke Jar
35 | *
36 | * Used to manage signed, encrypted Cookies. Provides:
37 | *
38 | * - Cookie integrity and authenticity with HMAC
39 | * - Confidentiality with symmetric encryption
40 | * - Protection from replay attack if using SSL or TLS
41 | * - Protection from interception if using SSL or TLS
42 | *
43 | * This code was originally called "BigOrNot_CookieManager" and written by
44 | * Matthieu Huguet released under "CopyLeft" license. I have cleaned up the
45 | * code formatting to conform with Slim Framework contributor guidelines and
46 | * added additional code where necessary to play nice with Slim Cookie objects.
47 | *
48 | * Requirements:
49 | *
50 | * - libmcrypt > 2.4.x
51 | *
52 | * @author Matthies Huguet
53 | */
54 | class Slim_Http_CookieJar {
55 |
56 | /**
57 | * @var string Server secret key
58 | */
59 | protected $_secret = '';
60 |
61 | /**
62 | * @var int Cryptographic algorithm used to encrypt cookies data
63 | */
64 | protected $_algorithm = MCRYPT_RIJNDAEL_256;
65 |
66 | /**
67 | * @var int Cryptographic mode (CBC, CFB ...)
68 | */
69 | protected $_mode = MCRYPT_MODE_CBC;
70 |
71 | /**
72 | * @var resource mcrypt module resource
73 | */
74 | protected $_cryptModule = null;
75 |
76 | /**
77 | * @var bool Enable high confidentiality for cookie value (symmetric encryption)
78 | */
79 | protected $_highConfidentiality = true;
80 |
81 | /**
82 | * @var bool Enable SSL support
83 | */
84 | protected $_ssl = false;
85 |
86 | /**
87 | * @var array[Cookie] Cookie objects
88 | */
89 | protected $_cookies = array();
90 |
91 | /**
92 | * Constructor
93 | *
94 | * Initialize cookie manager and mcrypt module.
95 | *
96 | * @param string $secret Server's secret key
97 | * @param array $config
98 | * @throws Exception If secret key is empty
99 | * @throws Exception If unable to open mcypt module
100 | */
101 | public function __construct( $secret, $config = null ) {
102 | if ( empty($secret) ) {
103 | throw new Exception('You must provide a secret key');
104 | }
105 | $this->_secret = $secret;
106 | if ( $config !== null && !is_array($config) ) {
107 | throw new Exception('Config must be an array');
108 | }
109 | if ( is_array($config) ) {
110 | if ( isset($config['high_confidentiality']) ) {
111 | $this->_highConfidentiality = $config['high_confidentiality'];
112 | }
113 | if ( isset($config['mcrypt_algorithm']) ) {
114 | $this->_algorithm = $config['mcrypt_algorithm'];
115 | }
116 | if ( isset($config['mcrypt_mode']) ) {
117 | $this->_mode = $config['mcrypt_mode'];
118 | }
119 | if ( isset($config['enable_ssl']) ) {
120 | $this->_ssl = $config['enable_ssl'];
121 | }
122 | }
123 | if ( extension_loaded('mcrypt') ) {
124 | $this->_cryptModule = mcrypt_module_open($this->_algorithm, '', $this->_mode, '');
125 | if ( $this->_cryptModule === false ) {
126 | throw new Exception('Error while loading mcrypt module');
127 | }
128 | }
129 | }
130 |
131 | /**
132 | * Get the high confidentiality mode
133 | *
134 | * @return bool TRUE if cookie data encryption is enabled, or FALSE if it isn't
135 | */
136 | public function getHighConfidentiality() {
137 | return $this->_highConfidentiality;
138 | }
139 |
140 | /**
141 | * Enable or disable cookie data encryption
142 | *
143 | * @param bool $enable TRUE to enable, FALSE to disable
144 | * @return CookieJar
145 | */
146 | public function setHighConfidentiality( $enable ) {
147 | $this->_highConfidentiality = (bool)$enable;
148 | return $this;
149 | }
150 |
151 | /**
152 | * Get the SSL status (enabled or disabled?)
153 | *
154 | * @return bool TRUE if SSL support is enabled, or FALSE if it isn't
155 | */
156 | public function getSSL() {
157 | return $this->_ssl;
158 | }
159 |
160 | /**
161 | * Enable SSL support (not enabled by default)
162 | *
163 | * Pro: Protect against replay attack
164 | * Con: Cookie's lifetime is limited to SSL session's lifetime
165 | *
166 | * @param bool $enable TRUE to enable, FALSE to disable
167 | * @return CookieJar
168 | */
169 | public function setSSL( $enable ) {
170 | $this->_ssl = (bool)$enable;
171 | return $this;
172 | }
173 |
174 | /**
175 | * Get Cookies for Response
176 | *
177 | * @author Josh Lockhart
178 | * @return array[Cookie]
179 | */
180 | public function getResponseCookies() {
181 | return $this->_cookies;
182 | }
183 |
184 | /**
185 | * Get Cookie with name for Response
186 | *
187 | * @author Josh Lockhart
188 | * @param string $cookiename The name of the Cookie
189 | * @return Cookie|null Cookie, or NULL if Cookie with name not found
190 | */
191 | public function getResponseCookie( $cookiename ) {
192 | return isset($this->_cookies[$cookiename]) ? $this->_cookies[$cookiename] : null;
193 | }
194 |
195 | /**
196 | * Set a secure cookie
197 | *
198 | * @param string $name Cookie name
199 | * @param string $value Cookie value
200 | * @param string $username User identifier
201 | * @param integer $expire Expiration time
202 | * @param string $path Cookie path
203 | * @param string $domain Cookie domain
204 | * @param bool $secure When TRUE, send the cookie only on a secure connection
205 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
206 | */
207 | public function setCookie( $cookiename, $value, $username, $expire = 0, $path = '/', $domain = '', $secure = false, $httponly = null ) {
208 | $secureValue = extension_loaded('mcrypt') ? $this->_secureCookieValue($value, $username, $expire) : $value;
209 | $this->setClassicCookie($cookiename, $secureValue, $expire, $path, $domain, $secure, $httponly);
210 | }
211 |
212 | /**
213 | * Delete a cookie
214 | *
215 | * @param string $name Cookie name
216 | * @param string $path Cookie path
217 | * @param string $domain Cookie domain
218 | * @param bool $secure When TRUE, send the cookie only on a secure connection
219 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
220 | */
221 | public function deleteCookie( $name, $path = '/', $domain = '', $secure = false, $httponly = null ) {
222 | $expire = 315554400; /* 1980-01-01 */
223 | $this->_cookies[$name] = new Slim_Http_Cookie($name, '', $expire, $path, $domain, $secure, $httponly);
224 | //setcookie($name, '', $expire, $path, $domain, $secure, $httponly);
225 | }
226 |
227 | /**
228 | * Get a secure cookie value
229 | *
230 | * Verify the integrity of cookie data and decrypt it. If the cookie
231 | * is invalid, it can be automatically destroyed (default behaviour)
232 | *
233 | * @param string $cookiename Cookie name
234 | * @param bool $delete Destroy the cookie if invalid?
235 | * @return string|false The Cookie value, or FALSE if Cookie invalid
236 | */
237 | public function getCookieValue( $cookiename, $deleteIfInvalid = true ) {
238 | if ( $this->cookieExists($cookiename) ) {
239 | if ( extension_loaded('mcrypt') ) {
240 | $cookieValues = explode('|', $_COOKIE[$cookiename]);
241 | if ( (count($cookieValues) === 4) && ($cookieValues[1] == 0 || $cookieValues[1] >= time()) ) {
242 | $key = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1], $this->_secret);
243 | $cookieData = base64_decode($cookieValues[2]);
244 | if ( $cookieData !== '' && $this->getHighConfidentiality() ) {
245 | $data = $this->_decrypt($cookieData, $key, md5($cookieValues[1]));
246 | } else {
247 | $data = $cookieData;
248 | }
249 | if ( $this->_ssl && isset($_SERVER['SSL_SESSION_ID']) ) {
250 | $verifKey = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1] . $data . $_SERVER['SSL_SESSION_ID'], $key);
251 | } else {
252 | $verifKey = hash_hmac('sha1', $cookieValues[0] . $cookieValues[1] . $data, $key);
253 | }
254 | if ( $verifKey == $cookieValues[3] ) {
255 | return $data;
256 | }
257 | }
258 | } else {
259 | return $_COOKIE[$cookiename];
260 | }
261 | }
262 | if ( $deleteIfInvalid ) {
263 | $this->deleteCookie($cookiename);
264 | }
265 | return false;
266 | }
267 |
268 | /**
269 | * Send a classic (unsecure) cookie
270 | *
271 | * @param string $name Cookie name
272 | * @param string $value Cookie value
273 | * @param integer $expire Expiration time
274 | * @param string $path Cookie path
275 | * @param string $domain Cookie domain
276 | * @param bool $secure When TRUE, send the cookie only on a secure connection
277 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
278 | */
279 | public function setClassicCookie( $cookiename, $value, $expire = 0, $path = '/', $domain = '', $secure = false, $httponly = null ) {
280 | /* httponly option is only available for PHP version >= 5.2 */
281 | if ( $httponly === null ) {
282 | $this->_cookies[$cookiename] = new Slim_Http_Cookie($cookiename, $value, $expire, $path, $domain, $secure);
283 | //setcookie($cookiename, $value, $expire, $path, $domain, $secure);
284 | } else {
285 | $this->_cookies[$cookiename] = new Slim_Http_Cookie($cookiename, $value, $expire, $path, $domain, $secure, $httponly);
286 | //setcookie($cookiename, $value, $expire, $path, $domain, $secure, $httponly);
287 | }
288 | }
289 |
290 | /**
291 | * Verify if a cookie exists
292 | *
293 | * @param string $cookiename
294 | * @return bool TRUE if cookie exist, or FALSE if not
295 | */
296 | public function cookieExists($cookiename) {
297 | return isset($_COOKIE[$cookiename]);
298 | }
299 |
300 | /**
301 | * Secure a cookie value
302 | *
303 | * The initial value is transformed with this protocol:
304 | *
305 | * secureValue = username|expire|base64((value)k,expire)|HMAC(user|expire|value,k)
306 | * where k = HMAC(user|expire, sk)
307 | * and sk is server's secret key
308 | * (value)k,md5(expire) is the result an cryptographic function (ex: AES256) on "value" with key k and initialisation vector = md5(expire)
309 | *
310 | * @param string $value Unsecure value
311 | * @param string $username User identifier
312 | * @param integer $expire Expiration time
313 | * @return string Secured value
314 | */
315 | protected function _secureCookieValue( $value, $username, $expire ) {
316 | if ( is_string($expire) ) {
317 | $expire = strtotime($expire);
318 | }
319 | $key = hash_hmac('sha1', $username . $expire, $this->_secret);
320 | if ( $value !== '' && $this->getHighConfidentiality() ) {
321 | $encryptedValue = base64_encode($this->_encrypt($value, $key, md5($expire)));
322 | } else {
323 | $encryptedValue = base64_encode($value);
324 | }
325 | if ( $this->_ssl && isset($_SERVER['SSL_SESSION_ID']) ) {
326 | $verifKey = hash_hmac('sha1', $username . $expire . $value . $_SERVER['SSL_SESSION_ID'], $key);
327 | } else {
328 | $verifKey = hash_hmac('sha1', $username . $expire . $value, $key);
329 | }
330 | $result = array($username, $expire, $encryptedValue, $verifKey);
331 | return implode('|', $result);
332 | }
333 |
334 | /**
335 | * Encrypt a given data with a given key and a given initialisation vector
336 | *
337 | * @param string $data Data to crypt
338 | * @param string $key Secret key
339 | * @param string $iv Initialisation vector
340 | * @return string Encrypted data
341 | */
342 | protected function _encrypt( $data, $key, $iv ) {
343 | $iv = $this->_validateIv($iv);
344 | $key = $this->_validateKey($key);
345 | mcrypt_generic_init($this->_cryptModule, $key, $iv);
346 | $res = @mcrypt_generic($this->_cryptModule, $data);
347 | mcrypt_generic_deinit($this->_cryptModule);
348 | return $res;
349 | }
350 |
351 | /**
352 | * Decrypt a given data with a given key and a given initialisation vector
353 | *
354 | * @param string $data Data to crypt
355 | * @param string $key Secret key
356 | * @param string $iv Initialisation vector
357 | * @return string Encrypted data
358 | */
359 | protected function _decrypt( $data, $key, $iv ) {
360 | $iv = $this->_validateIv($iv);
361 | $key = $this->_validateKey($key);
362 | mcrypt_generic_init($this->_cryptModule, $key, $iv);
363 | $decryptedData = mdecrypt_generic($this->_cryptModule, $data);
364 | $res = str_replace("\x0", '', $decryptedData);
365 | mcrypt_generic_deinit($this->_cryptModule);
366 | return $res;
367 | }
368 |
369 | /**
370 | * Validate Initialization vector
371 | *
372 | * If given IV is too long for the selected mcrypt algorithm, it will be truncated
373 | *
374 | * @param string $iv Initialization vector
375 | * @return string
376 | */
377 | protected function _validateIv($iv) {
378 | $ivSize = mcrypt_enc_get_iv_size($this->_cryptModule);
379 | if ( strlen($iv) > $ivSize ) {
380 | $iv = substr($iv, 0, $ivSize);
381 | }
382 | return $iv;
383 | }
384 |
385 | /**
386 | * Validate key
387 | *
388 | * If given key is too long for the selected mcrypt algorithm, it will be truncated
389 | *
390 | * @param string $key key
391 | * @param string
392 | */
393 | protected function _validateKey($key) {
394 | $keySize = mcrypt_enc_get_key_size($this->_cryptModule);
395 | if ( strlen($key) > $keySize ) {
396 | $key = substr($key, 0, $keySize);
397 | }
398 | return $key;
399 | }
400 |
401 | }
402 |
--------------------------------------------------------------------------------
/Slim/Slim.php:
--------------------------------------------------------------------------------
1 |
6 | * @copyright 2011 Josh Lockhart
7 | * @link http://www.slimframework.com
8 | * @license http://www.slimframework.com/license
9 | * @version 1.5.0
10 | *
11 | * MIT LICENSE
12 | *
13 | * Permission is hereby granted, free of charge, to any person obtaining
14 | * a copy of this software and associated documentation files (the
15 | * "Software"), to deal in the Software without restriction, including
16 | * without limitation the rights to use, copy, modify, merge, publish,
17 | * distribute, sublicense, and/or sell copies of the Software, and to
18 | * permit persons to whom the Software is furnished to do so, subject to
19 | * the following conditions:
20 | *
21 | * The above copyright notice and this permission notice shall be
22 | * included in all copies or substantial portions of the Software.
23 | *
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 | */
32 |
33 | //Ensure PHP session IDs only use the characters [a-z0-9]
34 | ini_set('session.hash_bits_per_character', 4);
35 | ini_set('session.hash_function', 0);
36 |
37 | //Slim's Encryted Cookies rely on libmcyrpt and these two constants.
38 | //If libmycrpt is unavailable, we ensure the expected constants
39 | //are available to avoid errors.
40 | if ( !defined('MCRYPT_RIJNDAEL_256') ) {
41 | define('MCRYPT_RIJNDAEL_256', 0);
42 | }
43 | if ( !defined('MCRYPT_MODE_CBC') ) {
44 | define('MCRYPT_MODE_CBC', 0);
45 | }
46 |
47 | //This determines which errors are reported by PHP. By default, all
48 | //errors (including E_STRICT) are reported.
49 | error_reporting(E_ALL | E_STRICT);
50 |
51 | //This tells PHP to auto-load classes using Slim's autoloader; this will
52 | //only auto-load a class file located in the same directory as Slim.php
53 | //whose file name (excluding the final dot and extension) is the same
54 | //as its class name (case-sensitive). For example, "View.php" will be
55 | //loaded when Slim uses the "View" class for the first time.
56 | spl_autoload_register(array('Slim', 'autoload'));
57 |
58 | //PHP 5.3 will complain if you don't set a timezone. If you do not
59 | //specify your own timezone before requiring Slim, this tells PHP to use UTC.
60 | if ( @date_default_timezone_set(date_default_timezone_get()) === false ) {
61 | date_default_timezone_set('UTC');
62 | }
63 |
64 | /**
65 | * Slim
66 | *
67 | * @package Slim
68 | * @author Josh Lockhart
69 | * @since Version 1.0
70 | */
71 | class Slim {
72 |
73 | /**
74 | * @var array[Slim]
75 | */
76 | protected static $apps = array();
77 |
78 | /**
79 | * @var string
80 | */
81 | protected $name;
82 |
83 | /**
84 | * @var Slim_Http_Request
85 | */
86 | protected $request;
87 |
88 | /**
89 | * @var Slim_Http_Response
90 | */
91 | protected $response;
92 |
93 | /**
94 | * @var Slim_Router
95 | */
96 | protected $router;
97 |
98 | /**
99 | * @var Slim_View
100 | */
101 | protected $view;
102 |
103 | /**
104 | * @var Slim_Log
105 | */
106 | protected $log;
107 |
108 | /**
109 | * @var array Key-value array of application settings
110 | */
111 | protected $settings;
112 |
113 | /**
114 | * @var string The application mode
115 | */
116 | protected $mode;
117 |
118 | /**
119 | * @var array Plugin hooks
120 | */
121 | protected $hooks = array(
122 | 'slim.before' => array(array()),
123 | 'slim.before.router' => array(array()),
124 | 'slim.before.dispatch' => array(array()),
125 | 'slim.after.dispatch' => array(array()),
126 | 'slim.after.router' => array(array()),
127 | 'slim.after' => array(array())
128 | );
129 |
130 | /**
131 | * Slim auto-loader
132 | *
133 | * This method lazy-loads class files when a given class if first used.
134 | * Class files must exist in the same directory as this file and be named
135 | * the same as its class definition (excluding the dot and extension).
136 | *
137 | * @return void
138 | */
139 | public static function autoload( $class ) {
140 | if ( strpos($class, 'Slim') !== 0 ) {
141 | return;
142 | }
143 | $file = dirname(__FILE__) . '/' . str_replace('_', DIRECTORY_SEPARATOR, substr($class,5)) . '.php';
144 | if ( file_exists($file) ) {
145 | require $file;
146 | }
147 | }
148 |
149 | /***** INITIALIZATION *****/
150 |
151 | /**
152 | * Constructor
153 | * @param array $userSettings
154 | * @return void
155 | */
156 | public function __construct( $userSettings = array() ) {
157 | //Merge application settings
158 | $this->settings = array_merge(array(
159 | //Mode
160 | 'mode' => 'development',
161 | //Logging
162 | 'log.enable' => false,
163 | 'log.logger' => null,
164 | 'log.path' => './logs',
165 | 'log.level' => 4,
166 | //Debugging
167 | 'debug' => true,
168 | //View
169 | 'templates.path' => './templates',
170 | 'view' => 'Slim_View',
171 | //Settings for all cookies
172 | 'cookies.lifetime' => '20 minutes',
173 | 'cookies.path' => '/',
174 | 'cookies.domain' => '',
175 | 'cookies.secure' => false,
176 | 'cookies.httponly' => false,
177 | //Settings for encrypted cookies
178 | 'cookies.secret_key' => 'CHANGE_ME',
179 | 'cookies.cipher' => MCRYPT_RIJNDAEL_256,
180 | 'cookies.cipher_mode' => MCRYPT_MODE_CBC,
181 | 'cookies.encrypt' => true,
182 | 'cookies.user_id' => 'DEFAULT',
183 | //Session handler
184 | 'session.handler' => new Slim_Session_Handler_Cookies(),
185 | 'session.flash_key' => 'flash',
186 | //HTTP
187 | 'http.version' => null
188 | ), $userSettings);
189 |
190 | //Determine application mode
191 | $this->getMode();
192 |
193 | //Setup HTTP request and response handling
194 | $this->request = new Slim_Http_Request();
195 | $this->response = new Slim_Http_Response($this->request);
196 | $this->response->setCookieJar(new Slim_Http_CookieJar($this->settings['cookies.secret_key'], array(
197 | 'high_confidentiality' => $this->settings['cookies.encrypt'],
198 | 'mcrypt_algorithm' => $this->settings['cookies.cipher'],
199 | 'mcrypt_mode' => $this->settings['cookies.cipher_mode'],
200 | 'enable_ssl' => $this->settings['cookies.secure']
201 | )));
202 | $this->response->httpVersion($this->settings['http.version']);
203 | $this->router = new Slim_Router($this->request);
204 |
205 | //Start session if not already started
206 | if ( session_id() === '' ) {
207 | $sessionHandler = $this->config('session.handler');
208 | if ( $sessionHandler instanceof Slim_Session_Handler ) {
209 | $sessionHandler->register($this);
210 | }
211 | session_cache_limiter(false);
212 | session_start();
213 | }
214 |
215 | //Setup view with flash messaging
216 | $this->view($this->config('view'))->setData('flash', new Slim_Session_Flash($this->config('session.flash_key')));
217 |
218 | //Set app name
219 | if ( !isset(self::$apps['default']) ) {
220 | $this->setName('default');
221 | }
222 |
223 | //Set global Error handler after Slim app instantiated
224 | set_error_handler(array('Slim', 'handleErrors'));
225 | }
226 |
227 | /**
228 | * Get application mode
229 | * @return string
230 | */
231 | public function getMode() {
232 | if ( !isset($this->mode) ) {
233 | if ( isset($_ENV['SLIM_MODE']) ) {
234 | $this->mode = (string)$_ENV['SLIM_MODE'];
235 | } else {
236 | $envMode = getenv('SLIM_MODE');
237 | if ( $envMode !== false ) {
238 | $this->mode = $envMode;
239 | } else {
240 | $this->mode = (string)$this->config('mode');
241 | }
242 | }
243 | }
244 | return $this->mode;
245 | }
246 |
247 | /***** NAMING *****/
248 |
249 | /**
250 | * Get Slim application with name
251 | * @param string $name The name of the Slim application to fetch
252 | * @return Slim|null
253 | */
254 | public static function getInstance( $name = 'default' ) {
255 | return isset(self::$apps[(string)$name]) ? self::$apps[(string)$name] : null;
256 | }
257 |
258 | /**
259 | * Set Slim application name
260 | * @param string $name The name of this Slim application
261 | * @return void
262 | */
263 | public function setName( $name ) {
264 | $this->name = $name;
265 | self::$apps[$name] = $this;
266 | }
267 |
268 | /**
269 | * Get Slim application name
270 | * @return string|null
271 | */
272 | public function getName() {
273 | return $this->name;
274 | }
275 |
276 | /***** LOGGING *****/
277 |
278 | /**
279 | * Get application Log (lazy-loaded)
280 | * @return Slim_Log
281 | */
282 | public function getLog() {
283 | if ( !isset($this->log) ) {
284 | $this->log = new Slim_Log();
285 | $this->log->setEnabled($this->config('log.enable'));
286 | $logger = $this->config('log.logger');
287 | if ( $logger ) {
288 | $this->log->setLogger($logger);
289 | } else {
290 | $this->log->setLogger(new Slim_Logger($this->config('log.path'), $this->config('log.level')));
291 | }
292 | }
293 | return $this->log;
294 | }
295 |
296 | /***** CONFIGURATION *****/
297 |
298 | /**
299 | * Configure Slim for a given mode
300 | *
301 | * This method will immediately invoke the callable if
302 | * the specified mode matches the current application mode.
303 | * Otherwise, the callable is ignored. This should be called
304 | * only _after_ you initialize your Slim app.
305 | *
306 | * @param string $mode
307 | * @param mixed $callable
308 | * @return void
309 | */
310 | public function configureMode( $mode, $callable ) {
311 | if ( $mode === $this->getMode() && is_callable($callable) ) {
312 | call_user_func($callable);
313 | }
314 | }
315 |
316 | /**
317 | * Configure Slim Settings
318 | *
319 | * This method defines application settings and acts as a setter and a getter.
320 | *
321 | * If only one argument is specified and that argument is a string, the value
322 | * of the setting identified by the first argument will be returned, or NULL if
323 | * that setting does not exist.
324 | *
325 | * If only one argument is specified and that argument is an associative array,
326 | * the array will be merged into the existing application settings.
327 | *
328 | * If two arguments are provided, the first argument is the name of the setting
329 | * to be created or updated, and the second argument is the setting value.
330 | *
331 | * @param string|array $name If a string, the name of the setting to set or retrieve. Else an associated array of setting names and values
332 | * @param mixed $value If name is a string, the value of the setting identified by $name
333 | * @return mixed The value of a setting if only one argument is a string
334 | */
335 | public function config( $name, $value = null ) {
336 | if ( func_num_args() === 1 ) {
337 | if ( is_array($name) ) {
338 | $this->settings = array_merge($this->settings, $name);
339 | } else {
340 | return in_array($name, array_keys($this->settings)) ? $this->settings[$name] : null;
341 | }
342 | } else {
343 | $this->settings[$name] = $value;
344 | }
345 | }
346 |
347 | /***** ROUTING *****/
348 |
349 | /**
350 | * Add GET|POST|PUT|DELETE route
351 | *
352 | * Adds a new route to the router with associated callable. This
353 | * route will only be invoked when the HTTP request's method matches
354 | * this route's method.
355 | *
356 | * ARGUMENTS:
357 | *
358 | * First: string The URL pattern (REQUIRED)
359 | * In-Between: mixed Anything that returns TRUE for `is_callable` (OPTIONAL)
360 | * Last: mixed Anything that returns TRUE for `is_callable` (REQUIRED)
361 | *
362 | * The first argument is required and must always be the
363 | * route pattern (ie. '/books/:id').
364 | *
365 | * The last argument is required and must always be the callable object
366 | * to be invoked when the route matches an HTTP request.
367 | *
368 | * You may also provide an unlimited number of in-between arguments;
369 | * each interior argument must be callable and will be invoked in the
370 | * order specified before the route's callable is invoked.
371 | *
372 | * USAGE:
373 | *
374 | * Slim::get('/foo'[, middleware, middleware, ...], callable);
375 | *
376 | * @param array (See notes above)
377 | * @return Slim_Route
378 | */
379 | protected function mapRoute($args) {
380 | $pattern = array_shift($args);
381 | $callable = array_pop($args);
382 | $route = $this->router->map($pattern, $callable);
383 | if ( count($args) > 0 ) {
384 | $route->setMiddleware($args);
385 | }
386 | return $route;
387 | }
388 |
389 | /**
390 | * Add generic route without associated HTTP method
391 | * @see Slim::mapRoute
392 | * @return Slim_Route
393 | */
394 | public function map() {
395 | $args = func_get_args();
396 | return $this->mapRoute($args);
397 | }
398 |
399 | /**
400 | * Add GET route
401 | * @see Slim::mapRoute
402 | * @return Slim_Route
403 | */
404 | public function get() {
405 | $args = func_get_args();
406 | return $this->mapRoute($args)->via(Slim_Http_Request::METHOD_GET, Slim_Http_Request::METHOD_HEAD);
407 | }
408 |
409 | /**
410 | * Add POST route
411 | * @see Slim::mapRoute
412 | * @return Slim_Route
413 | */
414 | public function post() {
415 | $args = func_get_args();
416 | return $this->mapRoute($args)->via(Slim_Http_Request::METHOD_POST);
417 | }
418 |
419 | /**
420 | * Add PUT route
421 | * @see Slim::mapRoute
422 | * @return Slim_Route
423 | */
424 | public function put() {
425 | $args = func_get_args();
426 | return $this->mapRoute($args)->via(Slim_Http_Request::METHOD_PUT);
427 | }
428 |
429 | /**
430 | * Add DELETE route
431 | * @see Slim::mapRoute
432 | * @return Slim_Route
433 | */
434 | public function delete() {
435 | $args = func_get_args();
436 | return $this->mapRoute($args)->via(Slim_Http_Request::METHOD_DELETE);
437 | }
438 |
439 | /**
440 | * Add OPTIONS route
441 | * @see Slim::mapRoute
442 | * @return Slim_Route
443 | */
444 | public function options() {
445 | $args = func_get_args();
446 | return $this->mapRoute($args)->via(Slim_Http_Request::METHOD_OPTIONS);
447 | }
448 |
449 | /**
450 | * Not Found Handler
451 | *
452 | * This method defines or invokes the application-wide Not Found handler.
453 | * There are two contexts in which this method may be invoked:
454 | *
455 | * 1. When declaring the handler:
456 | *
457 | * If the $callable parameter is not null and is callable, this
458 | * method will register the callable to be invoked when no
459 | * routes match the current HTTP request. It WILL NOT invoke the callable.
460 | *
461 | * 2. When invoking the handler:
462 | *
463 | * If the $callable parameter is null, Slim assumes you want
464 | * to invoke an already-registered handler. If the handler has been
465 | * registered and is callable, it is invoked and sends a 404 HTTP Response
466 | * whose body is the output of the Not Found handler.
467 | *
468 | * @param mixed $callable Anything that returns true for is_callable()
469 | * @return void
470 | */
471 | public function notFound( $callable = null ) {
472 | if ( !is_null($callable) ) {
473 | $this->router->notFound($callable);
474 | } else {
475 | ob_start();
476 | $customNotFoundHandler = $this->router->notFound();
477 | if ( is_callable($customNotFoundHandler) ) {
478 | call_user_func($customNotFoundHandler);
479 | } else {
480 | call_user_func(array($this, 'defaultNotFound'));
481 | }
482 | $this->halt(404, ob_get_clean());
483 | }
484 | }
485 |
486 | /**
487 | * Error Handler
488 | *
489 | * This method defines or invokes the application-wide Error handler.
490 | * There are two contexts in which this method may be invoked:
491 | *
492 | * 1. When declaring the handler:
493 | *
494 | * If the $argument parameter is callable, this
495 | * method will register the callable to be invoked when an uncaught
496 | * Exception is detected, or when otherwise explicitly invoked.
497 | * The handler WILL NOT be invoked in this context.
498 | *
499 | * 2. When invoking the handler:
500 | *
501 | * If the $argument parameter is not callable, Slim assumes you want
502 | * to invoke an already-registered handler. If the handler has been
503 | * registered and is callable, it is invoked and passed the caught Exception
504 | * as its one and only argument. The error handler's output is captured
505 | * into an output buffer and sent as the body of a 500 HTTP Response.
506 | *
507 | * @param mixed $argument Callable|Exception
508 | * @return void
509 | */
510 | public function error( $argument = null ) {
511 | if ( is_callable($argument) ) {
512 | //Register error handler
513 | $this->router->error($argument);
514 | } else {
515 | //Invoke error handler
516 | ob_start();
517 | $customErrorHandler = $this->router->error();
518 | if ( is_callable($customErrorHandler) ) {
519 | call_user_func_array($customErrorHandler, array($argument));
520 | } else {
521 | call_user_func_array(array($this, 'defaultError'), array($argument));
522 | }
523 | $this->halt(500, ob_get_clean());
524 | }
525 | }
526 |
527 | /***** ACCESSORS *****/
528 |
529 | /**
530 | * Get the Request object
531 | * @return Slim_Http_Request
532 | */
533 | public function request() {
534 | return $this->request;
535 | }
536 |
537 | /**
538 | * Get the Response object
539 | * @return Slim_Http_Response
540 | */
541 | public function response() {
542 | return $this->response;
543 | }
544 |
545 | /**
546 | * Get the Router object
547 | * @return Slim_Router
548 | */
549 | public function router() {
550 | return $this->router;
551 | }
552 |
553 | /**
554 | * Get and/or set the View
555 | *
556 | * This method declares the View to be used by the Slim application.
557 | * If the argument is a string, Slim will instantiate a new object
558 | * of the same class. If the argument is an instance of View or a subclass
559 | * of View, Slim will use the argument as the View.
560 | *
561 | * If a View already exists and this method is called to create a
562 | * new View, data already set in the existing View will be
563 | * transferred to the new View.
564 | *
565 | * @param string|Slim_View $viewClass The name of a Slim_View class;
566 | * An instance of Slim_View;
567 | * @return Slim_View
568 | */
569 | public function view( $viewClass = null ) {
570 | if ( !is_null($viewClass) ) {
571 | $existingData = is_null($this->view) ? array() : $this->view->getData();
572 | if ( $viewClass instanceOf Slim_View ) {
573 | $this->view = $viewClass;
574 | } else {
575 | $this->view = new $viewClass();
576 | }
577 | $this->view->appendData($existingData);
578 | }
579 | return $this->view;
580 | }
581 |
582 | /***** RENDERING *****/
583 |
584 | /**
585 | * Render a template
586 | *
587 | * Call this method within a GET, POST, PUT, DELETE, NOT FOUND, or ERROR
588 | * callable to render a template whose output is appended to the
589 | * current HTTP response body. How the template is rendered is
590 | * delegated to the current View.
591 | *
592 | * @param string $template The name of the template passed into the View::render method
593 | * @param array $data Associative array of data made available to the View
594 | * @param int $status The HTTP response status code to use (Optional)
595 | * @return void
596 | */
597 | public function render( $template, $data = array(), $status = null ) {
598 | $templatesPath = $this->config('templates.path');
599 | //Legacy support
600 | if ( is_null($templatesPath) ) {
601 | $templatesPath = $this->config('templates_dir');
602 | }
603 | $this->view->setTemplatesDirectory($templatesPath);
604 | if ( !is_null($status) ) {
605 | $this->response->status($status);
606 | }
607 | $this->view->appendData($data);
608 | $this->view->display($template);
609 | }
610 |
611 | /***** HTTP CACHING *****/
612 |
613 | /**
614 | * Set Last-Modified HTTP Response Header
615 | *
616 | * Set the HTTP 'Last-Modified' header and stop if a conditional
617 | * GET request's `If-Modified-Since` header matches the last modified time
618 | * of the resource. The `time` argument is a UNIX timestamp integer value.
619 | * When the current request includes an 'If-Modified-Since' header that
620 | * matches the specified last modified time, the application will stop
621 | * and send a '304 Not Modified' response to the client.
622 | *
623 | * @param int $time The last modified UNIX timestamp
624 | * @throws SlimException Returns HTTP 304 Not Modified response if resource last modified time matches `If-Modified-Since` header
625 | * @throws InvalidArgumentException If provided timestamp is not an integer
626 | * @return void
627 | */
628 | public function lastModified( $time ) {
629 | if ( is_integer($time) ) {
630 | $this->response->header('Last-Modified', date(DATE_RFC1123, $time));
631 | if ( $time === strtotime($this->request->headers('IF_MODIFIED_SINCE')) ) $this->halt(304);
632 | } else {
633 | throw new InvalidArgumentException('Slim::lastModified only accepts an integer UNIX timestamp value.');
634 | }
635 | }
636 |
637 | /**
638 | * Set ETag HTTP Response Header
639 | *
640 | * Set the etag header and stop if the conditional GET request matches.
641 | * The `value` argument is a unique identifier for the current resource.
642 | * The `type` argument indicates whether the etag should be used as a strong or
643 | * weak cache validator.
644 | *
645 | * When the current request includes an 'If-None-Match' header with
646 | * a matching etag, execution is immediately stopped. If the request
647 | * method is GET or HEAD, a '304 Not Modified' response is sent.
648 | *
649 | * @param string $value The etag value
650 | * @param string $type The type of etag to create; either "strong" or "weak"
651 | * @throws InvalidArgumentException If provided type is invalid
652 | * @return void
653 | */
654 | public function etag( $value, $type = 'strong' ) {
655 |
656 | //Ensure type is correct
657 | if ( !in_array($type, array('strong', 'weak')) ) {
658 | throw new InvalidArgumentException('Invalid Slim::etag type. Expected "strong" or "weak".');
659 | }
660 |
661 | //Set etag value
662 | $value = '"' . $value . '"';
663 | if ( $type === 'weak' ) $value = 'W/'.$value;
664 | $this->response->header('ETag', $value);
665 |
666 | //Check conditional GET
667 | if ( $etagsHeader = $this->request->headers('IF_NONE_MATCH')) {
668 | $etags = preg_split('@\s*,\s*@', $etagsHeader);
669 | if ( in_array($value, $etags) || in_array('*', $etags) ) $this->halt(304);
670 | }
671 |
672 | }
673 |
674 | /***** COOKIES *****/
675 |
676 | /**
677 | * Set a normal, unencrypted Cookie
678 | *
679 | * @param string $name The cookie name
680 | * @param mixed $value The cookie value
681 | * @param mixed $time The duration of the cookie;
682 | * If integer, should be UNIX timestamp;
683 | * If string, converted to UNIX timestamp with `strtotime`;
684 | * @param string $path The path on the server in which the cookie will be available on
685 | * @param string $domain The domain that the cookie is available to
686 | * @param bool $secure Indicates that the cookie should only be transmitted over a secure
687 | * HTTPS connection to/from the client
688 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
689 | * @return void
690 | */
691 | public function setCookie( $name, $value, $time = null, $path = null, $domain = null, $secure = null, $httponly = null ) {
692 | $time = is_null($time) ? $this->config('cookies.lifetime') : $time;
693 | $path = is_null($path) ? $this->config('cookies.path') : $path;
694 | $domain = is_null($domain) ? $this->config('cookies.domain') : $domain;
695 | $secure = is_null($secure) ? $this->config('cookies.secure') : $secure;
696 | $httponly = is_null($httponly) ? $this->config('cookies.httponly') : $httponly;
697 | $this->response->getCookieJar()->setClassicCookie($name, $value, $time, $path, $domain, $secure, $httponly);
698 | }
699 |
700 | /**
701 | * Get the value of a Cookie from the current HTTP Request
702 | *
703 | * Return the value of a cookie from the current HTTP request,
704 | * or return NULL if cookie does not exist. Cookies created during
705 | * the current request will not be available until the next request.
706 | *
707 | * @param string $name
708 | * @return string|null
709 | */
710 | public function getCookie( $name ) {
711 | return $this->request->cookies($name);
712 | }
713 |
714 | /**
715 | * Set an encrypted Cookie
716 | *
717 | * @param string $name The cookie name
718 | * @param mixed $value The cookie value
719 | * @param mixed $time The duration of the cookie;
720 | * If integer, should be UNIX timestamp;
721 | * If string, converted to UNIX timestamp with `strtotime`;
722 | * @param string $path The path on the server in which the cookie will be available on
723 | * @param string $domain The domain that the cookie is available to
724 | * @param bool $secure Indicates that the cookie should only be transmitted over a secure
725 | * HTTPS connection from the client
726 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
727 | * @return void
728 | */
729 | public function setEncryptedCookie( $name, $value, $time = null, $path = null, $domain = null, $secure = null, $httponly = null ) {
730 | $time = is_null($time) ? $this->config('cookies.lifetime') : $time;
731 | $path = is_null($path) ? $this->config('cookies.path') : $path;
732 | $domain = is_null($domain) ? $this->config('cookies.domain') : $domain;
733 | $secure = is_null($secure) ? $this->config('cookies.secure') : $secure;
734 | $httponly = is_null($httponly) ? $this->config('cookies.httponly') : $httponly;
735 | $userId = $this->config('cookies.user_id');
736 | $this->response->getCookieJar()->setCookie($name, $value, $userId, $time, $path, $domain, $secure, $httponly);
737 | }
738 |
739 | /**
740 | * Get the value of an encrypted Cookie from the current HTTP request
741 | *
742 | * Return the value of an encrypted cookie from the current HTTP request,
743 | * or return NULL if cookie does not exist. Encrypted cookies created during
744 | * the current request will not be available until the next request.
745 | *
746 | * @param string $name
747 | * @return string|null
748 | */
749 | public function getEncryptedCookie( $name ) {
750 | $value = $this->response->getCookieJar()->getCookieValue($name);
751 | return ($value === false) ? null : $value;
752 | }
753 |
754 | /**
755 | * Delete a Cookie (for both normal or encrypted Cookies)
756 | *
757 | * Remove a Cookie from the client. This method will overwrite an existing Cookie
758 | * with a new, empty, auto-expiring Cookie. This method's arguments must match
759 | * the original Cookie's respective arguments for the original Cookie to be
760 | * removed. If any of this method's arguments are omitted or set to NULL, the
761 | * default Cookie setting values (set during Slim::init) will be used instead.
762 | *
763 | * @param string $name The cookie name
764 | * @param string $path The path on the server in which the cookie will be available on
765 | * @param string $domain The domain that the cookie is available to
766 | * @param bool $secure Indicates that the cookie should only be transmitted over a secure
767 | * HTTPS connection from the client
768 | * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
769 | * @return void
770 | */
771 | public function deleteCookie( $name, $path = null, $domain = null, $secure = null, $httponly = null ) {
772 | $path = is_null($path) ? $this->config('cookies.path') : $path;
773 | $domain = is_null($domain) ? $this->config('cookies.domain') : $domain;
774 | $secure = is_null($secure) ? $this->config('cookies.secure') : $secure;
775 | $httponly = is_null($httponly) ? $this->config('cookies.httponly') : $httponly;
776 | $this->response->getCookieJar()->deleteCookie( $name, $path, $domain, $secure, $httponly );
777 | }
778 |
779 | /***** HELPERS *****/
780 |
781 | /**
782 | * Get the Slim application's absolute directory path
783 | *
784 | * This method returns the absolute path to the Slim application's
785 | * directory. If the Slim application is installed in a public-accessible
786 | * sub-directory, the sub-directory path will be included. This method
787 | * will always return an absolute path WITH a trailing slash.
788 | *
789 | * @return string
790 | */
791 | public function root() {
792 | return rtrim($_SERVER['DOCUMENT_ROOT'], '/') . rtrim($this->request->getRootUri(), '/') . '/';
793 | }
794 |
795 | /**
796 | * Stop
797 | *
798 | * Send the current Response as is and stop executing the Slim
799 | * application. The thrown exception will be caught by the Slim
800 | * custom exception handler which exits this script.
801 | *
802 | * @throws Slim_Exception_Stop
803 | * @return void
804 | */
805 | public function stop() {
806 | $flash = $this->view->getData('flash');
807 | if ( $flash ) {
808 | $flash->save();
809 | }
810 | session_write_close();
811 | $this->response->send();
812 | throw new Slim_Exception_Stop();
813 | }
814 |
815 | /**
816 | * Halt
817 | *
818 | * Halt the application and immediately send an HTTP response with a
819 | * specific status code and body. This may be used to send any type of
820 | * response: info, success, redirect, client error, or server error.
821 | * If you need to render a template AND customize the response status,
822 | * you should use Slim::render() instead.
823 | *
824 | * @param int $status The HTTP response status
825 | * @param string $message The HTTP response body
826 | * @return void
827 | */
828 | public function halt( $status, $message = '') {
829 | if ( ob_get_level() !== 0 ) {
830 | ob_clean();
831 | }
832 | $this->response->status($status);
833 | $this->response->body($message);
834 | $this->stop();
835 | }
836 |
837 | /**
838 | * Pass
839 | *
840 | * This method will cause the Router::dispatch method to ignore
841 | * the current route and continue to the next matching route in the
842 | * dispatch loop. If no subsequent mathing routes are found,
843 | * a 404 Not Found response will be sent to the client.
844 | *
845 | * @throws Slim_Exception_Pass
846 | * @return void
847 | */
848 | public function pass() {
849 | if ( ob_get_level() !== 0 ) {
850 | ob_clean();
851 | }
852 | throw new Slim_Exception_Pass();
853 | }
854 |
855 | /**
856 | * Set the HTTP response Content-Type
857 | * @param string $type The Content-Type for the Response (ie. text/html)
858 | * @return void
859 | */
860 | public function contentType( $type ) {
861 | $this->response->header('Content-Type', $type);
862 | }
863 |
864 | /**
865 | * Set the HTTP response status code
866 | * @param int $status The HTTP response status code
867 | * @return void
868 | */
869 | public function status( $code ) {
870 | $this->response->status($code);
871 | }
872 |
873 | /**
874 | * Get the URL for a named Route
875 | * @param string $name The route name
876 | * @param array $params Key-value array of URL parameters
877 | * @throws RuntimeException If named route does not exist
878 | * @return string
879 | */
880 | public function urlFor( $name, $params = array() ) {
881 | return $this->router->urlFor($name, $params);
882 | }
883 |
884 | /**
885 | * Redirect
886 | *
887 | * This method immediately redirects to a new URL. By default,
888 | * this issues a 302 Found response; this is considered the default
889 | * generic redirect response. You may also specify another valid
890 | * 3xx status code if you want. This method will automatically set the
891 | * HTTP Location header for you using the URL parameter and place the
892 | * destination URL into the response body.
893 | *
894 | * @param string $url The destination URL
895 | * @param int $status The HTTP redirect status code (Optional)
896 | * @throws InvalidArgumentException If status parameter is not a valid 3xx status code
897 | * @return void
898 | */
899 | public function redirect( $url, $status = 302 ) {
900 | if ( $status >= 300 && $status <= 307 ) {
901 | $this->response->header('Location', (string)$url);
902 | $this->halt($status, (string)$url);
903 | } else {
904 | throw new InvalidArgumentException('Slim::redirect only accepts HTTP 300-307 status codes.');
905 | }
906 | }
907 |
908 | /***** FLASH *****/
909 |
910 | /**
911 | * Set flash message for subsequent request
912 | * @param string $key
913 | * @param mixed $value
914 | * @return void
915 | */
916 | public function flash( $key, $value ) {
917 | $this->view->getData('flash')->set($key, $value);
918 | }
919 |
920 | /**
921 | * Set flash message for current request
922 | * @param string $key
923 | * @param mixed $value
924 | * @return void
925 | */
926 | public function flashNow( $key, $value ) {
927 | $this->view->getData('flash')->now($key, $value);
928 | }
929 |
930 | /**
931 | * Keep flash messages from previous request for subsequent request
932 | * @return void
933 | */
934 | public function flashKeep() {
935 | $this->view->getData('flash')->keep();
936 | }
937 |
938 | /***** HOOKS *****/
939 |
940 | /**
941 | * Assign hook
942 | * @param string $name The hook name
943 | * @param mixed $callable A callable object
944 | * @param int $priority The hook priority; 0 = high, 10 = low
945 | * @return void
946 | */
947 | public function hook( $name, $callable, $priority = 10 ) {
948 | if ( !isset($this->hooks[$name]) ) {
949 | $this->hooks[$name] = array(array());
950 | }
951 | if ( is_callable($callable) ) {
952 | $this->hooks[$name][(int)$priority][] = $callable;
953 | }
954 | }
955 |
956 | /**
957 | * Invoke hook
958 | * @param string $name The hook name
959 | * @param mixed $hookArgs (Optional) Argument for hooked functions
960 | * @return mixed
961 | */
962 | public function applyHook( $name, $hookArg = null ) {
963 | if ( !isset($this->hooks[$name]) ) {
964 | $this->hooks[$name] = array(array());
965 | }
966 | if( !empty($this->hooks[$name]) ) {
967 | // Sort by priority, low to high, if there's more than one priority
968 | if ( count($this->hooks[$name]) > 1 ) {
969 | ksort($this->hooks[$name]);
970 | }
971 | foreach( $this->hooks[$name] as $priority ) {
972 | if( !empty($priority) ) {
973 | foreach($priority as $callable) {
974 | $hookArg = call_user_func($callable, $hookArg);
975 | }
976 | }
977 | }
978 | return $hookArg;
979 | }
980 | }
981 |
982 | /**
983 | * Get hook listeners
984 | *
985 | * Return an array of registered hooks. If `$name` is a valid
986 | * hook name, only the listeners attached to that hook are returned.
987 | * Else, all listeners are returned as an associative array whose
988 | * keys are hook names and whose values are arrays of listeners.
989 | *
990 | * @param string $name A hook name (Optional)
991 | * @return array|null
992 | */
993 | public function getHooks( $name = null ) {
994 | if ( !is_null($name) ) {
995 | return isset($this->hooks[(string)$name]) ? $this->hooks[(string)$name] : null;
996 | } else {
997 | return $this->hooks;
998 | }
999 | }
1000 |
1001 | /**
1002 | * Clear hook listeners
1003 | *
1004 | * Clear all listeners for all hooks. If `$name` is
1005 | * a valid hook name, only the listeners attached
1006 | * to that hook will be cleared.
1007 | *
1008 | * @param string $name A hook name (Optional)
1009 | * @return void
1010 | */
1011 | public function clearHooks( $name = null ) {
1012 | if ( !is_null($name) && isset($this->hooks[(string)$name]) ) {
1013 | $this->hooks[(string)$name] = array(array());
1014 | } else {
1015 | foreach( $this->hooks as $key => $value ) {
1016 | $this->hooks[$key] = array(array());
1017 | }
1018 | }
1019 | }
1020 |
1021 | /***** RUN SLIM *****/
1022 |
1023 | /**
1024 | * Run the Slim application
1025 | *
1026 | * This method is the "meat and potatoes" of Slim and should be the last
1027 | * method called. This fires up Slim, invokes the Route that matches
1028 | * the current request, and returns the response to the client.
1029 | *
1030 | * This method will invoke the Not Found handler if no matching
1031 | * routes are found.
1032 | *
1033 | * This method will also catch any unexpected Exceptions thrown by this
1034 | * application; the Exceptions will be logged to this application's log
1035 | * and rethrown to the global Exception handler.
1036 | *
1037 | * @return void
1038 | */
1039 | public function run() {
1040 | try {
1041 | try {
1042 | $this->applyHook('slim.before');
1043 | ob_start();
1044 | $this->applyHook('slim.before.router');
1045 | $dispatched = false;
1046 | $httpMethod = $this->request()->getMethod();
1047 | $httpMethodsAllowed = array();
1048 | foreach ( $this->router as $route ) {
1049 | if ( $route->supportsHttpMethod($httpMethod) ) {
1050 | try {
1051 | $this->applyHook('slim.before.dispatch');
1052 | $dispatched = $route->dispatch();
1053 | $this->applyHook('slim.after.dispatch');
1054 | if ( $dispatched ) {
1055 | break;
1056 | }
1057 | } catch ( Slim_Exception_Pass $e ) {
1058 | continue;
1059 | }
1060 | } else {
1061 | $httpMethodsAllowed = array_merge($httpMethodsAllowed, $route->getHttpMethods());
1062 | }
1063 | }
1064 | if ( !$dispatched ) {
1065 | if ( $httpMethodsAllowed ) {
1066 | $this->response()->header('Allow', implode(' ', $httpMethodsAllowed));
1067 | $this->halt(405);
1068 | } else {
1069 | $this->notFound();
1070 | }
1071 | }
1072 | $this->response()->write(ob_get_clean());
1073 | $this->applyHook('slim.after.router');
1074 | $this->view->getData('flash')->save();
1075 | session_write_close();
1076 | $this->response->send();
1077 | $this->applyHook('slim.after');
1078 | } catch ( Slim_Exception_RequestSlash $e ) {
1079 | $this->redirect($this->request->getRootUri() . $this->request->getResourceUri() . '/', 301);
1080 | } catch ( Exception $e ) {
1081 | if ( $e instanceof Slim_Exception_Stop ) throw $e;
1082 | $this->getLog()->error($e);
1083 | if ( $this->config('debug') === true ) {
1084 | $this->halt(500, self::generateErrorMarkup($e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString()));
1085 | } else {
1086 | $this->error($e);
1087 | }
1088 | }
1089 | } catch ( Slim_Exception_Stop $e ) {
1090 | //Exit application context
1091 | }
1092 | }
1093 |
1094 | /***** EXCEPTION AND ERROR HANDLING *****/
1095 |
1096 | /**
1097 | * Handle errors
1098 | *
1099 | * This is the global Error handler that will catch reportable Errors
1100 | * and convert them into ErrorExceptions that are caught and handled
1101 | * by each Slim application.
1102 | *
1103 | * @param int $errno The numeric type of the Error
1104 | * @param string $errstr The error message
1105 | * @param string $errfile The absolute path to the affected file
1106 | * @param int $errline The line number of the error in the affected file
1107 | * @return true
1108 | * @throws ErrorException
1109 | */
1110 | public static function handleErrors( $errno, $errstr = '', $errfile = '', $errline = '' ) {
1111 | if ( error_reporting() & $errno ) {
1112 | throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
1113 | }
1114 | return true;
1115 | }
1116 |
1117 | /**
1118 | * Generate markup for error message
1119 | *
1120 | * This method accepts details about an error or exception and
1121 | * generates HTML markup for the 500 response body that will
1122 | * be sent to the client.
1123 | *
1124 | * @param string $message The error message
1125 | * @param string $file The absolute file path to the affected file
1126 | * @param int $line The line number in the affected file
1127 | * @param string $trace A stack trace of the error
1128 | * @return string
1129 | */
1130 | protected static function generateErrorMarkup( $message, $file = '', $line = '', $trace = '' ) {
1131 | $body = 'The application could not run because of the following error:
';
1132 | $body .= "Details:
Message: $message
";
1133 | if ( $file !== '' ) $body .= "File: $file
";
1134 | if ( $line !== '' ) $body .= "Line: $line
";
1135 | if ( $trace !== '' ) $body .= 'Stack Trace:
' . nl2br($trace);
1136 | return self::generateTemplateMarkup('Slim Application Error', $body);
1137 | }
1138 |
1139 | /**
1140 | * Generate default template markup
1141 | *
1142 | * This method accepts a title and body content to generate
1143 | * an HTML page. This is primarily used to generate the layout markup
1144 | * for Error handlers and Not Found handlers.
1145 | *
1146 | * @param string $title The title of the HTML template
1147 | * @param string $body The body content of the HTML template
1148 | * @return string
1149 | */
1150 | protected static function generateTemplateMarkup( $title, $body ) {
1151 | $html = "$title";
1152 | $html .= "$title
";
1153 | $html .= $body;
1154 | $html .= '';
1155 | return $html;
1156 | }
1157 |
1158 | /**
1159 | * Default Not Found handler
1160 | * @return void
1161 | */
1162 | protected function defaultNotFound() {
1163 | echo self::generateTemplateMarkup('404 Page Not Found', 'The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.
Visit the Home Page');
1164 | }
1165 |
1166 | /**
1167 | * Default Error handler
1168 | * @return void
1169 | */
1170 | protected function defaultError() {
1171 | echo self::generateTemplateMarkup('Error', 'A website error has occured. The website administrator has been notified of the issue. Sorry for the temporary inconvenience.
');
1172 | }
1173 |
1174 | }
--------------------------------------------------------------------------------