initial commit

This commit is contained in:
Colin Mitchell 2012-04-13 19:47:29 -04:00
commit a6edee97b7
161 changed files with 25053 additions and 0 deletions

11
.htaccess Normal file
View File

@ -0,0 +1,11 @@
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^ index.php [QSA,L]
RewriteRule (.*) index.php?x=$1 [QSA,L]

64
GopherGetter.php Normal file
View File

@ -0,0 +1,64 @@
<?php
require 'JG_Cache.php';
class GopherGetter {
public $uri;
public $host;
public $port;
public $path;
function __construct($u) {
$this->uri = "gopher:/$u";
// split host and port from uri
$data = parse_url($this->uri);
$this->host = $data['host'];
$this->port = array_key_exists('port', $data) ? $data['port'] : 70;
// strip the leading slash from the path
if ( array_key_exists('path', $data) ) {
$this->path = ltrim($data['path'], '/');
}
else {
$this->path = "/";
}
}
function isValid() {
return isSet($this->host) && isSet($this->port) && isSet($this->path);
}
function get() {
$cache = new JG_Cache('/tmp'); //Make sure it exists and is writeable
$this->result = "";
$this->errstr = "";
$this->errno = "";
$this->result = $cache->get('key', 1000000);
if ( $this->result === FALSE ) {
// echo $path;
$fp = stream_socket_client("tcp://$this->host:$this->port", $this->errno, $this->errstr, 30);
if (!$fp) {
return FALSE;
}
else {
fwrite($fp, "$this->path\r\n");
while (!feof($fp)) {
$this->result .= fgets($fp, 1024);
}
fclose($fp);
}
$cache->set($this->uri, $this->result);
}
return TRUE;
}
};
?>

105
JG_Cache.php Normal file
View File

@ -0,0 +1,105 @@
<?php
/*
For explanation and usage, see:
http://www.jongales.com/blog/2009/02/18/simple-file-based-php-cache-class/
*/
class JG_Cache {
function __construct($dir)
{
$this->dir = $dir;
}
private function _name($key)
{
return sprintf("%s/%s", $this->dir, sha1($key));
}
public function get($key, $expiration = 3600)
{
if ( !is_dir($this->dir) OR !is_writable($this->dir))
{
return FALSE;
}
$cache_path = $this->_name($key);
if (!@file_exists($cache_path))
{
return FALSE;
}
if (filemtime($cache_path) < (time() - $expiration))
{
$this->clear($key);
return FALSE;
}
if (!$fp = @fopen($cache_path, 'rb'))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = '';
if (filesize($cache_path) > 0)
{
$cache = unserialize(fread($fp, filesize($cache_path)));
}
else
{
$cache = NULL;
}
flock($fp, LOCK_UN);
fclose($fp);
return $cache;
}
public function set($key, $data)
{
if ( !is_dir($this->dir) OR !is_writable($this->dir))
{
return FALSE;
}
$cache_path = $this->_name($key);
if ( ! $fp = fopen($cache_path, 'wb'))
{
return FALSE;
}
if (flock($fp, LOCK_EX))
{
fwrite($fp, serialize($data));
flock($fp, LOCK_UN);
}
else
{
return FALSE;
}
fclose($fp);
@chmod($cache_path, 0777);
return TRUE;
}
public function clear($key)
{
$cache_path = $this->_name($key);
if (file_exists($cache_path))
{
unlink($cache_path);
return TRUE;
}
return FALSE;
}
}

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2011 Josh Lockhart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

0
README Normal file
View File

163
README.markdown Normal file
View File

@ -0,0 +1,163 @@
# Slim Framework for PHP 5
Slim is a micro framework for PHP 5 that helps you quickly write simple yet powerful RESTful web applications and APIs. Slim is easy to use for both beginners and professionals. Slim favors cleanliness over terseness and common cases over edge cases. Its interface is simple, intuitive, and extensively documented — both online and in the code itself. Thank you for choosing Slim for your next project. I think you're going to love it.
## Features
* Clean and simple [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) for writing powerful web applications
* HTTP routing
* Supports all standard and custom HTTP request methods
* Route parameters and conditions
* Route redirects
* Route passing
* Route halting
* Route middleware
* Named routes and `urlFor()` helper
* Easy configuration
* Easy templating with custom Views (e.g. Twig, Mustache, Smarty)
* Flash messaging
* Signed cookies with AES-256 encryption
* HTTP caching (ETag and Last-Modified)
* Logging
* Error handling
* Custom Not Found handler
* Custom Error handler
* Debugging
* Built upon the Rack protocol
* Extensible middleware and hook architecture
* Supports PHP >= 5.2.0
## "Hello World" application (PHP >= 5.3)
The Slim Framework for PHP 5 supports anonymous functions. This is the preferred method to define Slim application routes. This example assumes you have setup URL rewriting with your web server (see below).
```php
<?php
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name!";
});
$app->run();
```
## "Hello World" application (PHP < 5.3)
If you are running PHP < 5.3, the second argument to the application's `get()` instance method is the name of a callable function instead of an anonymous function. This example assumes you have setup URL rewriting with your web server (see below).
```php
<?php
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/hello/:name', 'hello');
function hello($name) {
echo "Hello, $name!";
}
$app->run();
```
## Get Started
### Install Slim
Download the Slim Framework for PHP 5 and unzip the downloaded file into your virtual host's public directory. Slim will work in a sub-directory, too.
### Setup your webserver
#### Apache
Ensure the `.htaccess` and `index.php` files are in the same public-accessible directory. The `.htaccess` file should contain this code:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
#### Nginx
Your nginx configuration file should contain this code (along with other settings you may need) in your `location` block:
if (!-f $request_filename) {
rewrite ^ /index.php last;
}
This assumes that Slim's `index.php` is in the root folder of your project (www root).
#### lighttpd ####
Your lighttpd configuration file should contain this code (along with other settings you may need). This code requires lighttpd >= 1.4.24.
url.rewrite-if-not-file = ("^" => "/index.php")
This assumes that Slim's `index.php` is in the root folder of your project (www root).
### Build Your Application
Your Slim application will be defined in `index.php`. First, `require` the Slim Framework:
```php
require 'Slim/Slim.php';
```
Next, initialize the Slim application:
```php
$app = new Slim();
```
Next, define your application's routes:
```php
$app->get('/hello/:name', function ($name) {
echo "Hello $name";
});
```
Finally, run your Slim application:
```php
$app->run();
```
For more information about building an application with the Slim Framework, refer to the [official documentation](http://github.com/codeguy/Slim/wiki/Slim-Framework-Documentation).
## Documentation
* [Stable Branch Documentation](http://www.slimframework.com/documentation/stable)
* [Development Branch Documentation](http://www.slimframework.com/documentation/develop)
## Community
### Forum
Visit Slim's official forum and knowledge base at <http://help.slimframework.com> where you can find announcements, chat with fellow Slim users, ask questions, help others, or show off your cool Slim Framework apps.
### Twitter
Follow [@slimphp](http://www.twitter.com/slimphp) on Twitter to receive the very latest news and updates about the framework.
### IRC
You can find me, Josh Lockhart, hanging out in the ##slim chat room during the day. Feel free to say hi, ask questions, or just hang out. If you're on a Mac, check out Colloquy; if you're on a PC, check out mIRC; if you're on Linux, I'm sure you already know what you're doing.
## Resources
Additional resources (ie. custom Views and plugins) are available online in a separate repository.
<https://github.com/codeguy/Slim-Extras>
Here are more links that may also be useful.
* Road Map: <http://github.com/codeguy/Slim/wiki/Road-Map>
* Source Code: <http://github.com/codeguy/Slim/>
## About the Author
Slim is created and maintained by Josh Lockhart, a web developer by day at [New Media Campaigns](http://www.newmediacampaigns.com), and a [hacker by night](http://github.com/codeguy).
Slim is in active development, and test coverage is continually improving.
## Open Source License
Slim is released under the MIT public license.
<http://www.slimframework.com/license>

225
Slim/Environment.php Normal file
View File

@ -0,0 +1,225 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Environment
*
* This class creates and returns a key/value array of common
* environment variables for the current HTTP request.
*
* This is a singleton class; derived environment variables will
* be common across multiple Slim applications.
*
* This class matches the Rack (Ruby) specification as closely
* as possible. More information available below.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Environment implements ArrayAccess, IteratorAggregate {
/**
* @var array
*/
protected $properties;
/**
* @var Slim_Environment
*/
protected static $environment;
/**
* Get environment instance (singleton)
*
* This creates and/or returns an Environment instance (singleton)
* derived from $_SERVER variables. You may override the global server
* variables by using `Environment::mock()` instead.
*
* @param bool $refresh Refresh properties using global server variables?
* @return Slim_Environment
*/
public static function getInstance( $refresh = false ) {
if ( is_null(self::$environment) || $refresh ) {
self::$environment = new self();
}
return self::$environment;
}
/**
* Get mock environment instance
*
* @param array $userSettings
* @return Environment
*/
public static function mock( $userSettings = array() ) {
self::$environment = new self(array_merge(array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '',
'PATH_INFO' => '',
'QUERY_STRING' => '',
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
'ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'USER_AGENT' => 'Slim Framework',
'REMOTE_ADDR' => '127.0.0.1',
'slim.url_scheme' => 'http',
'slim.input' => '',
'slim.errors' => @fopen('php://stderr', 'w')
), $userSettings));
return self::$environment;
}
/**
* Constructor (private access)
*
* @param array|null $settings If present, these are used instead of global server variables
* @return void
*/
private function __construct( $settings = null ) {
if ( $settings ) {
$this->properties = $settings;
} else {
$env = array();
//The HTTP request method
$env['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD'];
//The IP
$env['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
/**
* Application paths
*
* This derives two paths: SCRIPT_NAME and PATH_INFO. The SCRIPT_NAME
* is the real, physical path to the application, be it in the root
* directory or a subdirectory of the public document root. The PATH_INFO is the
* virtual path to the requested resource within the application context.
*
* With htaccess, the SCRIPT_NAME will be an absolute path (without file name);
* if not using htaccess, it will also include the file name. If it is "/",
* it is set to an empty string (since it cannot have a trailing slash).
*
* The PATH_INFO will be an absolute path with a leading slash; this will be
* used for application routing.
*/
if ( strpos($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']) === 0 ) {
$env['SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME']; //Without URL rewrite
} else {
$env['SCRIPT_NAME'] = pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME); //With URL rewrite
}
$env['PATH_INFO'] = substr_replace($_SERVER['REQUEST_URI'], '', 0, strlen($env['SCRIPT_NAME']));
if ( strpos($env['PATH_INFO'], '?') !== false ) {
$env['PATH_INFO'] = substr_replace($env['PATH_INFO'], '', strpos($env['PATH_INFO'], '?')); //query string is not removed automatically
}
$env['SCRIPT_NAME'] = rtrim($env['SCRIPT_NAME'], '/');
$env['PATH_INFO'] = '/' . ltrim($env['PATH_INFO'], '/');
//The portion of the request URI following the '?'
$env['QUERY_STRING'] = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
//Name of server host that is running the script
$env['SERVER_NAME'] = $_SERVER['SERVER_NAME'];
//Number of server port that is running the script
$env['SERVER_PORT'] = $_SERVER['SERVER_PORT'];
//HTTP request headers
$specialHeaders = array('CONTENT_TYPE', 'CONTENT_LENGTH', 'PHP_AUTH_USER', 'PHP_AUTH_PW', 'PHP_AUTH_DIGEST', 'AUTH_TYPE');
foreach ( $_SERVER as $key => $value ) {
if ( strpos($key, 'HTTP_') === 0 ) {
$env[substr($key, 5)] = $value;
} else if ( strpos($key, 'X_') === 0 || in_array($key, $specialHeaders) ) {
$env[$key] = $value;
}
}
//Is the application running under HTTPS or HTTP protocol?
$env['slim.url_scheme'] = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https';
//Input stream (readable one time only; not available for mutipart/form-data requests)
$rawInput = @file_get_contents('php://input');
if ( !$rawInput ) {
$rawInput = '';
}
$env['slim.input'] = $rawInput;
//Error stream
$env['slim.errors'] = fopen('php://stderr', 'w');
$this->properties = $env;
}
}
/**
* Array Access: Offset Exists
*/
public function offsetExists( $offset ) {
return isset($this->properties[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet( $offset ) {
if ( isset($this->properties[$offset]) ) {
return $this->properties[$offset];
} else {
return null;
}
}
/**
* Array Access: Offset Set
*/
public function offsetSet( $offset, $value ) {
$this->properties[$offset] = $value;
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset( $offset ) {
unset($this->properties[$offset]);
}
/**
* IteratorAggregate
*
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->properties);
}
}

46
Slim/Exception/Pass.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Pass Exception
*
* This Exception will cause the Router::dispatch method
* to skip the current matching route and continue to the next
* matching route. If no subsequent routes are found, a
* HTTP 404 Not Found response will be sent to the client.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Exception_Pass extends Exception {}

View File

@ -0,0 +1,47 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Request Slash Exception
*
* This Exception is thrown when Slim detects a matching route
* (defined with a trailing slash) and the HTTP request
* matches the route but does not have a trailing slash. This
* exception will be caught in `Slim::run` and trigger a 301 redirect
* to the same resource URI with a trailing slash.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Exception_RequestSlash extends Exception {}

44
Slim/Exception/Stop.php Normal file
View File

@ -0,0 +1,44 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Stop Exception
*
* This Exception is thrown when the Slim application needs to abort
* processing and return control flow to the outer PHP script.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Exception_Stop extends Exception {}

167
Slim/Http/Headers.php Normal file
View File

@ -0,0 +1,167 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* HTTP Headers
*
* This class is an abstraction of the HTTP response headers and
* provides array access to the header list while automatically
* stores and retrieves headers with lowercase canonical keys regardless
* of the input format.
*
* This class also implements the `Iterator` and `Countable`
* interfaces for even more convenient usage.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Http_Headers implements ArrayAccess, Iterator, Countable {
/**
* @var array HTTP headers
*/
protected $headers;
/**
* @var array Map canonical header name to original header name
*/
protected $map;
/**
* Constructor
* @param array $headers
* @return void
*/
public function __construct( $headers = array() ) {
$this->merge($headers);
}
/**
* Merge Headers
* @param array $headers
* @return void
*/
public function merge( $headers ) {
foreach ( $headers as $name => $value ) {
$this[$name] = $value;
}
}
/**
* Transform header name into canonical form
* @param string $name
* @return string
*/
protected function canonical( $name ) {
return strtolower(trim($name));
}
/**
* Array Access: Offset Exists
*/
public function offsetExists( $offset ) {
return isset($this->headers[$this->canonical($offset)]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet( $offset ) {
$canonical = $this->canonical($offset);
if ( isset($this->headers[$canonical]) ) {
return $this->headers[$canonical];
} else {
return null;
}
}
/**
* Array Access: Offset Set
*/
public function offsetSet( $offset, $value ) {
$canonical = $this->canonical($offset);
$this->headers[$canonical] = $value;
$this->map[$canonical] = $offset;
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset( $offset ) {
$canonical = $this->canonical($offset);
unset($this->headers[$canonical], $this->map[$canonical]);
}
/**
* Countable: Count
*/
public function count() {
return count($this->headers);
}
/**
* Iterator: Rewind
*/
public function rewind() {
reset($this->headers);
}
/**
* Iterator: Current
*/
public function current() {
return current($this->headers);
}
/**
* Iterator: Key
*/
public function key() {
$key = key($this->headers);
return $this->map[$key];
}
/**
* Iterator: Next
*/
public function next() {
return next($this->headers);
}
/**
* Iterator: Valid
*/
public function valid() {
return current($this->headers) !== false;
}
}

517
Slim/Http/Request.php Normal file
View File

@ -0,0 +1,517 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Slim HTTP Request
*
* This class provides a human-friendly interface to the Slim environment variables;
* environment variables are passed by reference and will be modified directly.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Http_Request {
const METHOD_HEAD = 'HEAD';
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
const METHOD_DELETE = 'DELETE';
const METHOD_OPTIONS = 'OPTIONS';
const METHOD_OVERRIDE = '_METHOD';
/**
* @var array
*/
protected static $formDataMediaTypes = array('application/x-www-form-urlencoded');
/**
* @var array
*/
protected $env;
/**
* Constructor
* @param array $env
* @see Slim_Environment
*/
public function __construct( $env ) {
$this->env = $env;
}
/**
* Get HTTP method
* @return string
*/
public function getMethod() {
return $this->env['REQUEST_METHOD'];
}
/**
* Is this a GET request?
* @return bool
*/
public function isGet() {
return $this->getMethod() === self::METHOD_GET;
}
/**
* Is this a POST request?
* @return bool
*/
public function isPost() {
return $this->getMethod() === self::METHOD_POST;
}
/**
* Is this a PUT request?
* @return bool
*/
public function isPut() {
return $this->getMethod() === self::METHOD_PUT;
}
/**
* Is this a DELETE request?
* @return bool
*/
public function isDelete() {
return $this->getMethod() === self::METHOD_DELETE;
}
/**
* Is this a HEAD request?
* @return bool
*/
public function isHead() {
return $this->getMethod() === self::METHOD_HEAD;
}
/**
* Is this a OPTIONS request?
* @return bool
*/
public function isOptions() {
return $this->getMethod() === self::METHOD_OPTIONS;
}
/**
* Is this an AJAX request?
* @return bool
*/
public function isAjax() {
if ( $this->params('isajax') ) {
return true;
} else if ( isset($this->env['X_REQUESTED_WITH']) && $this->env['X_REQUESTED_WITH'] === 'XMLHttpRequest' ) {
return true;
} else {
return false;
}
}
/**
* Is this an XHR request? (alias of Slim_Http_Request::isAjax)
* @return bool
*/
public function isXhr() {
return $this->isAjax();
}
/**
* Fetch GET and POST data
*
* This method returns a union of GET and POST data as a key-value array, or the value
* of the array key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|mixed|null
*/
public function params( $key = null ) {
$union = array_merge($this->get(), $this->post());
if ( $key ) {
if ( isset($union[$key]) ) {
return $union[$key];
} else {
return null;
}
} else {
return $union;
}
}
/**
* Fetch GET data
*
* This method returns a key-value array of data sent in the HTTP request query string, or
* the value of the array key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|mixed|null
*/
public function get( $key = null ) {
if ( !isset($this->env['slim.request.query_hash']) ) {
$output = array();
if ( function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte']) ) {
mb_parse_str($this->env['QUERY_STRING'], $output);
} else {
parse_str($this->env['QUERY_STRING'], $output);
}
$this->env['slim.request.query_hash'] = Slim_Http_Util::stripSlashesIfMagicQuotes($output);
}
if ( $key ) {
if ( isset($this->env['slim.request.query_hash'][$key]) ) {
return $this->env['slim.request.query_hash'][$key];
} else {
return null;
}
} else {
return $this->env['slim.request.query_hash'];
}
}
/**
* Fetch POST data
*
* This method returns a key-value array of data sent in the HTTP request body, or
* the value of a hash key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|mixed|null
* @throws RuntimeException If environment input is not available
*/
public function post( $key = null ) {
if ( !isset($this->env['slim.input']) ) {
throw new RuntimeException('Missing slim.input in environment variables');
}
if ( !isset($this->env['slim.request.form_hash']) ) {
$this->env['slim.request.form_hash'] = array();
if ( $this->isFormData() ) {
$output = array();
if ( function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte']) ) {
mb_parse_str($this->env['slim.input'], $output);
} else {
parse_str($this->env['slim.input'], $output);
}
$this->env['slim.request.form_hash'] = Slim_Http_Util::stripSlashesIfMagicQuotes($output);
}
}
if ( $key ) {
if ( isset($this->env['slim.request.form_hash'][$key]) ) {
return $this->env['slim.request.form_hash'][$key];
} else {
return null;
}
} else {
return $this->env['slim.request.form_hash'];
}
}
/**
* Fetch PUT data (alias for Slim_Http_Request::post)
* @param string $key
* @return array|mixed|null
*/
public function put( $key = null ) {
return $this->post($key);
}
/**
* Fetch COOKIE data
*
* This method returns a key-value array of Cookie data sent in the HTTP request, or
* the value of a array key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @return array|string|null
*/
public function cookies( $key = null ) {
if ( !isset($this->env['slim.request.cookie_hash']) ) {
$cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : '';
$this->env['slim.request.cookie_hash'] = Slim_Http_Util::parseCookieHeader($cookieHeader);
}
if ( $key ) {
if ( isset($this->env['slim.request.cookie_hash'][$key]) ) {
return $this->env['slim.request.cookie_hash'][$key];
} else {
return null;
}
} else {
return $this->env['slim.request.cookie_hash'];
}
}
/**
* Does the Request body contain parseable form data?
* @return bool
*/
public function isFormData() {
$method = isset($this->env['slim.method_override.original_method']) ? $this->env['slim.method_override.original_method'] : $this->getMethod();
return ( $method === self::METHOD_POST && is_null($this->getContentType()) ) || in_array($this->getMediaType(), self::$formDataMediaTypes);
}
/**
* Get Headers
*
* This method returns a key-value array of headers sent in the HTTP request, or
* the value of a hash key if requested; if the array key does not exist, NULL is returned.
*
* @param string $key
* @param mixed $default The default value returned if the requested header is not available
* @return mixed
*/
public function headers( $key = null, $default = null ) {
if ( $key ) {
$key = strtoupper($key);
$key = str_replace('-', '_', $key);
$key = preg_replace('@^HTTP_@', '', $key);
if ( isset($this->env[$key]) ) {
return $this->env[$key];
} else {
return $default;
}
} else {
$headers = array();
foreach ( $this->env as $key => $value ) {
if ( strpos($key, 'slim.') !== 0 ) {
$headers[$key] = $value;
}
}
return $headers;
}
}
/**
* Get Body
* @return string
*/
public function getBody() {
return $this->env['slim.input'];
}
/**
* Get Content Type
* @return string
*/
public function getContentType() {
if ( isset($this->env['CONTENT_TYPE']) ) {
return $this->env['CONTENT_TYPE'];
} else {
return null;
}
}
/**
* Get Media Type (type/subtype within Content Type header)
* @return string|null
*/
public function getMediaType() {
$contentType = $this->getContentType();
if ( $contentType ) {
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
return strtolower($contentTypeParts[0]);
} else {
return null;
}
}
/**
* Get Media Type Params
* @return array
*/
public function getMediaTypeParams() {
$contentType = $this->getContentType();
$contentTypeParams = array();
if ( $contentType ) {
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
$contentTypePartsLength = count($contentTypeParts);
for ( $i = 1; $i < $contentTypePartsLength; $i++ ) {
$paramParts = explode('=', $contentTypeParts[$i]);
$contentTypeParams[strtolower($paramParts[0])] = $paramParts[1];
}
}
return $contentTypeParams;
}
/**
* Get Content Charset
* @return string|null
*/
public function getContentCharset() {
$mediaTypeParams = $this->getMediaTypeParams();
if ( isset($mediaTypeParams['charset']) ) {
return $mediaTypeParams['charset'];
} else {
return null;
}
}
/**
* Get Content-Length
* @return int
*/
public function getContentLength() {
if ( isset($this->env['CONTENT_LENGTH']) ) {
return (int)$this->env['CONTENT_LENGTH'];
} else {
return 0;
}
}
/**
* Get Host
* @return string
*/
public function getHost() {
if ( isset($this->env['HOST']) ) {
return $this->env['HOST'];
} else {
return $this->env['SERVER_NAME'];
}
}
/**
* Get Host with Port
* @return string
*/
public function getHostWithPort() {
return sprintf('%s:%s', $this->getHost(), $this->getPort());
}
/**
* Get Port
* @return int
*/
public function getPort() {
return (int)$this->env['SERVER_PORT'];
}
/**
* Get Scheme (https or http)
* @return string
*/
public function getScheme() {
return $this->env['slim.url_scheme'];
}
/**
* Get Script Name (physical path)
* @return string
*/
public function getScriptName() {
return $this->env['SCRIPT_NAME'];
}
/**
* LEGACY: Get Root URI (alias for Slim_Http_Request::getScriptName)
* @return string
*/
public function getRootUri() {
return $this->getScriptName();
}
/**
* Get Path (physical path + virtual path)
* @return string
*/
public function getPath() {
return $this->getScriptName() . $this->getPathInfo();
}
/**
* Get Path Info (virtual path)
* @return string
*/
public function getPathInfo() {
return $this->env['PATH_INFO'];
}
/**
* LEGACY: Get Resource URI (alias for Slim_Http_Request::getPathInfo)
* @return string
*/
public function getResourceUri() {
return $this->getPathInfo();
}
/**
* Get URL (scheme + host [ + port if non-standard ])
* @return string
*/
public function getUrl() {
$url = $this->getScheme() . '://' . $this->getHost();
if ( ( $this->getScheme() === 'https' && $this->getPort() !== 443 ) || ( $this->getScheme() === 'http' && $this->getPort() !== 80 ) ) {
$url .= sprintf(':%s', $this->getPort());
}
return $url;
}
/**
* Get IP
* @return string
*/
public function getIp() {
return $this->env['REMOTE_ADDR'];
}
/**
* Get Referrer
* @return string|null
*/
public function getReferrer() {
if ( isset($this->env['REFERER']) ) {
return $this->env['REFERER'];
} else {
return null;
}
}
/**
* Get Referer (for those who can't spell)
* @return string|null
*/
public function getReferer() {
return $this->getReferrer();
}
/**
* Get User Agent
* @return string|null
*/
public function getUserAgent() {
if ( isset($this->env['USER_AGENT']) ) {
return $this->env['USER_AGENT'];
} else {
return null;
}
}
}

424
Slim/Http/Response.php Normal file
View File

@ -0,0 +1,424 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Response
*
* This is a simple abstraction over top an HTTP response. This
* provides methods to set the HTTP status, the HTTP headers,
* and the HTTP body.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Http_Response implements ArrayAccess, Countable, IteratorAggregate {
/**
* @var int HTTP status code
*/
protected $status;
/**
* @var Slim_Http_Headers List of HTTP response headers
* @see Slim_Http_Headers
*/
protected $header;
/**
* @var string HTTP response body
*/
protected $body;
/**
* @var int Length of HTTP response body
*/
protected $length;
/**
* @var array HTTP response codes and messages
*/
protected static $messages = array(
//Informational 1xx
100 => '100 Continue',
101 => '101 Switching Protocols',
//Successful 2xx
200 => '200 OK',
201 => '201 Created',
202 => '202 Accepted',
203 => '203 Non-Authoritative Information',
204 => '204 No Content',
205 => '205 Reset Content',
206 => '206 Partial Content',
//Redirection 3xx
300 => '300 Multiple Choices',
301 => '301 Moved Permanently',
302 => '302 Found',
303 => '303 See Other',
304 => '304 Not Modified',
305 => '305 Use Proxy',
306 => '306 (Unused)',
307 => '307 Temporary Redirect',
//Client Error 4xx
400 => '400 Bad Request',
401 => '401 Unauthorized',
402 => '402 Payment Required',
403 => '403 Forbidden',
404 => '404 Not Found',
405 => '405 Method Not Allowed',
406 => '406 Not Acceptable',
407 => '407 Proxy Authentication Required',
408 => '408 Request Timeout',
409 => '409 Conflict',
410 => '410 Gone',
411 => '411 Length Required',
412 => '412 Precondition Failed',
413 => '413 Request Entity Too Large',
414 => '414 Request-URI Too Long',
415 => '415 Unsupported Media Type',
416 => '416 Requested Range Not Satisfiable',
417 => '417 Expectation Failed',
422 => '422 Unprocessable Entity',
423 => '423 Locked',
//Server Error 5xx
500 => '500 Internal Server Error',
501 => '501 Not Implemented',
502 => '502 Bad Gateway',
503 => '503 Service Unavailable',
504 => '504 Gateway Timeout',
505 => '505 HTTP Version Not Supported'
);
/**
* Constructor
* @param string $body The HTTP response body
* @param int $status The HTTP response status
* @param Slim_Http_Headers|array $header The HTTP response headers
*/
public function __construct( $body = '', $status = 200, $header = array() ) {
$this->status = (int)$status;
$headers = array();
foreach ( $header as $key => $value ) {
$headers[$key] = $value;
}
$this->header = new Slim_Http_Headers(array_merge(array('Content-Type' => 'text/html'), $headers));
$this->body = '';
$this->write($body);
}
/**
* Get and set status
* @param int|null $status
* @return int
*/
public function status( $status = null ) {
if ( !is_null($status) ) {
$this->status = (int)$status;
}
return $this->status;
}
/**
* Get and set header
* @param string $name Header name
* @param string|null $value Header value
* @return string Header value
*/
public function header( $name, $value = null ) {
if ( !is_null($value) ) {
$this[$name] = $value;
}
return $this[$name];
}
/**
* Get headers
* @return Slim_Http_Headers
*/
public function headers() {
return $this->header;
}
/**
* Get and set body
* @param string|null $body Content of HTTP response body
* @return string
*/
public function body( $body = null ) {
if ( !is_null($body) ) {
$this->write($body, true);
}
return $this->body;
}
/**
* Get and set length
* @param int|null $length
* @return int
*/
public function length( $length = null ) {
if ( !is_null($length) ) {
$this->length = (int)$length;
}
return $this->length;
}
/**
* Append HTTP response body
* @param string $body Content to append to the current HTTP response body
* @param bool $replace Overwrite existing response body?
* @return string The updated HTTP response body
*/
public function write( $body, $replace = false ) {
if ( $replace ) {
$this->body = $body;
} else {
$this->body .= (string)$body;
}
$this->length = strlen($this->body);
return $this->body;
}
/**
* Finalize
*
* This prepares this response and returns an array
* of [status, headers, body]. This array is passed to outer middleware
* if available or directly to the Slim run method.
*
* @return array[int status, array headers, string body]
*/
public function finalize() {
if ( in_array($this->status, array(204, 304)) ) {
unset($this['Content-Type'], $this['Content-Length']);
return array($this->status, $this->header, '');
} else {
return array($this->status, $this->header, $this->body);
}
}
/**
* Set cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
* header on its own and delegates this responsibility to the `Slim_Http_Util` class. This
* response's header is passed by reference to the utility class and is directly modified. By not
* relying on PHP's native implementation, Slim allows middleware the opportunity to massage or
* analyze the raw header before the response is ultimately delivered to the HTTP client.
*
* @param string $name The name of the cookie
* @param string|array $value If string, the value of cookie; if array, properties for
* cookie including: value, expire, path, domain, secure, httponly
*/
public function setCookie( $name, $value ) {
Slim_Http_Util::setCookieHeader($this->header, $name, $value);
}
/**
* Delete cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
* header on its own and delegates this responsibility to the `Slim_Http_Util` class. This
* response's header is passed by reference to the utility class and is directly modified. By not
* relying on PHP's native implementation, Slim allows middleware the opportunity to massage or
* analyze the raw header before the response is ultimately delivered to the HTTP client.
*
* This method will set a cookie with the given name that has an expiration time in the past; this will
* prompt the HTTP client to invalidate and remove the client-side cookie. Optionally, you may
* also pass a key/value array as the second argument. If the "domain" key is present in this
* array, only the Cookie with the given name AND domain will be removed. The invalidating cookie
* sent with this response will adopt all properties of the second argument.
*
* @param string $name The name of the cookie
* @param array $value Properties for cookie including: value, expire, path, domain, secure, httponly
*/
public function deleteCookie( $name, $value = array() ) {
Slim_Http_Util::deleteCookieHeader($this->header, $name, $value);
}
/**
* Redirect
*
* This method prepares this response to return an HTTP Redirect response
* to the HTTP client.
*
* @param string $url The redirect destination
* @param int $status The redirect HTTP status code
*/
public function redirect ( $url, $status = 302 ) {
$this->status = $status;
$this['Location'] = $url;
}
/**
* Helpers: Empty?
* @return bool
*/
public function isEmpty() {
return in_array($this->status, array(201, 204, 304));
}
/**
* Helpers: Informational?
* @return bool
*/
public function isInformational() {
return $this->status >= 100 && $this->status < 200;
}
/**
* Helpers: OK?
* @return bool
*/
public function isOk() {
return $this->status === 200;
}
/**
* Helpers: Successful?
* @return bool
*/
public function isSuccessful() {
return $this->status >= 200 && $this->status < 300;
}
/**
* Helpers: Redirect?
* @return bool
*/
public function isRedirect() {
return in_array($this->status, array(301, 302, 303, 307));
}
/**
* Helpers: Redirection?
* @return bool
*/
public function isRedirection() {
return $this->status >= 300 && $this->status < 400;
}
/**
* Helpers: Forbidden?
* @return bool
*/
public function isForbidden() {
return $this->status === 403;
}
/**
* Helpers: Not Found?
* @return bool
*/
public function isNotFound() {
return $this->status === 404;
}
/**
* Helpers: Client error?
* @return bool
*/
public function isClientError() {
return $this->status >= 400 && $this->status < 500;
}
/**
* Helpers: Server Error?
* @return bool
*/
public function isServerError() {
return $this->status >= 500 && $this->status < 600;
}
/**
* Array Access: Offset Exists
*/
public function offsetExists( $offset ) {
return isset($this->header[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet( $offset ) {
if ( isset($this->header[$offset]) ) {
return $this->header[$offset];
} else {
return null;
}
}
/**
* Array Access: Offset Set
*/
public function offsetSet( $offset, $value ) {
$this->header[$offset] = $value;
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset( $offset ) {
unset($this->header[$offset]);
}
/**
* Countable: Count
*/
public function count() {
return count($this->header);
}
/**
* Get Iterator
*
* This returns the contained `Slim_Http_Headers` instance which
* is itself iterable.
*
* @return Slim_Http_Headers
*/
public function getIterator() {
return $this->header;
}
/**
* Get message for HTTP status code
* @return string|null
*/
public static function getMessageForCode( $status ) {
if ( isset(self::$messages[$status]) ) {
return self::$messages[$status];
} else {
return null;
}
}
}

110
Slim/Http/Stream.php Normal file
View File

@ -0,0 +1,110 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Slim HTTP Stream
*
* This class substitutes for `Slim_Http_Response` when
* `streamFile()`, `streamData()`, or `streamProcess()` is
* invoked. At which time, the Slim app's response property
* is set to an instance of `Slim_Http_Stream`.
*
* This class implements a `finalize()` and `write()` method
* just like `Slim_Http_Response` (polymorphism) so that the framework's
* expectations are still met.
*
* In the Slim app's `run()` method, if it encounters a response body
* that is not a string, the response body object's `process()` method
* is invoked; otherwise, Slim will `echo()` the string response body.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Http_Stream {
/**
* @var mixed This is a Slim_Stream_* instance that performs the actual streaming
*/
protected $streamer;
/**
* @var array
*/
protected $options;
/**
* Constructor
* @param mixed $streamer
* @param array $options
* @return void
*/
public function __construct( $streamer, $options ) {
$this->streamer = $streamer;
$this->options = array_merge(array(
'name' => 'foo',
'type' => 'application/octet-stream',
'disposition' => 'attachment', //or "inline"
'encoding' => 'binary', //or "ascii"
'allow_cache' => false
), $options);
}
/**
* Finalize
* @return array[status, header, body]
*/
public function finalize() {
$headers = new Slim_Http_Headers();
if ( $this->options['allow_cache'] ) {
$headers['Pragma'] = 'public'; //Used by HTTP/1.0 clients
$headers['Cache-Control'] = 'public';
} else {
$headers['Pragma'] = 'no-cache'; //Used by HTTP/1.0 clients
$headers['Cache-Control'] = 'no-cache';
}
$headers['Content-Type'] = $this->options['type'];
$headers['Content-Disposition'] = sprintf('%s; filename=%s', $this->options['disposition'], $this->options['name']);
$headers['Content-Transfer-Encoding'] = $this->options['encoding'];
return array(200, $headers, $this->streamer);
}
/**
* Write
*
* This is a dummy method to satisfy the framework's expectations. In the future
* some refactoring may allow this method to be removed. For now, carry on. Nothing
* to see here folks.
*
* @return void
*/
public function write( $body ) {}
}

364
Slim/Http/Util.php Normal file
View File

@ -0,0 +1,364 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Slim HTTP Utilities
*
* This class provides useful methods for handling HTTP requests.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Http_Util {
/**
* Strip slashes from string or array
*
* This method strips slashes from its input. By default, this method will only
* strip slashes from its input if magic quotes are enabled. Otherwise, you may
* override the magic quotes setting with either TRUE or FALSE as the send argument
* to force this method to strip or not strip slashes from its input.
*
* @var array|string $rawData
* @return array|string
*/
public static function stripSlashesIfMagicQuotes( $rawData, $overrideStripSlashes = null ) {
$strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes;
if ( $strip ) {
return self::_stripSlashes($rawData);
} else {
return $rawData;
}
}
/**
* Strip slashes from string or array
* @param array|string $rawData
* @return array|string
*/
protected static function _stripSlashes( $rawData ) {
return is_array($rawData) ? array_map(array('self', '_stripSlashes'), $rawData) : stripslashes($rawData);
}
/**
* Encrypt data
*
* This method will encrypt data using a given key, vector, and cipher.
* By default, this will encrypt data using the RIJNDAEL/AES 256 bit cipher. You
* may override the default cipher and cipher mode by passing your own desired
* cipher and cipher mode as the final key-value array argument.
*
* @param string $data The unencrypted data
* @param string $key The encryption key
* @param string $iv The encryption initialization vector
* @param array $settings Optional key-value array with custom algorithm and mode
* @return string
*/
public static function encrypt( $data, $key, $iv, $settings = array() ) {
if ( $data === '' || !extension_loaded('mcrypt') ) {
return $data;
}
//Merge settings with defaults
$settings = array_merge(array(
'algorithm' => MCRYPT_RIJNDAEL_256,
'mode' => MCRYPT_MODE_CBC
), $settings);
//Get module
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
//Validate IV
$ivSize = mcrypt_enc_get_iv_size($module);
if ( strlen($iv) > $ivSize ) {
$iv = substr($iv, 0, $ivSize);
}
//Validate key
$keySize = mcrypt_enc_get_key_size($module);
if ( strlen($key) > $keySize ) {
$key = substr($key, 0, $keySize);
}
//Encrypt value
mcrypt_generic_init($module, $key, $iv);
$res = @mcrypt_generic($module, $data);
mcrypt_generic_deinit($module);
return $res;
}
/**
* Decrypt data
*
* This method will decrypt data using a given key, vector, and cipher.
* By default, this will decrypt data using the RIJNDAEL/AES 256 bit cipher. You
* may override the default cipher and cipher mode by passing your own desired
* cipher and cipher mode as the final key-value array argument.
*
* @param string $data The encrypted data
* @param string $key The encryption key
* @param string $iv The encryption initialization vector
* @param array $settings Optional key-value array with custom algorithm and mode
* @return string
*/
public static function decrypt( $data, $key, $iv, $settings = array() ) {
if ( $data === '' || !extension_loaded('mcrypt') ) {
return $data;
}
//Merge settings with defaults
$settings = array_merge(array(
'algorithm' => MCRYPT_RIJNDAEL_256,
'mode' => MCRYPT_MODE_CBC
), $settings);
//Get module
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
//Validate IV
$ivSize = mcrypt_enc_get_iv_size($module);
if ( strlen($iv) > $ivSize ) {
$iv = substr($iv, 0, $ivSize);
}
//Validate key
$keySize = mcrypt_enc_get_key_size($module);
if ( strlen($key) > $keySize ) {
$key = substr($key, 0, $keySize);
}
//Decrypt value
mcrypt_generic_init($module, $key, $iv);
$decryptedData = @mdecrypt_generic($module, $data);
$res = str_replace("\x0", '', $decryptedData);
mcrypt_generic_deinit($module);
return $res;
}
/**
* Encode secure cookie value
*
* This method will create the secure value of an HTTP cookie. The
* cookie value is encrypted and hashed so that its value is
* secure and checked for integrity when read in subsequent requests.
*
* @param string $value The unsecure HTTP cookie value
* @param int $expires The UNIX timestamp at which this cookie will expire
* @param string $secret The secret key used to hash the cookie value
* @param int $algorithm The algorithm to use for encryption
* @param int $mode The algorithm mode to use for encryption
* @param string
*/
public static function encodeSecureCookie( $value, $expires, $secret, $algorithm, $mode ) {
$key = hash_hmac('sha1', $expires, $secret);
$iv = md5($expires);
$secureString = base64_encode(self::encrypt($value, $key, $iv, array(
'algorithm' => $algorithm,
'mode' => $mode
)));
$verificationString = hash_hmac('sha1', $expires . $value, $key);
return implode('|', array($expires, $secureString, $verificationString));
}
/**
* Decode secure cookie value
*
* This method will decode the secure value of an HTTP cookie. The
* cookie value is encrypted and hashed so that its value is
* secure and checked for integrity when read in subsequent requests.
*
* @param string $value The secure HTTP cookie value
* @param int $expires The UNIX timestamp at which this cookie will expire
* @param string $secret The secret key used to hash the cookie value
* @param int $algorithm The algorithm to use for encryption
* @param int $mode The algorithm mode to use for encryption
* @param string
*/
public static function decodeSecureCookie( $value, $secret, $algorithm, $mode ) {
if ( $value ) {
$value = explode('|', $value);
if ( count($value) === 3 && ( (int)$value[0] === 0 || (int)$value[0] > time() ) ) {
$key = hash_hmac('sha1', $value[0], $secret);
$iv = md5($value[0]);
$data = self::decrypt(base64_decode($value[1]), $key, $iv, array(
'algorithm' => $algorithm,
'mode' => $mode
));
$verificationString = hash_hmac('sha1', $value[0] . $data, $key);
if ( $verificationString === $value[2] ) {
return $data;
}
}
}
return false;
}
/**
* Set HTTP cookie header
*
* This method will construct and set the HTTP `Set-Cookie` header. Slim
* uses this method instead of PHP's native `setcookie` method. This allows
* more control of the HTTP header irrespective of the native implementation's
* dependency on PHP versions.
*
* This method accepts the Slim_Http_Headers object by reference as its
* first argument; this method directly modifies this object instead of
* returning a value.
*
* @param array $header
* @param string $name
* @param string $value
* @return void
*/
public static function setCookieHeader( &$header, $name, $value ) {
//Build cookie header
if ( is_array($value) ) {
$domain = '';
$path = '';
$expires = '';
$secure = '';
$httponly = '';
if ( isset($value['domain']) && $value['domain'] ) {
$domain = '; domain=' . $value['domain'];
}
if ( isset($value['path']) && $value['path'] ) {
$path = '; path=' . $value['path'];
}
if ( isset($value['expires']) ) {
if ( is_string($value['expires']) ) {
$timestamp = strtotime($value['expires']);
} else {
$timestamp = (int)$value['expires'];
}
if ( $timestamp !== 0 ) {
$expires = '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);
}
}
if ( isset($value['secure']) && $value['secure'] ) {
$secure = '; secure';
}
if ( isset($value['httponly']) && $value['httponly'] ) {
$httponly = '; HttpOnly';
}
$cookie = sprintf('%s=%s%s', urlencode($name), urlencode((string)$value['value']), $domain . $path . $expires . $secure . $httponly);
} else {
$cookie = sprintf('%s=%s', urlencode($name), urlencode((string)$value));
}
//Set cookie header
if ( !isset($header['Set-Cookie']) || $header['Set-Cookie'] === '' ) {
$header['Set-Cookie'] = $cookie;
} else {
$header['Set-Cookie'] = implode("\n", array($header['Set-Cookie'], $cookie));
}
}
/**
* Delete HTTP cookie header
*
* This method will construct and set the HTTP `Set-Cookie` header to invalidate
* a client-side HTTP cookie. If a cookie with the same name (and, optionally, domain)
* is already set in the HTTP response, it will also be removed. Slim uses this method
* instead of PHP's native `setcookie` method. This allows more control of the HTTP header
* irrespective of PHP's native implementation's dependency on PHP versions.
*
* This method accepts the Slim_Http_Headers object by reference as its
* first argument; this method directly modifies this object instead of
* returning a value.
*
* @param array $header
* @param string $name
* @param string $value
* @return void
*/
public static function deleteCookieHeader( &$header, $name, $value = array() ) {
//Remove affected cookies from current response header
$cookiesOld = array();
$cookiesNew = array();
if ( isset($header['Set-Cookie']) ) {
$cookiesOld = explode("\n", $header['Set-Cookie']);
}
foreach ( $cookiesOld as $c ) {
if ( isset($value['domain']) && $value['domain'] ) {
$regex = sprintf('@%s=.*domain=%s@', urlencode($name), preg_quote($value['domain']));
} else {
$regex = sprintf('@%s=@', urlencode($name));
}
if ( preg_match($regex, $c) === 0 ) {
$cookiesNew[] = $c;
}
}
if ( $cookiesNew ) {
$header['Set-Cookie'] = implode("\n", $cookiesNew);
} else {
unset($header['Set-Cookie']);
}
//Set invalidating cookie to clear client-side cookie
self::setCookieHeader($header, $name, array_merge(array('value' => '', 'path' => null, 'domain' => null, 'expires' => time() - 100), $value));
}
/**
* Parse cookie header
*
* This method will parse the HTTP requst's `Cookie` header
* and extract cookies into an associative array.
*
* @param string
* @return array
*/
public static function parseCookieHeader( $header ) {
$cookies = array();
$header = rtrim($header, "\r\n");
$headerPieces = preg_split('@\s*;\s*@', $header);
foreach ( $headerPieces as $c ) {
$cParts = explode('=', $c);
if ( count($cParts) === 2 ) {
$key = urldecode($cParts[0]);
$value = urldecode($cParts[1]);
if ( isset($cookies[$key]) ) {
if ( is_array($cookies[$key]) ) {
$cookies[$key][] = $value;
} else {
$cookies[$key] = array($cookies[$key], $value);
}
} else {
$cookies[$key] = $value;
}
}
}
return $cookies;
}
}

219
Slim/Log.php Normal file
View File

@ -0,0 +1,219 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Log
*
* This is the primary logger for a Slim application. You may provide
* a Log Writer in conjunction with this Log to write to various output
* destinations (e.g. a file). This class provides this interface:
*
* debug( mixed $object )
* info( mixed $object )
* warn( mixed $object )
* error( mixed $object )
* fatal( mixed $object )
*
* This class assumes only that your Log Writer has a public `write()` method
* that accepts any object as its one and only argument. The Log Writer
* class may write or send its argument anywhere: a file, STDERR,
* a remote web API, etc. The possibilities are endless.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Log {
/**
* @var array
*/
static protected $levels = array(
0 => 'FATAL',
1 => 'ERROR',
2 => 'WARN',
3 => 'INFO',
4 => 'DEBUG'
);
/**
* @var mixed
*/
protected $writer;
/**
* @var bool
*/
protected $enabled;
/**
* @var int
*/
protected $level;
/**
* Constructor
* @param mixed $writer
* @return void
*/
public function __construct( $writer ) {
$this->writer = $writer;
$this->enabled = true;
$this->level = 4;
}
/**
* Is logging enabled?
* @return bool
*/
public function getEnabled() {
return $this->enabled;
}
/**
* Enable or disable logging
* @param bool $enabled
* @return void
*/
public function setEnabled( $enabled ) {
if ( $enabled ) {
$this->enabled = true;
} else {
$this->enabled = false;
}
}
/**
* Set level
* @param int $level
* @return void
* @throws InvalidArgumentException
*/
public function setLevel( $level ) {
if ( !isset(self::$levels[$level]) ) {
throw new InvalidArgumentException('Invalid log level');
}
$this->level = $level;
}
/**
* Get level
* @return int
*/
public function getLevel() {
return $this->level;
}
/**
* Set writer
* @param mixed $writer
* @return void
*/
public function setWriter( $writer ) {
$this->writer = $writer;
}
/**
* Get writer
* @return mixed
*/
public function getWriter() {
return $this->writer;
}
/**
* Is logging enabled?
* @return bool
*/
public function isEnabled() {
return $this->enabled;
}
/**
* Log debug message
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function debug( $object ) {
return $this->log($object, 4);
}
/**
* Log info message
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function info( $object ) {
return $this->log($object, 3);
}
/**
* Log warn message
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function warn( $object ) {
return $this->log($object, 2);
}
/**
* Log error message
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function error( $object ) {
return $this->log($object, 1);
}
/**
* Log fatal message
* @param mixed $object
* @return mixed|false What the Logger returns, or false if Logger not set or not enabled
*/
public function fatal( $object ) {
return $this->log($object, 0);
}
/**
* Log message
* @param mixed The object to log
* @param int The message level
* @return int|false
*/
protected function log( $object, $level ) {
if ( $this->enabled && $this->writer && $level <= $this->level ) {
return $this->writer->write($object);
} else {
return false;
}
}
}

71
Slim/LogFileWriter.php Normal file
View File

@ -0,0 +1,71 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Log File Writer
*
* This class is used by Slim_Log to write log messages to a valid, writable
* resource handle (e.g. a file or STDERR).
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_LogFileWriter {
/**
* @var resource
*/
protected $resource;
/**
* Constructor
* @param resource $resource
* @return void
* @throws InvalidArgumentException
*/
public function __construct( $resource ) {
if ( !is_resource($resource) ) {
throw new InvalidArgumentException('Cannot create LogFileWriter. Invalid resource handle.');
}
$this->resource = $resource;
}
/**
* Write message
* @param mixed $message
* @return int|false
*/
public function write( $message ) {
return fwrite($this->resource, (string)$message . PHP_EOL);
}
}

112
Slim/Middleware.php Normal file
View File

@ -0,0 +1,112 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Middleware
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
abstract class Slim_Middleware {
/**
* @var Slim Reference to the primary Slim application instance
*/
protected $app;
/**
* @var mixed Reference to the next downstream middleware
*/
protected $next;
/**
* Set application
*
* This method injects the primary Slim application instance into
* this middleware.
*
* @param Slim $application
* @return void
*/
final public function setApplication( $application ) {
$this->app = $application;
}
/**
* Get application
*
* This method retrieves the application previously injected
* into this middleware.
*
* @return Slim
*/
final public function getApplication() {
return $this->app;
}
/**
* Set next middleware
*
* This method injects the next downstream middleware into
* this middleware so that it may optionally be called
* when appropriate.
*
* @param Slim|Slim_Middleware
* @return void
*/
final public function setNextMiddleware( $nextMiddleware ) {
$this->next = $nextMiddleware;
}
/**
* Get next middleware
*
* This method retrieves the next downstream middleware
* previously injected into this middleware.
*
* @return Slim|Slim_Middleware
*/
final public function getNextMiddleware() {
return $this->next;
}
/**
* Call
*
* Perform actions specific to this middleware and optionally
* call the next downstream middleware.
*
* @return void
*/
abstract public function call();
}

View File

@ -0,0 +1,157 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Content Types
*
* This is middleware for a Slim application that intercepts
* the HTTP request body and parses it into the appropriate
* PHP data structure if possible; else it returns the HTTP
* request body unchanged. This is particularly useful
* for preparing the HTTP request body for an XML or JSON API.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Middleware_ContentTypes extends Slim_Middleware {
/**
* @var array
*/
protected $contentTypes;
/**
* Constructor
* @param array $settings
*/
public function __construct( $settings = array() ) {
$this->contentTypes = array_merge(array(
'application/json' => array($this, 'parseJson'),
'application/xml' => array($this, 'parseXml'),
'text/xml' => array($this, 'parseXml'),
'text/csv' => array($this, 'parseCsv')
), $settings);
}
/**
* Call
* @return void
*/
public function call() {
$env = $this->app->environment();
if ( isset($env['CONTENT_TYPE']) ) {
$env['slim.input_original'] = $env['slim.input'];
$env['slim.input'] = $this->parse($env['slim.input'], $env['CONTENT_TYPE']);
}
$this->next->call();
}
/**
* Parse input
*
* This method will attempt to parse the request body
* based on its content type if available.
*
* @param string $input
* @param string $contentType
* @return mixed
*/
protected function parse ( $input, $contentType ) {
if ( isset($this->contentTypes[$contentType]) && is_callable($this->contentTypes[$contentType]) ) {
$result = call_user_func($this->contentTypes[$contentType], $input);
if ( $result ) {
return $result;
}
}
return $input;
}
/**
* Parse JSON
*
* This method converts the raw JSON input
* into an associative array.
*
* @param string $input
* @return array|string
*/
protected function parseJson( $input ) {
if ( function_exists('json_decode') ) {
$result = json_decode($input, true);
if ( $result ) {
return $result;
}
}
}
/**
* Parse XML
*
* This method creates a SimpleXMLElement
* based upon the XML input. If the SimpleXML
* extension is not available, the raw input
* will be returned unchanged.
*
* @param string $input
* @return SimpleXMLElement|string
*/
protected function parseXml( $input ) {
if ( class_exists('SimpleXMLElement') ) {
try {
return new SimpleXMLElement($input);
} catch ( Exception $e ) {}
}
return $input;
}
/**
* Parse CSV
*
* This method parses CSV content into a numeric array
* containing an array of data for each CSV line.
*
* @param string $input
* @return array
*/
protected function parseCsv( $input ) {
$temp = fopen('php://memory', 'rw');
fwrite($temp, $input);
fseek($temp, 0);
$res = array();
while ( ($data = fgetcsv($temp)) !== false ) {
$res[] = $data;
}
fclose($temp);
return $res;
}
}

170
Slim/Middleware/Flash.php Normal file
View File

@ -0,0 +1,170 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Flash
*
* This is middleware for a Slim application that enables
* Flash messaging between HTTP requests. This allows you
* set Flash messages for the current request, for the next request,
* or to retain messages from the previous request through to
* the next request.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Middleware_Flash extends Slim_Middleware implements ArrayAccess {
/**
* @var array
*/
protected $settings;
/**
* @var array
*/
protected $messages;
/**
* Constructor
* @param Slim $app
* @param array $settings
* @return void
*/
public function __construct( $settings = array() ) {
$this->settings = array_merge(array('key' => 'slim.flash'), $settings);
$this->messages = array(
'prev' => isset($_SESSION[$this->settings['key']]) ? $_SESSION[$this->settings['key']] : array(), //flash messages from prev request
'next' => array(), //flash messages for next request
'now' => array() //flash messages for current request
);
}
/**
* Call
* @return void
*/
public function call() {
$env = $this->app->environment();
$env['slim.flash'] = $this;
$this->next->call();
$this->save();
}
/**
* Now
*
* Specify a flash message for a given key to be shown for the current request
*
* @param string $key
* @param string $value
* @return void
*/
public function now( $key, $value ) {
$this->messages['now'][(string)$key] = $value;
}
/**
* Set
*
* Specify a flash message for a given key to be shown for the next request
*
* @param string $key
* @param string $value
* @return void
*/
public function set( $key, $value ) {
$this->messages['next'][(string)$key] = $value;
}
/**
* Keep
*
* Retain flash messages from the previous request for the next request
*
* @return void
*/
public function keep() {
foreach ( $this->messages['prev'] as $key => $val ) {
$this->messages['next'][$key] = $val;
}
}
/**
* Save
*/
public function save() {
$_SESSION[$this->settings['key']] = $this->messages['next'];
}
/**
* Get messages
*
* Return array of flash messages to be shown for the current request
*
* @return array
*/
public function getMessages() {
return array_merge($this->messages['prev'], $this->messages['now']);
}
/**
* Array Access: Offset Exists
*/
public function offsetExists( $offset ) {
$messages = $this->getMessages();
return isset($messages[$offset]);
}
/**
* Array Access: Offset Get
*/
public function offsetGet( $offset ) {
$messages = $this->getMessages();
return isset($messages[$offset]) ? $messages[$offset] : null;
}
/**
* Array Access: Offset Set
*/
public function offsetSet( $offset, $value ) {
$this->now($offset, $value);
}
/**
* Array Access: Offset Unset
*/
public function offsetUnset( $offset ) {
unset($this->messages['prev'][$offset], $this->messages['now'][$offset]);
}
}

View File

@ -0,0 +1,93 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* HTTP Method Override
*
* This is middleware for a Slim application that allows traditional
* desktop browsers to submit psuedo PUT and DELETE requests by relying
* on a pre-determined request parameter. Without this middleware,
* desktop browsers are only able to submit GET and POST requests.
*
* This middleware is included automatically!
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Middleware_MethodOverride extends Slim_Middleware {
/**
* @var array
*/
protected $settings;
/**
* Constructor
* @param Slim $app
* @param array $settings
* @return void
*/
public function __construct( $settings = array() ) {
$this->settings = array_merge(array('key' => '_METHOD'), $settings);
}
/**
* Call
*
* Implements Slim middleware interface. This method is invoked and passed
* an array of environemnt variables. This middleware inspects the environment
* variables for the HTTP method override parameter; if found, this middleware
* modifies the environment settings so downstream middleware and/or the Slim
* application will treat the request with the desired HTTP method.
*
* @param array $env
* @return array[status, header, body]
*/
public function call() {
$env = $this->app->environment();
if ( isset($env['X_HTTP_METHOD_OVERRIDE']) ) {
// Header commonly used by Backbone.js and others
$env['slim.method_override.original_method'] = $env['REQUEST_METHOD'];
$env['REQUEST_METHOD'] = strtoupper($env['X_HTTP_METHOD_OVERRIDE']);
} else if ( isset($env['REQUEST_METHOD']) && $env['REQUEST_METHOD'] === 'POST' ) {
// HTML Form Override
$req = new Slim_Http_Request($env);
$method = $req->post($this->settings['key']);
if ( $method ) {
$env['slim.method_override.original_method'] = $env['REQUEST_METHOD'];
$env['REQUEST_METHOD'] = strtoupper($method);
}
}
$this->next->call();
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Pretty Exceptions
*
* This middleware catches any Exception thrown by the surrounded
* application and displays a developer-friendly diagnostic screen.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Middleware_PrettyExceptions extends Slim_Middleware {
/**
* @var array
*/
protected $settings;
/**
* Constructor
* @param Slim|middleware $app
* @param array $settings
*/
public function __construct( $settings = array() ) {
$this->settings = $settings;
}
/**
* Call
* @return void
*/
public function call() {
try {
$this->next->call();
} catch ( Exception $e ) {
$env = $this->app->environment();
$env['slim.log']->error($e);
$this->app->response()->status(500);
$this->app->response()->body($this->renderBody($env, $e));
}
}
/**
* Render response body
* @param array $env
* @param Exception $exception
* @return string
*/
protected function renderBody( &$env, $exception ) {
$title = 'Slim Application Error';
$code = $exception->getCode();
$message = $exception->getMessage();
$file = $exception->getFile();
$line = $exception->getLine();
$trace = $exception->getTraceAsString();
$html = sprintf('<h1>%s</h1>', $title);
$html .= '<p>The application could not run because of the following error:</p>';
$html .= '<h2>Details</h2>';
if ( $code ) {
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
}
if ( $message ) {
$html .= sprintf('<div><strong>Message:</strong> %s</div>', $message);
}
if ( $file ) {
$html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
}
if ( $line ) {
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
}
if ( $trace ) {
$html .= '<h2>Trace</h2>';
$html .= sprintf('<pre>%s</pre>', $trace);
}
return sprintf("<html><head><title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{display:inline-block;width:65px;}</style></head><body>%s</body></html>", $title, $html);
}
}

View File

@ -0,0 +1,143 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Session Cookie
*
* This class provides an HTTP cookie storage mechanism
* for session data. This class avoids using a PHP session
* and instead serializes/unserializes the $_SESSION global
* variable to/from an HTTP cookie.
*
* If a secret key is provided with this middleware, the HTTP
* cookie will be checked for integrity to ensure the client-side
* cookie is not changed.
*
* You should NEVER store sensitive data in a client-side cookie
* in any format, encrypted or not. If you need to store sensitive
* user information in a session, you should rely on PHP's native
* session implementation, or use other middleware to store
* session data in a database or alternative server-side cache.
*
* Because this class stores serialized session data in an HTTP cookie,
* you are inherently limtied to 4 Kb. If you attempt to store
* more than this amount, serialization will fail.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Middleware_SessionCookie extends Slim_Middleware {
/**
* @var array
*/
protected $settings;
/**
* Constructor
*
* @param array $settings
* @return void
*/
public function __construct( $settings = array() ) {
$this->settings = array_merge(array(
'expires' => '20 minutes',
'path' => '/',
'domain' => null,
'secure' => false,
'httponly' => false,
'name' => 'slim_session',
'secret' => 'CHANGE_ME',
'cipher' => MCRYPT_RIJNDAEL_256,
'cipher_mode' => MCRYPT_MODE_CBC
), $settings);
if ( is_string($this->settings['expires']) ) {
$this->settings['expires'] = strtotime($this->settings['expires']);
}
}
/**
* Call
* @return void
*/
public function call() {
$this->loadSession();
$this->next->call();
$this->saveSession();
}
/**
* Load session
* @param array $env
* @return void
*/
protected function loadSession() {
$value = Slim_Http_Util::decodeSecureCookie(
$this->app->request()->cookies($this->settings['name']),
$this->settings['secret'],
$this->settings['cipher'],
$this->settings['cipher_mode']
);
if ( $value ) {
$_SESSION = unserialize($value);
} else {
$_SESSION = array();
}
}
/**
* Save session
* @return void
*/
protected function saveSession() {
$value = Slim_Http_Util::encodeSecureCookie(
serialize($_SESSION),
$this->settings['expires'],
$this->settings['secret'],
$this->settings['cipher'],
$this->settings['cipher_mode']
);
if ( strlen($value) > 4096 ) {
$this->app->getLog()->error('WARNING! Slim_Middleware_SessionCookie data size is larger than 4KB. Content save failed.');
} else {
$this->app->response()->setCookie($this->settings['name'], array(
'value' => $value,
'domain' => $this->settings['domain'],
'path' => $this->settings['path'],
'expires' => $this->settings['expires'],
'secure' => $this->settings['secure'],
'httponly' => $this->settings['httponly']
));
}
}
}

400
Slim/Route.php Normal file
View File

@ -0,0 +1,400 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Route
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Route {
/**
* @var string The route pattern (ie. "/books/:id")
*/
protected $pattern;
/**
* @var mixed The callable associated with this route
*/
protected $callable;
/**
* @var array Conditions for this route's URL parameters
*/
protected $conditions = array();
/**
* @var array Default conditions applied to all Route instances
*/
protected static $defaultConditions = array();
/**
* @var string The name of this route (optional)
*/
protected $name;
/**
* @var array Key-value array of URL parameters
*/
protected $params = array();
/**
* @var array HTTP methods supported by this Route
*/
protected $methods = array();
/**
* @var Slim_Router The Router to which this Route belongs
*/
protected $router;
/**
* @var array[Callable] Middleware
*/
protected $middleware = array();
/**
* Constructor
* @param string $pattern The URL pattern (ie. "/books/:id")
* @param mixed $callable Anything that returns TRUE for is_callable()
*/
public function __construct( $pattern, $callable ) {
$this->setPattern($pattern);
$this->setCallable($callable);
$this->setConditions(self::getDefaultConditions());
}
/**
* Set default route conditions for all instances
* @param array $defaultConditions
* @return void
*/
public static function setDefaultConditions( array $defaultConditions ) {
self::$defaultConditions = $defaultConditions;
}
/**
* Get default route conditions for all instances
* @return array
*/
public static function getDefaultConditions() {
return self::$defaultConditions;
}
/**
* Get route pattern
* @return string
*/
public function getPattern() {
return $this->pattern;
}
/**
* Set route pattern
* @param string $pattern
* @return void
*/
public function setPattern( $pattern ) {
$this->pattern = str_replace(')', ')?', (string)$pattern);
}
/**
* Get route callable
* @return mixed
*/
public function getCallable() {
return $this->callable;
}
/**
* Set route callable
* @param mixed $callable
* @return void
*/
public function setCallable($callable) {
$this->callable = $callable;
}
/**
* Get route conditions
* @return array
*/
public function getConditions() {
return $this->conditions;
}
/**
* Set route conditions
* @param array $conditions
* @return void
*/
public function setConditions( array $conditions ) {
$this->conditions = $conditions;
}
/**
* Get route name
* @return string|null
*/
public function getName() {
return $this->name;
}
/**
* Set route name
* @param string $name
* @return void
*/
public function setName( $name ) {
$this->name = (string)$name;
$this->router->addNamedRoute($this->name, $this);
}
/**
* Get route parameters
* @return array
*/
public function getParams() {
return $this->params;
}
/**
* Add supported HTTP method(s)
* @return void
*/
public function setHttpMethods() {
$args = func_get_args();
$this->methods = $args;
}
/**
* Get supported HTTP methods
* @return array
*/
public function getHttpMethods() {
return $this->methods;
}
/**
* Append supported HTTP methods
* @return void
*/
public function appendHttpMethods() {
$args = func_get_args();
$this->methods = array_merge($this->methods, $args);
}
/**
* Append supported HTTP methods (alias for Route::appendHttpMethods)
* @return Slim_Route
*/
public function via() {
$args = func_get_args();
$this->methods = array_merge($this->methods, $args);
return $this;
}
/**
* Detect support for an HTTP method
* @return bool
*/
public function supportsHttpMethod( $method ) {
return in_array($method, $this->methods);
}
/**
* Get router
* @return Slim_Router
*/
public function getRouter() {
return $this->router;
}
/**
* Set router
* @param Slim_Router $router
* @return void
*/
public function setRouter( Slim_Router $router ) {
$this->router = $router;
}
/**
* Get middleware
* @return array[Callable]
*/
public function getMiddleware() {
return $this->middleware;
}
/**
* Set middleware
*
* This method allows middleware to be assigned to a specific Route.
* If the method argument `is_callable` (including callable arrays!),
* we directly append the argument to `$this->middleware`. Else, we
* assume the argument is an array of callables and merge the array
* with `$this->middleware`. Even if non-callables are included in the
* argument array, we still merge them; we lazily check each item
* against `is_callable` during Route::dispatch().
*
* @param Callable|array[Callable]
* @return Slim_Route
* @throws InvalidArgumentException If argument is not callable or not an array
*/
public function setMiddleware( $middleware ) {
if ( is_callable($middleware) ) {
$this->middleware[] = $middleware;
} else if ( is_array($middleware) ) {
$this->middleware = array_merge($this->middleware, $middleware);
} else {
throw new InvalidArgumentException('Route middleware must be callable or an array of callables');
}
return $this;
}
/**
* Matches URI?
*
* Parse this route's pattern, and then compare it to an HTTP resource URI
* This method was modeled after the techniques demonstrated by Dan Sosedoff at:
*
* http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/
*
* @param string $resourceUri A Request URI
* @return bool
*/
public function matches( $resourceUri ) {
//Extract URL params
preg_match_all('@:([\w]+)@', $this->pattern, $paramNames, PREG_PATTERN_ORDER);
$paramNames = $paramNames[0];
//Convert URL params into regex patterns, construct a regex for this route
$patternAsRegex = preg_replace_callback('@:[\w]+@', array($this, 'convertPatternToRegex'), $this->pattern);
if ( substr($this->pattern, -1) === '/' ) {
$patternAsRegex = $patternAsRegex . '?';
}
$patternAsRegex = '@^' . $patternAsRegex . '$@';
//Cache URL params' names and values if this route matches the current HTTP request
if ( preg_match($patternAsRegex, $resourceUri, $paramValues) ) {
array_shift($paramValues);
foreach ( $paramNames as $index => $value ) {
$val = substr($value, 1);
if ( isset($paramValues[$val]) ) {
$this->params[$val] = urldecode($paramValues[$val]);
}
}
return true;
} else {
return false;
}
}
/**
* Convert a URL parameter (ie. ":id") into a regular expression
* @param array URL parameters
* @return string Regular expression for URL parameter
*/
protected function convertPatternToRegex( $matches ) {
$key = str_replace(':', '', $matches[0]);
if ( array_key_exists($key, $this->conditions) ) {
return '(?P<' . $key . '>' . $this->conditions[$key] . ')';
} else {
return '(?P<' . $key . '>[a-zA-Z0-9_\-\.\!\~\*\\\'\(\)\:\@\&\=\$\+,%]+)';
}
}
/**
* Set route name
* @param string $name The name of the route
* @return Slim_Route
*/
public function name( $name ) {
$this->setName($name);
return $this;
}
/**
* Merge route conditions
* @param array $conditions Key-value array of URL parameter conditions
* @return Slim_Route
*/
public function conditions( array $conditions ) {
$this->conditions = array_merge($this->conditions, $conditions);
return $this;
}
/**
* Dispatch route
*
* This method invokes this route's callable. If middleware is
* registered for this route, each callable middleware is invoked in
* the order specified.
*
* This method is smart about trailing slashes on the route pattern.
* If this route's pattern is defined with a trailing slash, and if the
* current request URI does not have a trailing slash but otherwise
* matches this route's pattern, a Slim_Exception_RequestSlash
* will be thrown triggering an HTTP 301 Permanent Redirect to the same
* URI _with_ a trailing slash. This Exception is caught in the
* `Slim::run` loop. If this route's pattern is defined without a
* trailing slash, and if the current request URI does have a trailing
* slash, this route will not be matched and a 404 Not Found
* response will be sent if no subsequent matching routes are found.
*
* @return bool Was route callable invoked successfully?
* @throws Slim_Exception_RequestSlash
*/
public function dispatch() {
if ( substr($this->pattern, -1) === '/' && substr($this->router->getRequest()->getResourceUri(), -1) !== '/' ) {
throw new Slim_Exception_RequestSlash();
}
//Invoke middleware
$req = $this->router->getRequest();
$res = $this->router->getResponse();
foreach ( $this->middleware as $mw ) {
if ( is_callable($mw) ) {
call_user_func_array($mw, array($req, $res, $this));
}
}
//Invoke callable
if ( is_callable($this->getCallable()) ) {
call_user_func_array($this->callable, array_values($this->params));
return true;
}
return false;
}
}

237
Slim/Router.php Normal file
View File

@ -0,0 +1,237 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Router
*
* This class organizes Route objects and, upon request, will
* return an iterator for routes that match the HTTP request URI.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_Router implements IteratorAggregate {
/**
* @var Slim_Http_Request
*/
protected $request;
/**
* @var Slim_Http_Response
*/
protected $response;
/**
* @var array Lookup hash of all routes
*/
protected $routes;
/**
* @var array Lookup hash of named routes, keyed by route name
*/
protected $namedRoutes;
/**
* @var array Array of routes that match the Request URI (lazy-loaded)
*/
protected $matchedRoutes;
/**
* @var mixed Callable to be invoked if no matching routes are found
*/
protected $notFound;
/**
* @var mixed Callable to be invoked if application error
*/
protected $error;
/**
* Constructor
* @param Slim_Http_Request $request The HTTP request object
* @param Slim_Http_Response $response The HTTP response object
*/
public function __construct( Slim_Http_Request $request, Slim_Http_Response $response ) {
$this->request = $request;
$this->response = $response;
$this->routes = array();
$this->namedRoutes = array();
}
/**
* Get Iterator
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->getMatchedRoutes());
}
/**
* Get Request
* @return Slim_Http_Request
*/
public function getRequest() {
return $this->request;
}
/**
* Get Response
* @return Slim_Http_Response
*/
public function getResponse() {
return $this->response;
}
/**
* Return routes that match the current request
* @return array[Slim_Route]
*/
public function getMatchedRoutes( $reload = false ) {
if ( $reload || is_null($this->matchedRoutes) ) {
$this->matchedRoutes = array();
foreach ( $this->routes as $route ) {
if ( $route->matches($this->request->getResourceUri()) ) {
$this->matchedRoutes[] = $route;
}
}
}
return $this->matchedRoutes;
}
/**
* Map a route to a callback function
* @param string $pattern The URL pattern (ie. "/books/:id")
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return Slim_Route
*/
public function map( $pattern, $callable ) {
$route = new Slim_Route($pattern, $callable);
$route->setRouter($this);
$this->routes[] = $route;
return $route;
}
/**
* Get URL for named route
* @param string $name The name of the route
* @param array Associative array of URL parameter names and values
* @throws RuntimeException If named route not found
* @return string The URL for the given route populated with the given parameters
*/
public function urlFor( $name, $params = array() ) {
if ( !$this->hasNamedRoute($name) ) {
throw new RuntimeException('Named route not found for name: ' . $name);
}
$pattern = $this->getNamedRoute($name)->getPattern();
$search = $replace = array();
foreach ( $params as $key => $value ) {
$search[] = ':' . $key;
$replace[] = $value;
}
$pattern = str_replace($search, $replace, $pattern);
//Remove remnants of unpopulated, trailing optional pattern segments
return preg_replace(array(
'@\(\/?:.+\/??\)\??@',
'@\?|\(|\)@'
), '', $this->request->getRootUri() . $pattern);
}
/**
* Add named route
* @param string $name The route name
* @param Slim_Route $route The route object
* @throws RuntimeException If a named route already exists with the same name
* @return void
*/
public function addNamedRoute( $name, Slim_Route $route ) {
if ( $this->hasNamedRoute($name) ) {
throw new RuntimeException('Named route already exists with name: ' . $name);
}
$this->namedRoutes[(string)$name] = $route;
}
/**
* Has named route
* @param string $name The route name
* @return bool
*/
public function hasNamedRoute( $name ) {
return isset($this->namedRoutes[(string)$name]);
}
/**
* Get named route
* @param string $name
* @return Slim_Route|null
*/
public function getNamedRoute( $name ) {
if ( $this->hasNamedRoute($name) ) {
return $this->namedRoutes[(string)$name];
} else {
return null;
}
}
/**
* Get named routes
* @return ArrayIterator
*/
public function getNamedRoutes() {
return new ArrayIterator($this->namedRoutes);
}
/**
* Register a 404 Not Found callback
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return mixed
*/
public function notFound( $callable = null ) {
if ( is_callable($callable) ) {
$this->notFound = $callable;
}
return $this->notFound;
}
/**
* Register a 500 Error callback
* @param mixed $callable Anything that returns TRUE for is_callable()
* @return mixed
*/
public function error( $callable = null ) {
if ( is_callable($callable) ) {
$this->error = $callable;
}
return $this->error;
}
}

1275
Slim/Slim.php Normal file

File diff suppressed because it is too large Load Diff

103
Slim/Stream/Data.php Normal file
View File

@ -0,0 +1,103 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Stream Data
*
* This class will stream raw data to the HTTP client.
* You may control how the data is streamed by passing an associative array
* of settings as the second argument to the constructor. They are:
*
* 1) buffer_size - The size of each streamed data chunk
* 2) time_limit - The amount of time allowed to stream the data
*
* By default, PHP will run indefinitely until the data streaming is complete
* or the client closes the HTTP connection. The chunk size is 8192 bytes
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Stream_Data {
/**
* @var string
*/
protected $data;
/**
* @var array
*/
protected $options;
/**
* Constructor
* @param string $data The raw data to be streamed to the HTTP client
* @param array $options Optional associative array of streaming settings
* @return void
*/
public function __construct( $data, $options = array() ) {
$this->data = (string)$data;
$this->options = array_merge(array(
'buffer_size' => 8192,
'time_limit' => 0
), $options);
}
/**
* Process
*
* This method initiates the data stream to the HTTP client. Buffered
* content is continually and immediately flushed. Use the `time_limit`
* setting if you want to set a finite timeout for large data; otherwise
* the script is configured to run indefinitely until all data is sent.
*
* Data will be base64 encoded into memory and streamed in chunks to
* the HTTP client.
*
* @return void
*/
public function process() {
set_time_limit($this->options['time_limit']);
$handle = fopen('data:text/plain;base64,' . base64_encode($this->data), 'rb');
if ( $handle ) {
while ( !feof($handle) && connection_status() === 0 ) {
$buffer = fread($handle, $this->options['buffer_size']);
if ( $buffer ) {
echo $buffer;
ob_flush();
flush();
}
}
fclose($handle);
}
}
}

107
Slim/Stream/File.php Normal file
View File

@ -0,0 +1,107 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Stream File
*
* This class will stream a file from your file system to the HTTP client.
* You may control how the file is streamed by passing an associative array
* of settings as the second argument to the constructor. They are:
*
* 1) buffer_size - The size of each streamed file chunk
* 2) time_limit - The amount of time allowed to stream the file
*
* By default, PHP will run indefinitely until the file streaming is complete
* or the client closes the HTTP connection. The chunk size is 8192 bytes
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Stream_File {
/**
* @var string
*/
protected $path;
/**
* @var array
*/
protected $options;
/**
* Constructor
* @param string $path Relative or absolute path to readable file
* @param array $options Optional associative array of streaming settings
* @return void
* @throws InvalidArgumentException If file does not exist or is not readable
*/
public function __construct( $path, $options = array() ) {
if ( !is_file($path) ) {
throw new InvalidArgumentException('Cannot stream file. File does not exist.');
}
if ( !is_readable($path) ) {
throw new InvalidArgumentException('Cannot stream file. File is not readable.');
}
$this->path = $path;
$this->options = array_merge(array(
'buffer_size' => 8192,
'time_limit' => 0
), $options);
}
/**
* Process
*
* This method initiates the file stream to the HTTP client. Buffered
* content is continually and immediately flushed. Use the `time_limit`
* setting if you want to set a finite timeout for large files; otherwise
* the script is configured to run indefinitely until the entire file is sent.
*
* @return void
*/
public function process() {
set_time_limit($this->options['time_limit']);
$handle = fopen($this->path, 'rb');
if ( $handle ) {
while ( !feof($handle) && connection_status() === 0 ) {
$buffer = fread($handle, $this->options['buffer_size']);
if ( $buffer ) {
echo $buffer;
ob_flush();
flush();
}
}
fclose($handle);
}
}
}

99
Slim/Stream/Process.php Normal file
View File

@ -0,0 +1,99 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Stream Process Output
*
* This class will stream process output to the HTTP client.
* You may control how the output is streamed by passing an associative array
* of settings as the second argument to the constructor. They are:
*
* 1) time_limit - The amount of time allowed to stream the data
*
* By default, PHP will run indefinitely until the output streaming is complete
* or the client closes the HTTP connection. Unlike Slim_Stream_File,
* this class will stream output line by line as it is returned from
* the system process.
*
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
class Slim_Stream_Process {
/**
* @var string
*/
protected $process;
/**
* @var array
*/
protected $options;
/**
* Constructor
* @param string $process The system process to execute; BE SURE YOU ESCAPE SHELL ARGS!
* @param array $options Optional associative array of streaming settings
* @return void
*/
public function __construct( $process, $options = array() ) {
$this->process = (string)$process;
$this->options = array_merge(array(
'time_limit' => 0
), $options);
}
/**
* Process
*
* This method initiates the process output stream to the HTTP client. Buffered
* content is continually and immediately flushed. Use the `time_limit`
* setting if you want to set a finite timeout for large output; otherwise
* the script is configured to run indefinitely until all output is sent.
*
* Unlike Slim_Http_File, data is flushed by line rather than in chunks.
*
* @return void
*/
public function process() {
set_time_limit($this->options['time_limit']);
$handle = popen($this->process, 'r');
if ( $handle ) {
while ( ($data = fgets($handle)) !== false && connection_status() === 0 ) {
echo $data;
ob_flush();
flush();
}
pclose($handle);
}
}
}

164
Slim/View.php Normal file
View File

@ -0,0 +1,164 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart <info@slimframework.com>
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
* @version 1.6.0
* @package Slim
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Slim View
*
* The View is responsible for rendering and/or displaying a template.
* It is recommended that you subclass View and re-implement the
* `View::render` method to use a custom templating engine such as
* Smarty, Twig, Mustache, etc. It is important that `View::render`
* `return` the final template output. Do not `echo` the output.
*
* @package Slim
* @author Josh Lockhart
* @since 1.0.0
*/
class Slim_View {
/**
* @var array Key-value array of data available to the template
*/
protected $data = array();
/**
* @var string Absolute or relative path to the templates directory
*/
protected $templatesDirectory;
/**
* Constructor
*
* This is empty but may be overridden in a subclass
*/
public function __construct() {}
/**
* Get data
* @param string $key
* @return array|mixed|null All View data if no $key, value of datum
* if $key, or NULL if $key but datum
* does not exist.
*/
public function getData( $key = null ) {
if ( !is_null($key) ) {
return isset($this->data[$key]) ? $this->data[$key] : null;
} else {
return $this->data;
}
}
/**
* Set data
*
* This method is overloaded to accept two different method signatures.
* You may use this to set a specific key with a specfic value,
* or you may use this to set all data to a specific array.
*
* USAGE:
*
* View::setData('color', 'red');
* View::setData(array('color' => 'red', 'number' => 1));
*
* @param string|array
* @param mixed Optional. Only use if first argument is a string.
* @return void
* @throws InvalidArgumentException If incorrect method signature
*/
public function setData() {
$args = func_get_args();
if ( count($args) === 1 && is_array($args[0]) ) {
$this->data = $args[0];
} else if ( count($args) === 2 ) {
$this->data[(string)$args[0]] = $args[1];
} else {
throw new InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`');
}
}
/**
* Append data to existing View data
* @param array $data
* @return void
*/
public function appendData( array $data ) {
$this->data = array_merge($this->data, $data);
}
/**
* Get templates directory
* @return string|null Path to templates directory without trailing slash
*/
public function getTemplatesDirectory() {
return $this->templatesDirectory;
}
/**
* Set templates directory
* @param string $dir
* @return void
* @throws RuntimeException If directory is not a directory or does not exist
*/
public function setTemplatesDirectory( $dir ) {
$this->templatesDirectory = rtrim($dir, '/');
}
/**
* Display template
*
* This method echoes the rendered template to the current output buffer
*
* @param string $template Path to template file relative to templates directoy
* @return void
*/
public function display( $template ) {
echo $this->render($template);
}
/**
* Render template
* @param string $template Path to template file relative to templates directory
* @return string Rendered template
* @throws RuntimeException If template does not exist
*/
public function render( $template ) {
extract($this->data);
$templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
if ( !file_exists($templatePath) ) {
throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.');
}
ob_start();
require $templatePath;
return ob_get_clean();
}
}

65
Slim/Views/BlitzView.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* BlitzView
*
* The BlitzView provides native support for the Blitz templating system
* for PHP. Blitz is written as C and compiled to a PHP extension. Which means
* it is FAST. You can learn more about Blitz at:
*
* <http://alexeyrybak.com/blitz/blitz_en.html>
*
* The xBlitz extended blitz class provides better block handling
* (load assoc arrays correctly, one level)
*
* @author Tobias O. <https://github.com/tobsn>
*/
class xBlitz extends Blitz{function xblock($k,$a){foreach($a as $v){$this->block('/'.$k,$v,true);}}}
class BlitzView extends Slim_View {
private $blitzEnvironment = null;
public function render( $template ) {
$env = $this->getEnvironment( $template );
return $env->parse( $this->getData() );
}
private function getEnvironment( $template ) {
if ( !$this->blitzEnvironment ) {
ini_set( 'blitz.path', $this->getTemplatesDirectory() . '/' );
$this->blitzEnvironment = new xBlitz( $template );
}
return $this->blitzEnvironment;
}
}
?>

91
Slim/Views/DwooView.php Normal file
View File

@ -0,0 +1,91 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* DwooView
*
* The DwooView is a Custom View class that renders templates using the
* Dwoo template language (http://dwoo.org/).
*
* There are two fields that you, the developer, will need to change:
* - dwooDirectory
* - dwooTemplatesDirectory
*
* @package Slim
* @author Matthew Callis <http://superfamicom.org/>
*/
class DwooView extends Slim_View {
/**
* @var string The path to the directory containing the Dwoo folder without trailing slash.
*/
public static $dwooDirectory = null;
/**
* @var persistent instance of the Smarty object
*/
private static $dwooInstance = null;
/**
* @var string The path to the templates folder WITH the trailing slash
*/
public static $dwooTemplatesDirectory = 'templates';
/**
* Renders a template using Dwoo.php.
*
* @see View::render()
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
$dwoo = $this->getInstance();
return $dwoo->get(self::$dwooTemplatesDirectory.$template, $this->data);
}
/**
* Creates new Dwoo instance if it doesn't already exist, and returns it.
*
* @throws RuntimeException If Dwoo lib directory does not exist.
* @return DwooInstance
*/
private function getInstance() {
if ( !self::$dwooInstance ) {
if ( !is_dir(self::$dwooDirectory) ) {
throw new RuntimeException('Cannot set the Dwoo lib directory : ' . self::$dwooDirectory . '. Directory does not exist.');
}
require_once self::$dwooDirectory . '/dwooAutoload.php';
self::$dwooInstance = new Dwoo();
}
return self::$dwooInstance;
}
}
?>

View File

@ -0,0 +1,50 @@
# View Extensions
This is where you can define all you custom functions in the template parser method of choice, I have currently included
Twig and Smarty to allow Slim's urlFor() funtion in the template(view). You can add additional functions, filters, plugins to
the Extension directory under the template parser directory of choice.
## Twig
### How to use
To use this in Twig just include the code below at the top of your Slim index.php file after including TwigView.
TwigView::$twigExtensions = array(
'Twig_Extensions_Slim',
);
Inside your Smarty template you would write:
{{ urlFor('hello', {"name": "Josh", "age": "19"}) }}
You can easily pass variables that are objects or arrays by doing:
<a href="{{ urlFor('hello', {"name": person.name, "age": person.age}) }}">Hello {{ name }}</a>
If you need to specify the appname for the getInstance method in the urlFor functions, set it as the third parameter of the function
in your template:
<a href="{{ urlFor('hello', {"name": person.name, "age": person.age}, 'admin') }}">Hello {{ name }}</a>
The $twigExtensions take an array of extension class name which need to follow the naming convention starting with __Extension_Twig__,
this might seem like a overkill to add Slim's urlFor but it makes organising your project easier as your project becomes larger.
## Smarty
### How to use
To use this in Smarty just include the code below at the top of your Slim index.php after including SmartyView.
SmartyView::$smartyExtensions = array(
dirname(__FILE__) . '/Views/Extension/Smarty',
);
Inside your Smarty template you would write:
{urlFor name="hello" options="name.Josh|age.26"}
You can easily pass variables that are arrays using the (.) or object using the (->) by doing:
<a href="{urlFor name="hello" options="name.{$person.name}|age.{$person.age}"}">Hello {$name}</a>
If you need to specify the appname for the getInstance method in the urlFor functions, set the appname parameter in your function:
<a href="{urlFor name="hello" appname="admin" options="name.{$person.name}|age.{$person.age}"}">Hello {$name}</a>
The $smartyExtensions take an array of extension directories, this follows the Smarty naming convention provided in the Smarty docs.

View File

@ -0,0 +1,30 @@
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File: function.urlFor.php
* Type: function
* Name: urlFor
* Purpose: outputs url for a function with the defined name method
* -------------------------------------------------------------
*/
function smarty_function_urlFor($params, $template)
{
$name = isset($params['name']) ? $params['name'] : '';
$appName = isset($params['appname']) ? $params['appname'] : 'default';
$url = Slim::getInstance($appName)->urlFor($name);
if (isset($params['options']))
{
$options = explode('|', $params['options']);
foreach ($options as $option) {
list($key, $value) = explode('.', $option);
$opts[$key] = $value;
}
$url = Slim::getInstance($appName)->urlFor($name, $opts);
}
return $url;
}

View File

@ -0,0 +1,21 @@
<?php
class Twig_Extensions_Slim extends Twig_Extension
{
public function getName()
{
return 'slim';
}
public function getFunctions()
{
return array(
'urlFor' => new Twig_Function_Method($this, 'urlFor'),
);
}
public function urlFor($name, $params = array(), $appName = 'default')
{
return Slim::getInstance($appName)->urlFor($name, $params);
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Autoloads Twig Extensions classes.
*
* @package twig
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class Twig_Extensions_Autoloader
{
/**
* Registers Twig_Extensions_Autoloader as an SPL autoloader.
*/
static public function register()
{
ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array(new self, 'autoload'));
}
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*
* @return boolean Returns true if the class has been loaded
*/
static public function autoload($class)
{
if (0 !== strpos($class, 'Twig_Extensions')) {
return;
}
if (file_exists($file = dirname(__FILE__) . '/' . str_replace('_', '/', $class).'.php')) {
require $file;
}
}
}

88
Slim/Views/H2oView.php Normal file
View File

@ -0,0 +1,88 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* H2oView
*
* The H2oView is a custom View class which provides support for the H2o templating system (http://www.h2o-template.org).
*
* @package Slim
* @author Cenan Ozen <http://cenanozen.com/>
*/
class H2oView extends Slim_View {
/**
* @var string The path to the h2o.php WITH a trailing slash
*/
public static $h2o_directory = '';
/**
* @var array H2o options, see H2o documentation for reference
*/
public static $h2o_options = array();
/**
* Renders a template using h2o
*
* @param string $template template file name
* @return string
*/
public function render($template) {
if ( ! array_key_exists('searchpath', self::$h2o_options)) {
self::$h2o_options['searchpath'] = $this->getTemplatesDirectory().'/';
}
// Make sure H2o is loaded
$this->_load_h2o();
$h2o = new H2o($template, self::$h2o_options);
return $h2o->render($this->data);
}
/**
* Loads H2o library if it is not already loaded
*
* @access private
* @throws RuntimeException if h2o directory doesn't exist
* @return void
*/
private function _load_h2o() {
if (class_exists('H2o')) {
return;
}
if ( ! is_dir(self::$h2o_directory)) {
throw new RuntimeException('h2o directory is invalid');
}
require_once self::$h2o_directory . 'h2o.php';
}
}

78
Slim/Views/HaangaView.php Normal file
View File

@ -0,0 +1,78 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* HaangaView
*
* The HaangaView is a custom View class that renders templates using the Haanga
* template language (http://haanga.org/).
*
* Currently, to use HaangaView, developer must instantiate this class and pass these params:
* - path to Haanga directory which contain `lib`
* - path to templates directory
* - path to compiled templates directory
*
* Example:
* {{{
* require_once 'views/HaangaView.php';
* Slim::init(array(
* 'view' => new HaangaView('/path/to/Haanga/dir', '/path/to/templates/dir', '/path/to/compiled/dir')
* ));
* }}}
*
* @package Slim
* @author Isman Firmansyah
*/
class HaangaView extends Slim_View {
/**
* Configure Haanga environment
*/
public function __construct( $haangaDir, $templatesDir, $compiledDir ) {
require_once $haangaDir . '/lib/Haanga.php';
Haanga::configure(array(
'template_dir' => $templatesDir,
'cache_dir' => $compiledDir
));
}
/**
* Render Haanga Template
*
* This method will output the rendered template content
*
* @param string $template The path to the Haanga template, relative to the Haanga templates directory.
* @return string|NULL
*/
public function render( $template ) {
return Haanga::load($template, $this->data);
}
}
?>

86
Slim/Views/HamlView.php Normal file
View File

@ -0,0 +1,86 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* HamlView
*
* The HamlView is a Custom View class that renders templates using the
* HAML template language (http://haml-lang.com/) through the use of
* HamlPHP (https://github.com/sniemela/HamlPHP).
*
* There are three field that you, the developer, will need to change:
* - hamlDirectory
* - hamlTemplatesDirectory
* - hamlCacheDirectory
*
* @package Slim
* @author Matthew Callis <http://superfamicom.org/>
*/
class HamlView extends Slim_View {
/**
* @var string The path to the directory containing the "HamlPHP" folder without trailing slash.
*/
public static $hamlDirectory = null;
/**
* @var string The path to the templates folder WITH the trailing slash
*/
public static $hamlTemplatesDirectory = 'templates/';
/**
* @var string The path to the templates folder WITH the trailing slash
*/
public static $hamlCacheDirectory = null;
/**
* Renders a template using Haml.php.
*
* @see View::render()
* @throws RuntimeException If Haml lib directory does not exist.
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
if ( !is_dir(self::$hamlDirectory) ) {
throw new RuntimeException('Cannot set the HamlPHP lib directory : ' . self::$hamlDirectory . '. Directory does not exist.');
}
require_once self::$hamlDirectory . '/HamlPHP/HamlPHP.php';
require_once self::$hamlDirectory . '/HamlPHP/Storage/FileStorage.php';
$parser = new HamlPHP(new FileStorage(self::$hamlCacheDirectory));
return $parser->parseFile(self::$hamlTemplatesDirectory.$template, $this->data);
}
}
?>

View File

@ -0,0 +1,67 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* MustacheView
*
* The MustacheView is a Custom View class that renders templates using the
* Mustache template language (http://mustache.github.com/) and the
* [Mustache.php library](github.com/bobthecow/mustache.php).
*
* There is one field that you, the developer, will need to change:
* - mustacheDirectory
*
* @package Slim
* @author Johnson Page <http://johnsonpage.org>
*/
class MustacheView extends Slim_View {
/**
* @var string The path to the directory containing Mustache.php
*/
public static $mustacheDirectory = null;
/**
* Renders a template using Mustache.php.
*
* @see View::render()
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
require_once self::$mustacheDirectory . '/Mustache.php';
$m = new Mustache();
$contents = file_get_contents($this->getTemplatesDirectory() . '/' . ltrim($template, '/'));
return $m->render($contents, $this->data);
}
}
?>

100
Slim/Views/README.markdown Normal file
View File

@ -0,0 +1,100 @@
# Custom Views
The Slim Framework provides a default View class that uses PHP template files by default. This folder includes custom View classes that you may use with alternative template libraries, such as [Twig](http://www.twig-project.org/), [Smarty](http://www.smarty.net/), or [Mustache](http://mustache.github.com/).
## TwigView
The `TwigView` custom View class provides support for the [Twig](http://twig.sensiolabs.org/) template library. You can use the TwigView custom View in your Slim application like this:
<?php
require 'slim/Slim.php';
require 'views/TwigView.php';
$app = new Slim(array(
'view' => 'TwigView'
));
//Insert your application routes here
$app->run();
?>
You will need to configure the `TwigView::$twigOptions` and `TwigView::$twigDirectory` class variables before using the TwigView class in your application. These variables can be found at the top of the `views/TwigView.php` class definition.
## MustacheView
The `MustacheView` custom View class provides support for the [Mustache template language](http://mustache.github.com/) and the [Mustache.php library](github.com/bobthecow/mustache.php). You can use the MustacheView custom View in your Slim application like this:
<?php
require 'slim/Slim.php';
require 'views/MustacheView.php';
MustacheView::$mustacheDirectory = 'path/to/mustacheDirectory/';
$app = new Slim(array(
'view' => 'MustacheView'
));
//Insert your application routes here
$app->run();
?>
Before you can use the MustacheView class, you will need to set `MustacheView::$mustacheDirectory`. This property should be the relative or absolute path to the directory containing the `Mustache.php` library.
## SmartyView
The `SmartyView` custom View class provides support for the [Smarty](http://www.smarty.net/) template library. You can use the SmartyView custom View in your Slim application like this:
<?php
require 'slim/Slim.php';
require 'views/SmartyView.php';
$app = new Slim(array(
'view' => 'SmartyView'
));
//Insert your application routes here
$app->run();
?>
You will need to configure the `SmartyView::$smartyDirectory`, `SmartyView::$smartyCompileDirectory` , `SmartyView::$smartyCacheDirectory` and optionally `SmartyView::$smartyTemplatesDirectory`, class variables before using the SmartyView class in your application. These variables can be found at the top of the `views/SmartyView.php` class definition.
## BlitzView
The `BlitzView` custom View class provides support for the Blitz templating system for PHP. Blitz is written as C and compiled to a PHP extension. Which means it is FAST. You can learn more about Blitz at <http://alexeyrybak.com/blitz/blitz_en.html>. You can use the BlitzView custom View in your Slim application like this:
<?php
require 'slim/Slim.php';
require 'views/BlitzView.php';
$app = new Slim(array(
'view' => 'BlitzView'
));
//Insert your application routes here
$app->run();
?>
Place your Blitz template files in the designated templates directory.
## HaangaView
The `HaangaView` custom View class provides support for the Haanga templating system for PHP. Refer to the `views/HaangaView.php` file for further documentation.
<?php
require 'slim/Slim.php';
require_once 'views/HaangaView.php';
$app = new Slim(array(
'view' => new HaangaView('/path/to/Haanga/dir', '/path/to/templates/dir', '/path/to/compiled/dir')
));
//Insert your application routes here
$app->run();
?>
## H2oView
The `H2oView` custom View class provides support for the [H2o templating system](http://www.h2o-template.org) for PHP. You can use the H2oView custom View in your application like this:
<?php
require 'slim/Slim.php';
require 'views/H2oView.php';
H2oView::$h2o_directory = './h2o/';
$app = new Slim(array('view' => new H2oView));
// Insert your application routes here
$app->run();
?>
Refer to the `Views/H2oView.php` file for further documentation.

100
Slim/Views/RainView.php Normal file
View File

@ -0,0 +1,100 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* RainView
*
* The RainView is a Custom View class that renders templates using the
* Rain template language (http://www.raintpl.com/).
*
* There are three fields that you, the developer, will need to change:
* - rainDirectory
* - rainTemplatesDirectory
* - rainCacheDirectory
*
* @package Slim
* @author Matthew Callis <http://superfamicom.org/>
*/
class RainView extends Slim_View {
/**
* @var string The path to the directory containing "rain.tpl.class.php" without trailing slash.
*/
public static $rainDirectory = null;
/**
* @var persistent instance of the Smarty object
*/
private static $rainInstance = null;
/**
* @var string The path to the templates folder WITH the trailing slash
*/
public static $rainTemplatesDirectory = 'templates/';
/**
* @var string The path to the cache folder WITH the trailing slash
*/
public static $rainCacheDirectory = null;
/**
* Renders a template using Rain.php.
*
* @see View::render()
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
$rain = $this->getInstance();
$rain->assign($this->data);
return $rain->draw($template, $return_string = true);
}
/**
* Creates new Rain instance if it doesn't already exist, and returns it.
*
* @throws RuntimeException If Rain lib directory does not exist.
* @return RainInstance
*/
private function getInstance() {
if ( !self::$rainInstance ) {
if ( !is_dir(self::$rainDirectory) ) {
throw new RuntimeException('Cannot set the Rain lib directory : ' . self::$rainDirectory . '. Directory does not exist.');
}
require_once self::$rainDirectory . '/rain.tpl.class.php';
raintpl::$tpl_dir = self::$rainTemplatesDirectory;
raintpl::$cache_dir = self::$rainCacheDirectory;
self::$rainInstance = new raintpl();
}
return self::$rainInstance;
}
}
?>

92
Slim/Views/SavantView.php Normal file
View File

@ -0,0 +1,92 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* SavantView
*
* The SavantView is a Custom View class that renders templates using the
* Savant3 template language (http://phpsavant.com/).
*
* There are two fields that you, the developer, will need to change:
* - savantDirectory
* - savantOptions
*
* @package Slim
* @author Matthew Callis <http://superfamicom.org/>
*/
class SavantView extends Slim_View {
/**
* @var string The path to the directory containing Savant3.php and the Savant3 folder without trailing slash.
*/
public static $savantDirectory = null;
/**
* @var array The options for the Savant3 environment, see http://phpsavant.com/api/Savant3/
*/
public static $savantOptions = array('template_path' => 'templates');
/**
* @var persistent instance of the Savant object
*/
private static $savantInstance = null;
/**
* Renders a template using Savant3.php.
*
* @see View::render()
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
$savant = $this->getInstance();
$savant->assign($this->data);
return $savant->fetch($template);
}
/**
* Creates new Savant instance if it doesn't already exist, and returns it.
*
* @throws RuntimeException If Savant3 lib directory does not exist.
* @return SavantInstance
*/
private function getInstance() {
if ( !self::$savantInstance ) {
if ( !is_dir(self::$savantDirectory) ) {
throw new RuntimeException('Cannot set the Savant lib directory : ' . self::$savantDirectory . '. Directory does not exist.');
}
require_once self::$savantDirectory . '/Savant3.php';
self::$savantInstance = new Savant3(self::$savantOptions);
}
return self::$savantInstance;
}
}
?>

121
Slim/Views/SmartyView.php Normal file
View File

@ -0,0 +1,121 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* SmartyView
*
* The SmartyView is a custom View class that renders templates using the Smarty
* template language (http://www.smarty.net).
*
* Two fields that you, the developer, will need to change are:
* - smartyDirectory
* - smartyTemplatesDirectory
* - smartyCompileDirectory
* - smartyCacheDirectory
*
* @package Slim
* @author Jose da Silva <http://josedasilva.net>
*/
class SmartyView extends Slim_View {
/**
* @var string The path to the Smarty code directory WITHOUT the trailing slash
*/
public static $smartyDirectory = null;
/**
* @var string The path to the Smarty compiled templates folder WITHOUT the trailing slash
*/
public static $smartyCompileDirectory = null;
/**
* @var string The path to the Smarty cache folder WITHOUT the trailing slash
*/
public static $smartyCacheDirectory = null;
/**
* @var string The path to the templates folder WITHOUT the trailing slash
*/
public static $smartyTemplatesDirectory = 'templates';
/**
* @var SmartyExtensions The Smarty extensions directory you want to load plugins from
*/
public static $smartyExtensions = array();
/**
* @var persistent instance of the Smarty object
*/
private static $smartyInstance = null;
/**
* Render Smarty Template
*
* This method will output the rendered template content
*
* @param string $template The path to the Smarty template, relative to the templates directory.
* @return void
*/
public function render( $template ) {
$instance = self::getInstance();
$instance->assign($this->data);
return $instance->fetch($template);
}
/**
* Creates new Smarty object instance if it doesn't already exist, and returns it.
*
* @throws RuntimeException If Smarty lib directory does not exist
* @return Smarty Instance
*/
public static function getInstance() {
if ( !(self::$smartyInstance instanceof Smarty) ) {
if ( !is_dir(self::$smartyDirectory) ) {
throw new RuntimeException('Cannot set the Smarty lib directory : ' . self::$smartyDirectory . '. Directory does not exist.');
}
require_once self::$smartyDirectory . '/Smarty.class.php';
self::$smartyInstance = new Smarty();
self::$smartyInstance->template_dir = is_null(self::$smartyTemplatesDirectory) ? $this->getTemplatesDirectory() : self::$smartyTemplatesDirectory;
if ( self::$smartyExtensions ) {
self::$smartyInstance->addPluginsDir(self::$smartyExtensions);
}
if ( self::$smartyCompileDirectory ) {
self::$smartyInstance->compile_dir = self::$smartyCompileDirectory;
}
if ( self::$smartyCacheDirectory ) {
self::$smartyInstance->cache_dir = self::$smartyCacheDirectory;
}
}
return self::$smartyInstance;
}
}
?>

103
Slim/Views/SugarView.php Normal file
View File

@ -0,0 +1,103 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* SugarView
*
* The SugarView is a Custom View class that renders templates using the
* Sugar template language (http://php-sugar.net/).
*
* There are three fields that you, the developer, will need to change:
* - sugarDirectory
* - sugarTemplatesDirectory
* - sugarCacheDirectory
*
* @package Slim
* @author Matthew Callis <http://superfamicom.org/>
*/
class SugarView extends Slim_View {
/**
* @var string The path to the directory containing the Sugar folder without trailing slash.
*/
public static $sugarDirectory = null;
/**
* @var persistent instance of the Smarty object
*/
private static $sugarInstance = null;
/**
* @var string The path to the templates folder WITH the trailing slash
*/
public static $sugarTemplatesDirectory = 'templates/';
/**
* @var string The path to the cache folder WITH the trailing slash
*/
public static $sugarCacheDirectory = null;
/**
* Renders a template using Sugar.php.
*
* @see View::render()
* @param string $template The template name specified in Slim::render()
* @return string
*/
public function render( $template ) {
$sugar = $this->getInstance();
$template = $sugar->getTemplate($template);
foreach($this->data as $key => $value){
$template->set($key, $value);
}
return $template->fetch();
}
/**
* Creates new Sugar instance if it doesn't already exist, and returns it.
*
* @throws RuntimeException If Sugar lib directory does not exist.
* @return SugarInstance
*/
private function getInstance() {
if ( !self::$sugarInstance ) {
if ( !is_dir(self::$sugarDirectory) ) {
throw new RuntimeException('Cannot set the Sugar lib directory : ' . self::$sugarDirectory . '. Directory does not exist.');
}
require_once self::$sugarDirectory . '/Sugar.php';
self::$sugarInstance = new Sugar();
self::$sugarInstance->templateDir = self::$sugarTemplatesDirectory;
self::$sugarInstance->cacheDir = self::$sugarCacheDirectory;
}
return self::$sugarInstance;
}
}
?>

115
Slim/Views/TwigView.php Normal file
View File

@ -0,0 +1,115 @@
<?php
/**
* Slim - a micro PHP 5 framework
*
* @author Josh Lockhart
* @link http://www.slimframework.com
* @copyright 2011 Josh Lockhart
*
* MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* TwigView
*
* The TwigView is a custom View class that renders templates using the Twig
* template language (http://www.twig-project.org/).
*
* Two fields that you, the developer, will need to change are:
* - twigDirectory
* - twigOptions
*/
class TwigView extends Slim_View {
/**
* @var string The path to the Twig code directory WITHOUT the trailing slash
*/
public static $twigDirectory = null;
/**
* @var array The options for the Twig environment, see
* http://www.twig-project.org/book/03-Twig-for-Developers
*/
public static $twigOptions = array();
/**
* @var TwigExtension The Twig extensions you want to load
*/
public static $twigExtensions = array();
/**
* @var TwigEnvironment The Twig environment for rendering templates.
*/
private $twigEnvironment = null;
/**
* Render Twig Template
*
* This method will output the rendered template content
*
* @param string $template The path to the Twig template, relative to the Twig templates directory.
* @return void
*/
public function render( $template ) {
$env = $this->getEnvironment();
$template = $env->loadTemplate($template);
return $template->render($this->data);
}
/**
* Creates new TwigEnvironment if it doesn't already exist, and returns it.
*
* @return Twig_Environment
*/
public function getEnvironment() {
if ( !$this->twigEnvironment ) {
// Check for Composer Package Autoloader class loading
if (!class_exists('Twig_Autoloader')) {
require_once self::$twigDirectory . '/Autoloader.php';
}
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem($this->getTemplatesDirectory());
$this->twigEnvironment = new Twig_Environment(
$loader,
self::$twigOptions
);
// Check for Composer Package Autoloader class loading
if (!class_exists('Twig_Extensions_Autoloader')) {
$extension_autoloader = dirname(__FILE__) . '/Extension/TwigAutoloader.php';
if (file_exists($extension_autoloader)) require_once $extension_autoloader;
}
if (class_exists('Twig_Extensions_Autoloader')) {
Twig_Extensions_Autoloader::register();
foreach (self::$twigExtensions as $ext) {
$this->twigEnvironment->addExtension(new $ext);
}
}
}
return $this->twigEnvironment;
}
}
?>

686
assets/css/bootstrap-responsive.css vendored Normal file
View File

@ -0,0 +1,686 @@
/*!
* Bootstrap Responsive v2.0.2
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/
.clearfix {
*zoom: 1;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.input-block-level {
display: block;
width: 100%;
min-height: 28px;
/* Make inputs at least the height of their button counterpart */
/* Makes inputs behave like true block-level elements */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.hidden {
display: none;
visibility: hidden;
}
.visible-phone {
display: none;
}
.visible-tablet {
display: none;
}
.visible-desktop {
display: block;
}
.hidden-phone {
display: block;
}
.hidden-tablet {
display: block;
}
.hidden-desktop {
display: none;
}
@media (max-width: 767px) {
.visible-phone {
display: block;
}
.hidden-phone {
display: none;
}
.hidden-desktop {
display: block;
}
.visible-desktop {
display: none;
}
}
@media (min-width: 768px) and (max-width: 979px) {
.visible-tablet {
display: block;
}
.hidden-tablet {
display: none;
}
.hidden-desktop {
display: block;
}
.visible-desktop {
display: none;
}
}
@media (max-width: 480px) {
.nav-collapse {
-webkit-transform: translate3d(0, 0, 0);
}
.page-header h1 small {
display: block;
line-height: 18px;
}
input[type="checkbox"],
input[type="radio"] {
border: 1px solid #ccc;
}
.form-horizontal .control-group > label {
float: none;
width: auto;
padding-top: 0;
text-align: left;
}
.form-horizontal .controls {
margin-left: 0;
}
.form-horizontal .control-list {
padding-top: 0;
}
.form-horizontal .form-actions {
padding-left: 10px;
padding-right: 10px;
}
.modal {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
width: auto;
margin: 0;
}
.modal.fade.in {
top: auto;
}
.modal-header .close {
padding: 10px;
margin: -10px;
}
.carousel-caption {
position: static;
}
}
@media (max-width: 767px) {
body {
padding-left: 20px;
padding-right: 20px;
}
.navbar-fixed-top {
margin-left: -20px;
margin-right: -20px;
}
.container {
width: auto;
}
.row-fluid {
width: 100%;
}
.row {
margin-left: 0;
}
.row > [class*="span"],
.row-fluid > [class*="span"] {
float: none;
display: block;
width: auto;
margin: 0;
}
.thumbnails [class*="span"] {
width: auto;
}
input[class*="span"],
select[class*="span"],
textarea[class*="span"],
.uneditable-input {
display: block;
width: 100%;
min-height: 28px;
/* Make inputs at least the height of their button counterpart */
/* Makes inputs behave like true block-level elements */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.input-prepend input[class*="span"],
.input-append input[class*="span"] {
width: auto;
}
}
@media (min-width: 768px) and (max-width: 979px) {
.row {
margin-left: -20px;
*zoom: 1;
}
.row:before,
.row:after {
display: table;
content: "";
}
.row:after {
clear: both;
}
[class*="span"] {
float: left;
margin-left: 20px;
}
.container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 724px;
}
.span12 {
width: 724px;
}
.span11 {
width: 662px;
}
.span10 {
width: 600px;
}
.span9 {
width: 538px;
}
.span8 {
width: 476px;
}
.span7 {
width: 414px;
}
.span6 {
width: 352px;
}
.span5 {
width: 290px;
}
.span4 {
width: 228px;
}
.span3 {
width: 166px;
}
.span2 {
width: 104px;
}
.span1 {
width: 42px;
}
.offset12 {
margin-left: 764px;
}
.offset11 {
margin-left: 702px;
}
.offset10 {
margin-left: 640px;
}
.offset9 {
margin-left: 578px;
}
.offset8 {
margin-left: 516px;
}
.offset7 {
margin-left: 454px;
}
.offset6 {
margin-left: 392px;
}
.offset5 {
margin-left: 330px;
}
.offset4 {
margin-left: 268px;
}
.offset3 {
margin-left: 206px;
}
.offset2 {
margin-left: 144px;
}
.offset1 {
margin-left: 82px;
}
.row-fluid {
width: 100%;
*zoom: 1;
}
.row-fluid:before,
.row-fluid:after {
display: table;
content: "";
}
.row-fluid:after {
clear: both;
}
.row-fluid > [class*="span"] {
float: left;
margin-left: 2.762430939%;
}
.row-fluid > [class*="span"]:first-child {
margin-left: 0;
}
.row-fluid > .span12 {
width: 99.999999993%;
}
.row-fluid > .span11 {
width: 91.436464082%;
}
.row-fluid > .span10 {
width: 82.87292817100001%;
}
.row-fluid > .span9 {
width: 74.30939226%;
}
.row-fluid > .span8 {
width: 65.74585634900001%;
}
.row-fluid > .span7 {
width: 57.182320438000005%;
}
.row-fluid > .span6 {
width: 48.618784527%;
}
.row-fluid > .span5 {
width: 40.055248616%;
}
.row-fluid > .span4 {
width: 31.491712705%;
}
.row-fluid > .span3 {
width: 22.928176794%;
}
.row-fluid > .span2 {
width: 14.364640883%;
}
.row-fluid > .span1 {
width: 5.801104972%;
}
input,
textarea,
.uneditable-input {
margin-left: 0;
}
input.span12, textarea.span12, .uneditable-input.span12 {
width: 714px;
}
input.span11, textarea.span11, .uneditable-input.span11 {
width: 652px;
}
input.span10, textarea.span10, .uneditable-input.span10 {
width: 590px;
}
input.span9, textarea.span9, .uneditable-input.span9 {
width: 528px;
}
input.span8, textarea.span8, .uneditable-input.span8 {
width: 466px;
}
input.span7, textarea.span7, .uneditable-input.span7 {
width: 404px;
}
input.span6, textarea.span6, .uneditable-input.span6 {
width: 342px;
}
input.span5, textarea.span5, .uneditable-input.span5 {
width: 280px;
}
input.span4, textarea.span4, .uneditable-input.span4 {
width: 218px;
}
input.span3, textarea.span3, .uneditable-input.span3 {
width: 156px;
}
input.span2, textarea.span2, .uneditable-input.span2 {
width: 94px;
}
input.span1, textarea.span1, .uneditable-input.span1 {
width: 32px;
}
}
@media (max-width: 979px) {
body {
padding-top: 0;
}
.navbar-fixed-top {
position: static;
margin-bottom: 18px;
}
.navbar-fixed-top .navbar-inner {
padding: 5px;
}
.navbar .container {
width: auto;
padding: 0;
}
.navbar .brand {
padding-left: 10px;
padding-right: 10px;
margin: 0 0 0 -5px;
}
.navbar .nav-collapse {
clear: left;
}
.navbar .nav {
float: none;
margin: 0 0 9px;
}
.navbar .nav > li {
float: none;
}
.navbar .nav > li > a {
margin-bottom: 2px;
}
.navbar .nav > .divider-vertical {
display: none;
}
.navbar .nav .nav-header {
color: #999999;
text-shadow: none;
}
.navbar .nav > li > a,
.navbar .dropdown-menu a {
padding: 6px 15px;
font-weight: bold;
color: #999999;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.navbar .dropdown-menu li + li a {
margin-bottom: 2px;
}
.navbar .nav > li > a:hover,
.navbar .dropdown-menu a:hover {
background-color: #222222;
}
.navbar .dropdown-menu {
position: static;
top: auto;
left: auto;
float: none;
display: block;
max-width: none;
margin: 0 15px;
padding: 0;
background-color: transparent;
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.navbar .dropdown-menu:before,
.navbar .dropdown-menu:after {
display: none;
}
.navbar .dropdown-menu .divider {
display: none;
}
.navbar-form,
.navbar-search {
float: none;
padding: 9px 15px;
margin: 9px 0;
border-top: 1px solid #222222;
border-bottom: 1px solid #222222;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
}
.navbar .nav.pull-right {
float: none;
margin-left: 0;
}
.navbar-static .navbar-inner {
padding-left: 10px;
padding-right: 10px;
}
.btn-navbar {
display: block;
}
.nav-collapse {
overflow: hidden;
height: 0;
}
}
@media (min-width: 980px) {
.nav-collapse.collapse {
height: auto !important;
overflow: visible !important;
}
}
@media (min-width: 1200px) {
.row {
margin-left: -30px;
*zoom: 1;
}
.row:before,
.row:after {
display: table;
content: "";
}
.row:after {
clear: both;
}
[class*="span"] {
float: left;
margin-left: 30px;
}
.container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 1170px;
}
.span12 {
width: 1170px;
}
.span11 {
width: 1070px;
}
.span10 {
width: 970px;
}
.span9 {
width: 870px;
}
.span8 {
width: 770px;
}
.span7 {
width: 670px;
}
.span6 {
width: 570px;
}
.span5 {
width: 470px;
}
.span4 {
width: 370px;
}
.span3 {
width: 270px;
}
.span2 {
width: 170px;
}
.span1 {
width: 70px;
}
.offset12 {
margin-left: 1230px;
}
.offset11 {
margin-left: 1130px;
}
.offset10 {
margin-left: 1030px;
}
.offset9 {
margin-left: 930px;
}
.offset8 {
margin-left: 830px;
}
.offset7 {
margin-left: 730px;
}
.offset6 {
margin-left: 630px;
}
.offset5 {
margin-left: 530px;
}
.offset4 {
margin-left: 430px;
}
.offset3 {
margin-left: 330px;
}
.offset2 {
margin-left: 230px;
}
.offset1 {
margin-left: 130px;
}
.row-fluid {
width: 100%;
*zoom: 1;
}
.row-fluid:before,
.row-fluid:after {
display: table;
content: "";
}
.row-fluid:after {
clear: both;
}
.row-fluid > [class*="span"] {
float: left;
margin-left: 2.564102564%;
}
.row-fluid > [class*="span"]:first-child {
margin-left: 0;
}
.row-fluid > .span12 {
width: 100%;
}
.row-fluid > .span11 {
width: 91.45299145300001%;
}
.row-fluid > .span10 {
width: 82.905982906%;
}
.row-fluid > .span9 {
width: 74.358974359%;
}
.row-fluid > .span8 {
width: 65.81196581200001%;
}
.row-fluid > .span7 {
width: 57.264957265%;
}
.row-fluid > .span6 {
width: 48.717948718%;
}
.row-fluid > .span5 {
width: 40.170940171000005%;
}
.row-fluid > .span4 {
width: 31.623931624%;
}
.row-fluid > .span3 {
width: 23.076923077%;
}
.row-fluid > .span2 {
width: 14.529914530000001%;
}
.row-fluid > .span1 {
width: 5.982905983%;
}
input,
textarea,
.uneditable-input {
margin-left: 0;
}
input.span12, textarea.span12, .uneditable-input.span12 {
width: 1160px;
}
input.span11, textarea.span11, .uneditable-input.span11 {
width: 1060px;
}
input.span10, textarea.span10, .uneditable-input.span10 {
width: 960px;
}
input.span9, textarea.span9, .uneditable-input.span9 {
width: 860px;
}
input.span8, textarea.span8, .uneditable-input.span8 {
width: 760px;
}
input.span7, textarea.span7, .uneditable-input.span7 {
width: 660px;
}
input.span6, textarea.span6, .uneditable-input.span6 {
width: 560px;
}
input.span5, textarea.span5, .uneditable-input.span5 {
width: 460px;
}
input.span4, textarea.span4, .uneditable-input.span4 {
width: 360px;
}
input.span3, textarea.span3, .uneditable-input.span3 {
width: 260px;
}
input.span2, textarea.span2, .uneditable-input.span2 {
width: 160px;
}
input.span1, textarea.span1, .uneditable-input.span1 {
width: 60px;
}
.thumbnails {
margin-left: -30px;
}
.thumbnails > li {
margin-left: 30px;
}
}

12
assets/css/bootstrap-responsive.min.css vendored Normal file

File diff suppressed because one or more lines are too long

3990
assets/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

689
assets/css/bootstrap.min.css vendored Normal file
View File

@ -0,0 +1,689 @@
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
audio:not([controls]){display:none;}
html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
a:hover,a:active{outline:0;}
sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
sup{top:-0.5em;}
sub{bottom:-0.25em;}
img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;}
button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
button,input{*overflow:visible;line-height:normal;}
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
textarea{overflow:auto;vertical-align:top;}
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
.clearfix:after{clear:both;}
.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;}
.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
a{color:#0088cc;text-decoration:none;}
a:hover{color:#005580;text-decoration:underline;}
.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
.row:after{clear:both;}
[class*="span"]{float:left;margin-left:20px;}
.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
.span12{width:940px;}
.span11{width:860px;}
.span10{width:780px;}
.span9{width:700px;}
.span8{width:620px;}
.span7{width:540px;}
.span6{width:460px;}
.span5{width:380px;}
.span4{width:300px;}
.span3{width:220px;}
.span2{width:140px;}
.span1{width:60px;}
.offset12{margin-left:980px;}
.offset11{margin-left:900px;}
.offset10{margin-left:820px;}
.offset9{margin-left:740px;}
.offset8{margin-left:660px;}
.offset7{margin-left:580px;}
.offset6{margin-left:500px;}
.offset5{margin-left:420px;}
.offset4{margin-left:340px;}
.offset3{margin-left:260px;}
.offset2{margin-left:180px;}
.offset1{margin-left:100px;}
.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
.row-fluid:after{clear:both;}
.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;}
.row-fluid>[class*="span"]:first-child{margin-left:0;}
.row-fluid > .span12{width:99.99999998999999%;}
.row-fluid > .span11{width:91.489361693%;}
.row-fluid > .span10{width:82.97872339599999%;}
.row-fluid > .span9{width:74.468085099%;}
.row-fluid > .span8{width:65.95744680199999%;}
.row-fluid > .span7{width:57.446808505%;}
.row-fluid > .span6{width:48.93617020799999%;}
.row-fluid > .span5{width:40.425531911%;}
.row-fluid > .span4{width:31.914893614%;}
.row-fluid > .span3{width:23.404255317%;}
.row-fluid > .span2{width:14.89361702%;}
.row-fluid > .span1{width:6.382978723%;}
.container{margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
.container:after{clear:both;}
.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
.container-fluid:after{clear:both;}
p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}
.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;}
h4,h5,h6{line-height:18px;}
h4{font-size:14px;}h4 small{font-size:12px;}
h5{font-size:12px;}
h6{font-size:11px;color:#999999;text-transform:uppercase;}
.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
.page-header h1{line-height:1;}
ul,ol{padding:0;margin:0 0 9px 25px;}
ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
ul{list-style:disc;}
ol{list-style:decimal;}
li{line-height:18px;}
ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
dl{margin-bottom:18px;}
dt,dd{line-height:18px;}
dt{font-weight:bold;line-height:17px;}
dd{margin-left:9px;}
.dl-horizontal dt{float:left;clear:left;width:120px;text-align:right;}
.dl-horizontal dd{margin-left:130px;}
hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
strong{font-weight:bold;}
em{font-style:italic;}
.muted{color:#999999;}
abbr[title]{border-bottom:1px dotted #ddd;cursor:help;}
abbr.initialism{font-size:90%;text-transform:uppercase;}
blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
q:before,q:after,blockquote:before,blockquote:after{content:"";}
address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;}
small{font-size:100%;}
cite{font-style:normal;}
code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;}
pre code{padding:0;color:inherit;background-color:transparent;border:0;}
.pre-scrollable{max-height:340px;overflow-y:scroll;}
form{margin:0 0 18px;}
fieldset{padding:0;margin:0;border:0;}
legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;}
label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;}
input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
label{display:block;margin-bottom:5px;color:#333333;}
input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
.uneditable-textarea{width:auto;height:auto;}
label input,label textarea,label select{display:block;}
input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;}
input[type="image"]{border:0;}
input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;}
select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
input[type="file"]{line-height:18px \9;}
select{width:220px;background-color:#ffffff;}
select[multiple],select[size]{height:auto;}
input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
textarea{height:auto;}
input[type="hidden"]{display:none;}
.radio,.checkbox{padding-left:18px;}
.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}
input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;}
input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
.input-mini{width:60px;}
.input-small{width:90px;}
.input-medium{width:150px;}
.input-large{width:210px;}
.input-xlarge{width:270px;}
.input-xxlarge{width:530px;}
input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;}
input,textarea,.uneditable-input{margin-left:0;}
input.span12, textarea.span12, .uneditable-input.span12{width:930px;}
input.span11, textarea.span11, .uneditable-input.span11{width:850px;}
input.span10, textarea.span10, .uneditable-input.span10{width:770px;}
input.span9, textarea.span9, .uneditable-input.span9{width:690px;}
input.span8, textarea.span8, .uneditable-input.span8{width:610px;}
input.span7, textarea.span7, .uneditable-input.span7{width:530px;}
input.span6, textarea.span6, .uneditable-input.span6{width:450px;}
input.span5, textarea.span5, .uneditable-input.span5{width:370px;}
input.span4, textarea.span4, .uneditable-input.span4{width:290px;}
input.span3, textarea.span3, .uneditable-input.span3{width:210px;}
input.span2, textarea.span2, .uneditable-input.span2{width:130px;}
input.span1, textarea.span1, .uneditable-input.span1{width:50px;}
input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#eeeeee;border-color:#ddd;cursor:not-allowed;}
.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#eeeeee;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";}
.form-actions:after{clear:both;}
.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
:-moz-placeholder{color:#999999;}
::-webkit-input-placeholder{color:#999999;}
.help-block,.help-inline{color:#555555;}
.help-block{display:block;margin-bottom:9px;}
.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
.input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{*margin-left:0;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;}
.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;}
.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
.input-append input,.input-append select .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;}
.input-append .add-on,.input-append .btn{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;margin-bottom:0;}
.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
.form-search label,.form-inline label{display:inline-block;}
.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-left:0;margin-right:3px;}
.control-group{margin-bottom:9px;}
legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
.form-horizontal .control-group:after{clear:both;}
.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;}
.form-horizontal .controls{margin-left:160px;*display:inline-block;*margin-left:0;*padding-left:20px;}
.form-horizontal .help-block{margin-top:9px;margin-bottom:0;}
.form-horizontal .form-actions{padding-left:160px;}
table{max-width:100%;border-collapse:collapse;border-spacing:0;background-color:transparent;}
.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
.table th{font-weight:bold;}
.table thead th{vertical-align:bottom;}
.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
.table tbody+tbody{border-top:2px solid #dddddd;}
.table-condensed th,.table-condensed td{padding:4px 5px;}
.table-bordered{border:1px solid #dddddd;border-left:0;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}
table .span1{float:none;width:44px;margin-left:0;}
table .span2{float:none;width:124px;margin-left:0;}
table .span3{float:none;width:204px;margin-left:0;}
table .span4{float:none;width:284px;margin-left:0;}
table .span5{float:none;width:364px;margin-left:0;}
table .span6{float:none;width:444px;margin-left:0;}
table .span7{float:none;width:524px;margin-left:0;}
table .span8{float:none;width:604px;margin-left:0;}
table .span9{float:none;width:684px;margin-left:0;}
table .span10{float:none;width:764px;margin-left:0;}
table .span11{float:none;width:844px;margin-left:0;}
table .span12{float:none;width:924px;margin-left:0;}
table .span13{float:none;width:1004px;margin-left:0;}
table .span14{float:none;width:1084px;margin-left:0;}
table .span15{float:none;width:1164px;margin-left:0;}
table .span16{float:none;width:1244px;margin-left:0;}
table .span17{float:none;width:1324px;margin-left:0;}
table .span18{float:none;width:1404px;margin-left:0;}
table .span19{float:none;width:1484px;margin-left:0;}
table .span20{float:none;width:1564px;margin-left:0;}
table .span21{float:none;width:1644px;margin-left:0;}
table .span22{float:none;width:1724px;margin-left:0;}
table .span23{float:none;width:1804px;margin-left:0;}
table .span24{float:none;width:1884px;margin-left:0;}
[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;}
.icon-white{background-image:url("../img/glyphicons-halflings-white.png");}
.icon-glass{background-position:0 0;}
.icon-music{background-position:-24px 0;}
.icon-search{background-position:-48px 0;}
.icon-envelope{background-position:-72px 0;}
.icon-heart{background-position:-96px 0;}
.icon-star{background-position:-120px 0;}
.icon-star-empty{background-position:-144px 0;}
.icon-user{background-position:-168px 0;}
.icon-film{background-position:-192px 0;}
.icon-th-large{background-position:-216px 0;}
.icon-th{background-position:-240px 0;}
.icon-th-list{background-position:-264px 0;}
.icon-ok{background-position:-288px 0;}
.icon-remove{background-position:-312px 0;}
.icon-zoom-in{background-position:-336px 0;}
.icon-zoom-out{background-position:-360px 0;}
.icon-off{background-position:-384px 0;}
.icon-signal{background-position:-408px 0;}
.icon-cog{background-position:-432px 0;}
.icon-trash{background-position:-456px 0;}
.icon-home{background-position:0 -24px;}
.icon-file{background-position:-24px -24px;}
.icon-time{background-position:-48px -24px;}
.icon-road{background-position:-72px -24px;}
.icon-download-alt{background-position:-96px -24px;}
.icon-download{background-position:-120px -24px;}
.icon-upload{background-position:-144px -24px;}
.icon-inbox{background-position:-168px -24px;}
.icon-play-circle{background-position:-192px -24px;}
.icon-repeat{background-position:-216px -24px;}
.icon-refresh{background-position:-240px -24px;}
.icon-list-alt{background-position:-264px -24px;}
.icon-lock{background-position:-287px -24px;}
.icon-flag{background-position:-312px -24px;}
.icon-headphones{background-position:-336px -24px;}
.icon-volume-off{background-position:-360px -24px;}
.icon-volume-down{background-position:-384px -24px;}
.icon-volume-up{background-position:-408px -24px;}
.icon-qrcode{background-position:-432px -24px;}
.icon-barcode{background-position:-456px -24px;}
.icon-tag{background-position:0 -48px;}
.icon-tags{background-position:-25px -48px;}
.icon-book{background-position:-48px -48px;}
.icon-bookmark{background-position:-72px -48px;}
.icon-print{background-position:-96px -48px;}
.icon-camera{background-position:-120px -48px;}
.icon-font{background-position:-144px -48px;}
.icon-bold{background-position:-167px -48px;}
.icon-italic{background-position:-192px -48px;}
.icon-text-height{background-position:-216px -48px;}
.icon-text-width{background-position:-240px -48px;}
.icon-align-left{background-position:-264px -48px;}
.icon-align-center{background-position:-288px -48px;}
.icon-align-right{background-position:-312px -48px;}
.icon-align-justify{background-position:-336px -48px;}
.icon-list{background-position:-360px -48px;}
.icon-indent-left{background-position:-384px -48px;}
.icon-indent-right{background-position:-408px -48px;}
.icon-facetime-video{background-position:-432px -48px;}
.icon-picture{background-position:-456px -48px;}
.icon-pencil{background-position:0 -72px;}
.icon-map-marker{background-position:-24px -72px;}
.icon-adjust{background-position:-48px -72px;}
.icon-tint{background-position:-72px -72px;}
.icon-edit{background-position:-96px -72px;}
.icon-share{background-position:-120px -72px;}
.icon-check{background-position:-144px -72px;}
.icon-move{background-position:-168px -72px;}
.icon-step-backward{background-position:-192px -72px;}
.icon-fast-backward{background-position:-216px -72px;}
.icon-backward{background-position:-240px -72px;}
.icon-play{background-position:-264px -72px;}
.icon-pause{background-position:-288px -72px;}
.icon-stop{background-position:-312px -72px;}
.icon-forward{background-position:-336px -72px;}
.icon-fast-forward{background-position:-360px -72px;}
.icon-step-forward{background-position:-384px -72px;}
.icon-eject{background-position:-408px -72px;}
.icon-chevron-left{background-position:-432px -72px;}
.icon-chevron-right{background-position:-456px -72px;}
.icon-plus-sign{background-position:0 -96px;}
.icon-minus-sign{background-position:-24px -96px;}
.icon-remove-sign{background-position:-48px -96px;}
.icon-ok-sign{background-position:-72px -96px;}
.icon-question-sign{background-position:-96px -96px;}
.icon-info-sign{background-position:-120px -96px;}
.icon-screenshot{background-position:-144px -96px;}
.icon-remove-circle{background-position:-168px -96px;}
.icon-ok-circle{background-position:-192px -96px;}
.icon-ban-circle{background-position:-216px -96px;}
.icon-arrow-left{background-position:-240px -96px;}
.icon-arrow-right{background-position:-264px -96px;}
.icon-arrow-up{background-position:-289px -96px;}
.icon-arrow-down{background-position:-312px -96px;}
.icon-share-alt{background-position:-336px -96px;}
.icon-resize-full{background-position:-360px -96px;}
.icon-resize-small{background-position:-384px -96px;}
.icon-plus{background-position:-408px -96px;}
.icon-minus{background-position:-433px -96px;}
.icon-asterisk{background-position:-456px -96px;}
.icon-exclamation-sign{background-position:0 -120px;}
.icon-gift{background-position:-24px -120px;}
.icon-leaf{background-position:-48px -120px;}
.icon-fire{background-position:-72px -120px;}
.icon-eye-open{background-position:-96px -120px;}
.icon-eye-close{background-position:-120px -120px;}
.icon-warning-sign{background-position:-144px -120px;}
.icon-plane{background-position:-168px -120px;}
.icon-calendar{background-position:-192px -120px;}
.icon-random{background-position:-216px -120px;}
.icon-comment{background-position:-240px -120px;}
.icon-magnet{background-position:-264px -120px;}
.icon-chevron-up{background-position:-288px -120px;}
.icon-chevron-down{background-position:-313px -119px;}
.icon-retweet{background-position:-336px -120px;}
.icon-shopping-cart{background-position:-360px -120px;}
.icon-folder-close{background-position:-384px -120px;}
.icon-folder-open{background-position:-408px -120px;}
.icon-resize-vertical{background-position:-432px -119px;}
.icon-resize-horizontal{background-position:-456px -118px;}
.dropdown{position:relative;}
.dropdown-toggle{*margin-bottom:-3px;}
.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
.caret{display:inline-block;width:0;height:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"";}
.dropdown .caret{margin-top:8px;margin-left:2px;}
.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);}
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.pull-right{right:0;left:auto;}
.dropdown-menu .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;}
.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;}
.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
.dropdown.open .dropdown-menu{display:block;}
.pull-right .dropdown-menu{left:auto;right:0;}
.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";}
.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;}
.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;}
.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #cccccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;}
.btn:active,.btn.active{background-color:#cccccc \9;}
.btn:first-child{*margin-left:0;}
.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;}
.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.btn-large [class^="icon-"]{margin-top:1px;}
.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
.btn-small [class^="icon-"]{margin-top:-1px;}
.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;}
.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;}
.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
.btn-primary{background-color:#0074cc;background-image:-moz-linear-gradient(top, #0088cc, #0055cc);background-image:-ms-linear-gradient(top, #0088cc, #0055cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));background-image:-webkit-linear-gradient(top, #0088cc, #0055cc);background-image:-o-linear-gradient(top, #0088cc, #0055cc);background-image:linear-gradient(top, #0088cc, #0055cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);border-color:#0055cc #0055cc #003580;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0055cc;}
.btn-primary:active,.btn-primary.active{background-color:#004099 \9;}
.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;}
.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;}
.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;}
.btn-success:active,.btn-success.active{background-color:#408140 \9;}
.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;}
.btn-info:active,.btn-info.active{background-color:#24748c \9;}
.btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;}
.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
.btn-group:after{clear:both;}
.btn-group:first-child{*margin-left:0;}
.btn-group+.btn-group{margin-left:5px;}
.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;}
.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:3px;*padding-bottom:3px;}
.btn-group .btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:1px;*padding-bottom:1px;}
.btn-group .btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;}
.btn-group .btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;}
.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);}
.btn .caret{margin-top:7px;margin-left:0;}
.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
.btn-mini .caret{margin-top:5px;}
.btn-small .caret{margin-top:6px;}
.btn-large .caret{margin-top:6px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}
.alert-heading{color:inherit;}
.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
.alert-block{padding-top:14px;padding-bottom:14px;}
.alert-block>p,.alert-block>ul{margin-bottom:0;}
.alert-block p+p{margin-top:5px;}
.nav{margin-left:0;margin-bottom:18px;list-style:none;}
.nav>li>a{display:block;}
.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
.nav li+.nav-header{margin-top:9px;}
.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
.nav-list>li>a{padding:3px 15px;}
.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
.nav-list [class^="icon-"]{margin-right:2px;}
.nav-list .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
.nav-tabs:after,.nav-pills:after{clear:both;}
.nav-tabs>li,.nav-pills>li{float:left;}
.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
.nav-tabs{border-bottom:1px solid #ddd;}
.nav-tabs>li{margin-bottom:-1px;}
.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}
.nav-stacked>li{float:none;}
.nav-stacked>li>a{margin-right:0;}
.nav-tabs.nav-stacked{border-bottom:0;}
.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;}
.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}
.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;}
.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
.tabs-stacked .open>a:hover{border-color:#999999;}
.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
.tabbable:after{clear:both;}
.tab-content{display:table;width:100%;}
.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;}
.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
.tab-content>.active,.pill-content>.active{display:block;}
.tabs-below .nav-tabs{border-top:1px solid #ddd;}
.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;}
.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;}
.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;}
.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
.navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;}
.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
.navbar .container{width:auto;}
.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;}
.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;}
.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
.nav-collapse.collapse{height:auto;}
.navbar{color:#999999;}.navbar .brand:hover{text-decoration:none;}
.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;}
.navbar .navbar-text{margin-bottom:0;line-height:40px;}
.navbar .btn,.navbar .btn-group{margin-top:5px;}
.navbar .btn-group .btn{margin-top:0;}
.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";}
.navbar-form:after{clear:both;}
.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;}
.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;}
.navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
.navbar-fixed-top{top:0;}
.navbar-fixed-bottom{bottom:0;}
.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
.navbar .nav.pull-right{float:right;}
.navbar .nav>li{display:block;float:left;}
.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;}
.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;}
.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;}
.navbar .nav.pull-right{margin-left:10px;margin-right:0;}
.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
.navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;}
.navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);}
.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;}
.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;}
.navbar .nav.pull-right .dropdown-menu,.navbar .nav .dropdown-menu.pull-right{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before,.navbar .nav .dropdown-menu.pull-right:before{left:auto;right:12px;}
.navbar .nav.pull-right .dropdown-menu:after,.navbar .nav .dropdown-menu.pull-right:after{left:auto;right:13px;}
.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}
.breadcrumb .divider{padding:0 5px;color:#999999;}
.breadcrumb .active a{color:#333333;}
.pagination{height:36px;margin:18px 0;}
.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
.pagination li{display:inline;}
.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;}
.pagination a:hover,.pagination .active a{background-color:#f5f5f5;}
.pagination .active a{color:#999999;cursor:default;}
.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;}
.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.pagination-centered{text-align:center;}
.pagination-right{text-align:right;}
.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";}
.pager:after{clear:both;}
.pager li{display:inline;}
.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
.pager .next a{float:right;}
.pager .previous a{float:left;}
.pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;}
.modal-open .dropdown-menu{z-index:2050;}
.modal-open .dropdown.open{*z-index:2050;}
.modal-open .popover{z-index:2060;}
.modal-open .tooltip{z-index:2070;}
.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
.modal.fade.in{top:50%;}
.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
.modal-body{overflow-y:auto;max-height:400px;padding:15px;}
.modal-form{margin-bottom:0;}
.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";}
.modal-footer:after{clear:both;}
.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
.modal-footer .btn-group .btn+.btn{margin-left:-1px;}
.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
.tooltip.top{margin-top:-2px;}
.tooltip.right{margin-left:2px;}
.tooltip.bottom{margin-top:2px;}
.tooltip.left{margin-left:-2px;}
.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.tooltip-arrow{position:absolute;width:0;height:0;}
.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;}
.popover.right{margin-left:5px;}
.popover.bottom{margin-top:5px;}
.popover.left{margin-left:-5px;}
.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
.popover .arrow{position:absolute;width:0;height:0;}
.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}
.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";}
.thumbnails:after{clear:both;}
.thumbnails>li{float:left;margin:0 0 18px 20px;}
.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}
a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
.thumbnail .caption{padding:9px;}
.label{padding:1px 4px 2px;font-size:10.998px;font-weight:bold;line-height:13px;color:#ffffff;vertical-align:middle;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
.label:hover{color:#ffffff;text-decoration:none;}
.label-important{background-color:#b94a48;}
.label-important:hover{background-color:#953b39;}
.label-warning{background-color:#f89406;}
.label-warning:hover{background-color:#c67605;}
.label-success{background-color:#468847;}
.label-success:hover{background-color:#356635;}
.label-info{background-color:#3a87ad;}
.label-info:hover{background-color:#2d6987;}
.label-inverse{background-color:#333333;}
.label-inverse:hover{background-color:#1a1a1a;}
.badge{padding:1px 9px 2px;font-size:12.025px;font-weight:bold;white-space:nowrap;color:#ffffff;background-color:#999999;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
.badge-error{background-color:#b94a48;}
.badge-error:hover{background-color:#953b39;}
.badge-warning{background-color:#f89406;}
.badge-warning:hover{background-color:#c67605;}
.badge-success{background-color:#468847;}
.badge-success:hover{background-color:#356635;}
.badge-info{background-color:#3a87ad;}
.badge-info:hover{background-color:#2d6987;}
.badge-inverse{background-color:#333333;}
.badge-inverse:hover{background-color:#1a1a1a;}
@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);}
.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);}
.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);}
.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);}
.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.accordion{margin-bottom:18px;}
.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.accordion-heading{border-bottom:0;}
.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
.carousel{position:relative;margin-bottom:18px;line-height:1;}
.carousel-inner{overflow:hidden;width:100%;position:relative;}
.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
.carousel .item>img{display:block;line-height:1;}
.carousel .active,.carousel .next,.carousel .prev{display:block;}
.carousel .active{left:0;}
.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
.carousel .next{left:100%;}
.carousel .prev{left:-100%;}
.carousel .next.left,.carousel .prev.right{left:0;}
.carousel .active.left{left:-100%;}
.carousel .active.right{left:100%;}
.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);}
.carousel-caption h4,.carousel-caption p{color:#ffffff;}
.hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;}
.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;}
.pull-right{float:right;}
.pull-left{float:left;}
.hide{display:none;}
.show{display:block;}
.invisible{visibility:hidden;}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

1726
assets/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

6
assets/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

145
assets/js/gopher.js Normal file
View File

@ -0,0 +1,145 @@
(function( $ ){
//DirEntity ::= Type User_Name Tab Selector Tab Host Tab Port CR-LF
//1The QuIX Auditorium 1/audio quix.us 70 +
var entryPattern = /^(.)(.*?)\t(.*?)\t(.*?)\t(\d+).*/;
function gopher_parsedir (dirent) {
//var entryPattern = /^(.)(.*?)\t(.*?)\t(.*?)\t(.*?)\u000d\u000a$/;
// http://kevin.vanzonneveld.net
// + original by: Brett Zamir (http://brett-zamir.me)
// * example 1: var entry = gopher_parsedir('0All about my gopher site.\t/allabout.txt\tgopher.example.com\t70\u000d\u000a');
// * example 1: entry.title;
// * returns 1: 'All about my gopher site.'
/* Types
* 0 = plain text file
* 1 = directory menu listing
* 2 = CSO search query
* 3 = error message
* 4 = BinHex encoded text file
* 5 = binary archive file
* 6 = UUEncoded text file
* 7 = search engine query
* 8 = telnet session pointer
* 9 = binary file
* g = Graphics file format, primarily a GIF file
* h = HTML file
* i = informational message
* s = Audio file format, primarily a WAV file
*/
var entry = dirent.match(entryPattern);
if (entry === null) {
return {};
}
var type = entry[1];
switch (type) {
case 'i':
type = 255; // GOPHER_INFO
break;
case '1':
type = 1; // GOPHER_DIRECTORY
break;
case '0':
type = 0; // GOPHER_DOCUMENT
break;
case '4':
type = 4; // GOPHER_BINHEX
break;
case '5':
type = 5; // GOPHER_DOSBINARY
break;
case '6':
type = 6; // GOPHER_UUENCODED
break;
case '9':
type = 9; // GOPHER_BINARY
break;
case 'h':
type = 254; // GOPHER_HTTP
break;
default:
return {
type: -1,
data: dirent
}; // GOPHER_UNKNOWN
}
return {
type: type,
title: entry[2],
path: entry[3],
host: entry[4],
port: entry[5]
};
};
var parseGopher = function(data) {
var lines = [];
data = data.split("\n");
for ( var i = 0; i < data.length; i++ ) {
lines.push(gopher_parsedir(data[i]));
}
return lines;
};
var methods = {
init : function( options ) {
},
shouldRender : function( ) {
var data = $(this).html().trim().split("\n");
return data[0].match(entryPattern) !== null;
},
parse : function( ) {
var data = $(this).html().trim();
return parseGopher(data);
},
fromGopher : function(d) {
var data, entries;
if ( typeof(d) === "undefined" ) {
data = $(this).html().trim();
}
else {
data = d;
}
entries = parseGopher(data);
$(this).html("");
for ( var i = 0; i < entries.length; i++ ) {
var e = entries[i];
var href = "/" + e.host + e.path;
var text = e.title;
var result;
if ( e.path == "" ) {
result = text;
}
else {
result = $("<a />").attr("href", href).html(text);
}
$(this).append(result).append("<br />");
}
}
};
$.fn.gopher = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.gopher' );
}
};
})( jQuery );
//https://raw.github.com/kvz/phpjs/master/functions/net-gopher/gopher_parsedir.js

5
assets/js/gopherSpec.js Normal file
View File

@ -0,0 +1,5 @@
describe("gopher", function() {
it("makes testing JavaScript awesome!", function() {
expect(yourCode).toBeLotsBetter();
});
});

21
composer.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "slim/slim",
"type": "library",
"description": "Slim Framework, a micro framework for PHP 5",
"keywords": ["templating","extensions"],
"homepage": "http://github.com/codeguy/Slim",
"license": "MIT",
"authors": [
{
"name": "Josh Lockhart",
"email": "info@joshlockhart.com",
"homepage": "http://www.joshlockhart.com/"
}
],
"require": {
"php": ">=5.2.0"
},
"autoload": {
"psr-0": { "Slim": "Slim/" }
}
}

View File

@ -0,0 +1,12 @@
# Etag [caching-etag] #
A Slim application provides built-in support for HTTP caching using ETags. An ETag is a unique identifier for a resource URI. When an ETag header is set with the `etag()` method, the HTTP client will send an **If-None-Match** header with each subsequent HTTP request of the same resource URI. If the ETag value for the resource URI matches the **If-None-Match** HTTP request header, the Slim application will return a **304 Not Modified** HTTP response that will prompt the HTTP client to continue using its cache; this also prevents the Slim application from serving the entire markup for the resource URI, saving bandwidth and response time.
Setting an ETag with Slim is very simple. Invoke the `etag()` application method in your route callback, passing it a unique ID as the first and only argument.
$app->get('/foo', function () use ($app) {
$app->etag('unique-id');
echo "This will be cached after the initial request!";
});
Thats it. Make sure the unique ETag ID *is unique for the given resource*. Also make sure the ETag unique ID changes as your resource changes; otherwise, the HTTP client will continue serving its outdated cache.

View File

@ -0,0 +1,11 @@
# Expires [caching-expires] #
Used in conjunction with the Slim application's `etag()` or `lastModified()` methods, the `expires()` method sets an `Expires:` header on the HTTP response informing the HTTP client when its client-side cache for the current resource should be considered stale. The HTTP client will continue serving from its client-side cache until the expiration date is reached, at which time the HTTP client will send a conditional GET request to the Slim application.
The `expires()` method accepts one argument: an integer UNIX timestamp, or a string to be parsed with `strtotime()`.
$app->get('/foo', function () use ($app) {
$app->etag('unique-resource-id');
$app->expires('+1 week');
echo "This will be cached client-side for one week";
});

View File

@ -0,0 +1,10 @@
# Last-Modified [caching-last-modified] #
A Slim application provides built-in support for HTTP caching using the resources last modified date. When you specify a last modified date, Slim tells the HTTP client the date and time the current resource was last modified. The HTTP client will then send a **If-Modified-Since** header with each subsequent HTTP request for the given resource URI. If the last modification date you specify matches the **If-Modified-Since** HTTP request header, the Slim application will return a **304 Not Modified** HTTP response that will prompt the HTTP client to use its cache; this also prevents the Slim application from serving the entire markup for the resource URI saving bandwidth and response time.
Setting a last modified date with Slim is very simple. You only need to invoke the `lastModified()` application instance method in your route callback passing in a UNIX timestamp that represents the last modification date for the given resource. Be sure the `lastModified()` application instance method's timestamp updates along with the resources last modification date; otherwise, the browser client will continue serving its outdated cache.
$app->get('/foo', function () use ($app) {
$app->lastModified(1286139652);
echo "This will be cached after the initial request!";
});

9
docs/caching.markdown Normal file
View File

@ -0,0 +1,9 @@
# HTTP Caching [caching] #
A Slim application provides built-in support for HTTP caching with its `etag()`, `lastModified()`, and `expires()` instance methods. It is best to use _one_ of `etag()` or `lastModified()` — in conjunction with `expires()` — per route; never use _both_ `etag()` and `lastModified()` together in the same route callback.
The `etag()` and `lastModified()` methods should be invoked in a route callback *before* other code; this allows Slim to check conditional GET requests _before_ processing the route callback's remaining code.
Both `etag()` and `lastModified()` instruct the HTTP client to store the resource response in a client-side cache. The `expires()` method indicates to the HTTP client when the client-side cache should be considered stale.
More details for each method are below.

56
docs/environment.markdown Normal file
View File

@ -0,0 +1,56 @@
# The Environment [environment] #
The Slim Framework implements a derivation of the [Rack protocol](http://rack.rubyforge.org/doc/files/SPEC.html). When you instantiate a Slim application, it immediately inspects the `$_SERVER` superglobal and derives a set of environment variables that dictate application behavior.
## What is the Environment? ##
A Slim application's "environment" is an associative array of settings that are parsed once and made accessible to the Slim application and its middleware. You are free to modify the environment variables during runtime; changes will propagate immediately throughout the application.
When you instantiate a Slim application, the environment variables are derived from the `$_SERVER` superglobal; you do not need to set these yourself. However, you are free to modify or supplement these variables in [Slim middleware](#middleware).
These variables are fundamental to determining how your Slim application runs: the resource URI, the HTTP method, the HTTP request body, the URL query parameters, error output, and more. Middleware, described later, gives you the power to — among other things — manipulate environment variables before and/or after the Slim application is run.
## Environment Variables ##
The following text respectfully borrows the same information originally available at <http://rack.rubyforge.org/doc/files/SPEC.html>. The environment array **must** include these variables:
REQUEST_METHOD
: The HTTP request method. This is required and may never be an empty string.
SCRIPT_NAME
: The initial portion of the request URI's "path" that corresponds to the physical directory in which the Slim application is installed --- so that the application knows its virtual "location". This may be an empty string if the application is installed in the top-level of the public document root directory. This will never have a trailing slash.
PATH_INFO
: The remaining portion of the request URI's "path" that determines the "virtual" location of the HTTP request's target resource within the Slim application context. This will always have a leading slash; it may or may not have a trailing slash.
QUERY_STRING
: The part of the HTTP request's URI after, but not including, the "?". This is required but may be an empty string.
SERVER_NAME
: When combined with **SCRIPT\_NAME** and **PATH\_INFO**, this can be used to create a fully qualified URL to an application resource. However, if **HTTP_HOST** is present, that should be used instead of this. This is required and may never be an empty string.
SERVER_PORT
: When combined with **SCRIPT\_NAME** and **PATH\_INFO**, this can be used to create a fully qualified URL to any application resource. This is required and may never be an empty string.
HTTP_*
: Variables matching the HTTP request headers sent by the client. The existence of these variables correspond with those sent in the current HTTP request.
slim.url_scheme
: Will be "http" or "https" depending on the HTTP request URL.
slim.input
: Will be a string representing the raw HTTP request body. If the HTTP request body is empty (e.g. with a GET request), this will be an empty string.
slim.errors
: Must always be a writable resource; by default, this is a write-only resource handle to **php://stderr**.
The Slim application can store its own data in the environment, too. The environment array's keys must contain at least one dot, and should be prefixed uniquely (e.g. "prefix.foo"). The prefix **slim.** is reserved for use by Slim itself and must not be used otherwise. The environment must not contain the keys **HTTP\_CONTENT\_TYPE** or **HTTP\_CONTENT\_LENGTH** (use the versions without **HTTP\_**). The CGI keys (named without a period) must have String values. There are the following restrictions:
* slim.url_scheme must either be "http" or "https".
* slim.input must be a string.
* There must be a valid, writable resource in "slim.errors".
* The **REQUEST\_METHOD** must be a valid token.
* The **SCRIPT\_NAME**, if non-empty, must start with /
* The **PATH\_INFO**, if non-empty, must start with /
* The **CONTENT_LENGTH**, if given, must consist of digits only.
* One of **SCRIPT\_NAME** or **PATH\_INFO** must be set. **PATH\_INFO** should be / if **SCRIPT\_NAME** is empty. **SCRIPT\_NAME** never should be /, but instead be an empty string.

View File

@ -0,0 +1,19 @@
# Debugging [errors-debug] #
You can enable debugging during application instantiation with this setting:
$app = new Slim(array(
'debug' => true
));
You may also enable debugging during runtime with the Slim application's `config()` instance method.
$app = new Slim();
//Enable debugging (on by default)
$app->config('debug', true);
//Disable debugging
$app->config('debug', false);
If debugging is enabled and an exception or error occurs, a detailed error message will appear with the error description, the affected file, the file line number, and a stack trace. If debugging is disabled, your [custom Error handler](#error-handler) will be invoked instead.

View File

@ -0,0 +1,29 @@
# Error Handler [error-handler] #
You may use the Slim application's `error()` instance method to specify a custom error handler to be invoked when an error or exception occurs. Custom error handlers are only invoked if application debugging is disabled.
A custom error handler should render a user-friendly message that mitigates user confusion. Similar to the Slim application's `notFound()` instance method, the `error()` instance method acts as both a getter and a setter.
## Set a Custom Error Handler ##
You may set a custom error handler by passing a callable into the `error()` instance method as the first and only argument.
$app = new Slim();
//PHP >= 5.3
$app->error(function ( Exception $e ) use ($app) {
$app->render('error.php');
});
//PHP < 5.3
$app->error('custom_error_handler');
function custom_error_handler( Exception $e ){
$app = Slim::getInstance();
$app->render('error.php');
}
In this example, notice how the custom error handler accepts the caught Exception as its argument. This allows you to respond appropriately to different exceptions.
## Invoke a Custom Error Handler ##
Usually, the Slim application will automatically invoke the error handler when an exception or error occurs. However, you may also manually invoke the error handler with the Slim application's `error()` method (without an argument).

View File

@ -0,0 +1,35 @@
# Not Found Handler [not-found-handler] #
It is an inevitability that someone will request a page that does not exist. The Slim application lets you easily define a custom **Not Found** handler with the Slim application's `notFound()` instance method. The Not Found handler will be invoked when a matching route is not found for the current HTTP request. This method may be invoked in two different contexts.
## When defining the handler ##
If you invoke the Slim application's `notFound()` instance method and specify a callable object as its first and only argument, this method will register the callable object as the Not Found handler. However, the registered handler will not be invoked.
$app = new Slim();
//For PHP >= 5.3
$app->notFound(function () use ($app) {
$app->render('404.html');
});
//For PHP < 5.3
$app->notFound('custom_not_found_callback');
function custom_not_found_callback() {
$app = Slim::getInstance();
$app->render('404.html');
}
## When invoking the Not Found handler ##
If you invoke the Slim application's `notFound()` instance method without any arguments, this method will invoke the previously registered Not Found handler.
$app = new Slim();
$app->get('/hello/:name', function ($name) use ($app) {
if ( $name === 'Waldo' ) {
$app->notFound();
} else {
echo "Hello, $name";
}
});

View File

@ -0,0 +1,18 @@
# Error Output [errors-output] #
The Slim environment will always contain a key **slim.errors** with a value that is a writable resource to which log and error messages may be written. The Slim application's [Slim_Log](#logging) object will write log messages to **slim.errors** whenever an Exception is caught or the `Slim_Log` object is manually invoked.
If you want to redirect error output to a different location, you can define your own writable resource by modifying the Slim application's environment settings. I recommend you use [middleware](#middleware) to update the environment like this:
class CustomErrorMiddleware extends Slim_Middleware {
public function call() {
// Set new error output
$env = $this->app->environment();
$env['slim.errors'] = fopen('/path/to/custom/output', 'w');
// Call next middleware
$this->next->call();
}
}
Remember, **slim.errors** does not have to point to a file; it can point to any valid writable resource.

View File

@ -0,0 +1,3 @@
# Error Reporting [errors-reporting] #
By default, Slim will report **E\_ALL** and **E\_STRICT** errors. You can change the error reporting by editing **Slim/Slim.php**; the error reporting definition is at the top of that file. Only reported errors will be handled by Slim. Unreported errors will be ignored or handled elsewhere.

7
docs/errors.markdown Normal file
View File

@ -0,0 +1,7 @@
# Error Handling [errors] #
Lets face it: sometimes things go wrong. It is important to intercept errors and respond to them appropriately. A Slim application provides helper methods to respond to errors and exceptions.
Each Slim application handles its own errors and exceptions. If there are multiple Slim applications in the same PHP script, each application will catch and handle its own errors and exceptions. Errors or exceptions generated outside of a Slim application must be caught and handled elsewhere.
To prevent recoverable errors from stopping the entire PHP script, Slim converts errors into `ErrorException` instances that are caught and handled by a default or custom Slim application error handler.

25
docs/flash.markdown Normal file
View File

@ -0,0 +1,25 @@
# Flash Messaging [flash] #
Slim supports flash messaging much like Rails and other larger web frameworks. Flash messaging allows you to define messages that will persist until the next HTTP request but no further. This is helpful to display messages to the user after a given event or error occurs.
As shown below, the Slim application's `flash()` and `flashNow()` instance methods accept two arguments: a key and a message. The key may be whatever you want and defines how the message will be accessed in the View templates. For example, if I invoke the Slim application's `flash('foo', 'The foo message')` instance method with those arguments, I can access that message in the next requests templates with `flash['foo']`.
Flash messages are persisted with sessions; sessions are required for flash messages to work. Flash messages are stored in `$\_SESSION['flash']`.
## Flash
The Slim application's `flash()` instance method sets a message that will be available in the next requests view templates. The message in this example will be available in the variable `flash['error']` in the next requests view templates.
$app->flash('error', 'User email is required');
## Flash Now
The Slim application's `flashNow()` instance method sets a message that will be available in the current requests view templates. Messages set with the `flashNow()` application instance method will not be available in the next request. The message in the example below will be available in the variable `flash['info']` in the current requests view templates.
$app->flashNow('info', 'Your credit card is expired');
## Flash Keep
This method tells the Slim application to keep existing flash messages set in the previous request so they will be available to the next request. This method is helpful for persisting flash messages across HTTP redirects.
$app->flashKeep();

View File

@ -0,0 +1,10 @@
# Custom Hooks [hooks-custom] #
Custom hooks may also be created and invoked in a Slim application. When a custom hook is invoked with `applyHook()`, it will invoke all callables assigned to that hook. This is exactly how the Slim application's [default hooks](#hooks-default) work. In this example, I apply a custom hook called "my.hook.name". All callables previously registered for this hook will be invoked.
$app = new Slim();
$app->applyHook('my.hook.name');
When you run the above code, any callables previously assigned to the hook **my.hook.name** will be invoked in order of priority (ascending).
You should register callables to a hook before the hook is applied. Think of it this way: when you invoke the Slim application's `applyHook()` instance method, you are asking Slim to invoke all callables already registered for that hook name.

View File

@ -0,0 +1,21 @@
# Default Hooks [hooks-default] #
These are the default hooks always invoked in a Slim application.
slim.before
: This hook is invoked before the Slim application is run and before output buffering is turned on. This hook is invoked once during the Slim application lifecycle.
slim.before.router
: This hook is invoked after output buffering is turned on and before the router is dispatched. This hook is invoked once during the Slim application lifecycle.
slim.before.dispatch
: This hook is invoked before the current matching route is dispatched. Usually this hook is invoked only once during the Slim application lifecycle; however, this hook may be invoked multiple times if a matching route chooses to pass to a subsequent matching route.
slim.after.dispatch
: This hook is invoked after the current matching route is dispatched. Usually this hook is invoked only once during the Slim application lifecycle; however, this hook may be invoked multiple times if a matching route chooses to pass to a subsequent matching route.
slim.after.router
: This hook is invoked after the router is dispatched, before the Response is sent to the client, and after output buffering is turned off. This hook is invoked once during the Slim application lifecycle.
slim.after
: This hook is invoked after output buffering is turned off and after the Response is sent to the client. This hook is invoked once during the Slim application lifecycle.

33
docs/hooks-usage.markdown Normal file
View File

@ -0,0 +1,33 @@
# How to use a hook #
A callable is assigned to a hook using the Slim application's `hook()` instance method:
$app = new Slim();
$app->hook('the.hook.name', function () {
//Do something
});
The first argument is the hook name, and the second argument is the callable. Each hook maintains a priority list of registered callables. By default, each callable assigned to a hook is given a priority of 10. You can give your callable a different priority by passing an integer as the third parameter of the `hook()` method like this:
$app = new Slim();
$app->hook('the.hook.name', function () {
//Do something
}, 5);
The example above assigns a priority of 5 to the callable. When the hook is called, it will sort all callables assigned to it by priority (ascending). A callable with priority 1 will be invoked before a callable with priority 10.
Hooks do not pass arguments to their callables. If a callable needs to access the Slim application, you can inject the application into the callback with the `use` keyword or with the static `getInstance()` method:
$app = new Slim();
//If using PHP >= 5.3
$app->hook('the.hook.name', function () use ($app) {
// Do something
});
//If using PHP < 5.3
$app->hook('the.hook.name', 'nameOfMyHookFunction');
function nameOfMyHookFunction() {
$app = Slim::getInstance();
//Do something
}

7
docs/hooks.markdown Normal file
View File

@ -0,0 +1,7 @@
# Hooks [hooks] #
A Slim application provides a set of hooks to which you can register your own callbacks.
A “hook” is a moment in the Slim application lifecycle at which a priority list of callables assigned to the hook will be invoked. A hook is identified by a string name.
A “callable” is anything that returns `true` for `is_callable()`. A callable is assigned to a hook and is invoked when the hook is called.

144
docs/index.txt Normal file
View File

@ -0,0 +1,144 @@
# Documentation
#
# This documentation is written in MultiMarkdown format and may be consolidated into HTML, PDF,
# ODF, Latex, or other formats using the `mmd_merge` command line utility.
#
# Learn more about MultiMarkdown at <http://fletcherpenney.net/multimarkdown/>
welcome.markdown
system-requirements.markdown
instantiation.markdown
settings.markdown
names-and-scopes.markdown
modes.markdown
routing.markdown
routing-get.markdown
routing-post.markdown
routing-put.markdown
routing-delete.markdown
routing-options.markdown
routing-generic.markdown
routing-custom.markdown
routing-parameters.markdown
routing-names.markdown
routing-conditions.markdown
routing-middleware.markdown
routing-helpers.markdown
routing-helpers-halt.markdown
routing-helpers-pass.markdown
routing-helpers-redirect.markdown
routing-helpers-stop.markdown
routing-helpers-urlfor.markdown
routing-indepth.markdown
routing-indepth-slashes.markdown
routing-indepth-with-rewrite.markdown
routing-indepth-without-rewrite.markdown
environment.markdown
request.markdown
request-method.markdown
request-parameters.markdown
request-headers.markdown
request-cookies.markdown
request-xhr.markdown
request-paths.markdown
request-helpers.markdown
response.markdown
response-status.markdown
response-header.markdown
response-body.markdown
response-cookies.markdown
response-helpers.markdown
views.markdown
views-rendering.markdown
views-custom.markdown
views-data.markdown
views-settings.markdown
caching.markdown
caching-etag.markdown
caching-last-modified.markdown
caching-expires.markdown
middleware.markdown
middleware-architecture.markdown
middleware-implementation.markdown
middleware-add.markdown
hooks.markdown
hooks-usage.markdown
hooks-custom.markdown
hooks-default.markdown
flash.markdown
sessions.markdown
logging.markdown
errors.markdown
errors-error-handler.markdown
errors-notfound-handler.markdown
errors-debug.markdown
errors-reporting.markdown
errors-output.markdown

View File

@ -0,0 +1,11 @@
# Instantiation
First `require()` Slim into your application file. If you move the **Slim/** directory elsewhere on your filesystem, it is important that you keep Slim's dependencies in the same directory as Slim.php. Keeping the files together enables you to only require **Slim.php** and have the other files loaded automatically. Assuming the **Slim/** directory is on your include path, you only need to call:
require 'Slim/Slim.php';
After you require Slim, instantiate your Slim application like this:
$app = new Slim();
The Slim constructor accepts an optional associative array of settings to customize the Slim application during instantiation (see [settings]).

104
docs/logging.markdown Normal file
View File

@ -0,0 +1,104 @@
# Logging [logging] #
A Slim application provides a `Slim_Log` object that logs data to a specific output via a log writer.
## How to Log Messages ##
To log messages from a Slim application, get a reference to the `Slim_Log` object like this:
$log = $app->getLog();
The `Slim_Log` object provides the following public interface:
$log->debug( mixed $object );
$log->info( mixed $object );
$log->warn( mixed $object );
$log->error( mixed $object );
$log->fatal( mixed $object );
Each `Slim_Log` method accepts one mixed argument. The argument is usually a string, but the argument can be anything. The argument will be passed to the log writer. It is the log writer's responsibility to log arbitrary input appropriately.
## Log Writers ##
The Slim application's `Slim_Log` instance has a log writer. The log writer is responsible for sending a logged message to the appropriate output (e.g. STDERR, a log file, a remote web service, Twitter, or a database). Out of the box, the Slim application's `Slim_Log` object has a log writer instance of class `Slim_LogFileWriter`; this log writer directs output to the resource handle referenced by the application environment's **slim.errors** key (by default, this is "php://stderr"). You may also define and use a custom log writer.
### How to Use a Custom Log Writer ###
A custom log writer must implement the following public interface:
public function write( mixed $message );
You must tell the Slim application's `Slim_Log` instance to use your writer. You can do so in your application's settings during instantiation like this:
$app = new Slim(array(
'log.writer' => new MyLogWriter()
));
You may also set a custom log writer with middleware like this:
class CustomLogWriterMiddleware extends Slim_Middleware {
public function call() {
//Set the new log writer
$log = $this->app->getLog()->setWriter( new MyLogWriter() );
//Call next middleware
$this->next->call();
}
}
You can set the log writer similarly in an application [hook](#hooks) or [route](#routing-get) callback like this:
$app->hook('slim.before', function () use ($app) {
$app->getLog()->setWriter( new MyLogWriter() );
});
If you only need to redirect error output to a different resource, I recommend you [update the Environment's **slim.errors** element](#errors-output) instead of writing and entirely new LogWriter.
## How to Enable or Disable Logging ##
The Slim application's `Slim_Log` object provides the following public methods to enable or disable logging during runtime.
//Enable logging
$app->getLog()->setEnabled(true);
//Disable logging
$app->getLog()->setEnabled(false);
You may enable or disable the `Slim_Log` object during application instantiation like this:
$app = new Slim(array(
'log.enabled' => true
));
If logging is disabled, the `Slim_Log` object will ignore all logged messages until it is enabled.
## Log Levels ##
The Slim application's `Slim_Log` object provides the following public methods to define the _level_ of messages it will log. When you invoke the `Slim_Log` objects's `debug()`, `info()`, `warn()`, `error()`, or `fatal()` methods, you are inherently assigning a level to the logged message:
Debug
: Level 4
Info
: Level 3
Warn
: Level 2
Error
: Level 1
Fatal
: Level 0
Only messages that have a level _less than_ the current `Slim_Log` object's level will be logged. For example, if the `Slim_Log` object's level is "2", the `Slim_Log` object will ignore debug and info messages but will accept warn, error, and fatal messages.
You can set the `Slim_Log` object's level like this:
$app->getLog()->setLevel(2);
You can set the `Slim_Log` object's level during application instantiation like this:
$app = new Slim(array(
'log.level' => 2
));

View File

@ -0,0 +1,28 @@
# Add Middleware [middleware-add] #
Use the Slim application's `add()` instance method to add new middleware to a Slim application. New middleware will surround previously added middleware, or the Slim application itself if no middleware has yet been added.
## Example Middleware ##
class Secret_Middleware extends Slim_Middleware {
public function call() {
$app = $this->app;
$req = $app->request();
$res = $app->response();
if ( $req->headers('X-Secret-Request') === 'The sun is shining' ) {
$res->header('X-Secret-Response', 'But the ice is slippery');
}
$this->next->call();
}
}
## Add Middleware ##
$app = new Slim();
$app->add(new Secret_Middleware());
$app->get('/foo', function () use ($app) {
//Do something
});
$app->run();
The Slim application's `add()` method accepts one argument: a middleware instance. If the middleware instance requires special configuration, it may implement its own constructor so that it may be configured before it is added to the Slim application.

View File

@ -0,0 +1,36 @@
# Middleware Architecture [middleware-architecture] #
Think of a Slim application as the core of an onion. Each layer of the onion is middleware. When you invoke the Slim application's `run()` method, the outer-most middleware layer is invoked first. When ready, that middleware layer is responsible for optionally invoking the next middleware layer that it surrounds. This process steps deeper into the onion — through each middleware layer — until the core Slim application is invoked. This stepped process is possible because each middleware layer, and the Slim application itself, all implement a public `call()` instance method. When you add new middleware to a Slim application, the added middleware will become a new outer layer and surround the previous outer middleware layer (if available) or the Slim application itself.
## Application Reference ##
The purpose of middleware is to inspect, analyze, or modify the application environment, the application request, and the application response before and/or after the Slim application is invoked. It is easy for each middleware to obtain references to the primary Slim application, the Slim application's environment, the Slim application's request, and the Slim application's response:
class My_Middleware extends Slim_Middleware {
public function call() {
//The Slim application
$app = $this->app;
//The Environment object
$env = $app->environment();
//The Request object
$req = $app->request();
//The Response object
$res = $app->response();
}
}
Changes made to the environment, request, and response objects will propagate immediately throughout the application and its other middleware layers. This is possible because every middleware layer is given a reference to the same Slim application object.
## Next Middleware Reference ##
Each middleware layer also has a reference to the _next_ inner middleware layer with `$this->next`. It is each middleware's responsibility to optionally call the next middleware. Doing so will allow the Slim application to complete its full lifecycle. If a middleware layer chooses _not_ to call the next inner middleware layer, further inner middleware and the Slim application itself will not be run, and the application response will be returned to the HTTP client as is.
class My_Middleware extends Slim_Middleware {
public function call() {
//Optionally call the next middleware
$this->next->call();
}
}

View File

@ -0,0 +1,11 @@
# Middleware Implementation [middleware-implementation] #
Middleware **must** extend the `Slim_Middleware` class and implement a public `call()` instance method. The `call()` method does not accept arguments. Otherwise, each middleware may implement its own constructor, properties, and methods. I encourage you to look at Slim's built-in middleware for working examples (e.g. `Slim/Middleware/ContentTypes.php` or `Slim/Middleware/SessionCookie.php`).
This example is the most simple implementation of Slim application middleware. It extends `Slim_Middleware`, implements a public `call()` method, and calls the next inner middleware.
class My_Middleware extends Slim_Middleware {
public function call() {
$this->next->call();
}
}

3
docs/middleware.markdown Normal file
View File

@ -0,0 +1,3 @@
# Middleware [middleware] #
The Slim Framework implements a derivation of the Rack protocol. As a result, a Slim application can have middleware that may inspect, analyze, or modify the application environment variables, the application Request object, and the application Response object before and/or after the Slim application is invoked.

54
docs/modes.markdown Normal file
View File

@ -0,0 +1,54 @@
# Application Modes [application-modes]
It is common practice to run web applications in a specific mode depending on the current state of the project. If you are developing the application, you will run the application in "development" mode; if you are testing the application, you will run the application in "test" mode; if you launch the application, you will run the application in "production" mode.
Slim supports the concept of modes in that you may define your own modes and prompt Slim to prepare itself appropriately in the current mode. For example, you may want to enable debugging in "development" mode but not in "production" mode. The examples below demonstrate how to configure Slim differently for a given mode.
## What is a mode? [what-is-a-mode]
Technically, an application mode is merely a string of text — like "development" or "production" — that has an associated callback function used to prepare the Slim application appropriately. The application mode may be anything you like: “testing”, “production”, “development”, or even “foo”.
## How do I set the Slim application mode? [how-to-set-mode]
### Use an environment variable
If Slim sees an environment variable named **SLIM_MODE**, it will set the current application mode to that variables value. This lets you define the Slim application mode programmatically if calling the application from the command line.
$_ENV['SLIM_MODE'] = 'production';
### Use an application setting
If an environment variable is not found, Slim will next look for the mode in the application settings.
$app = new Slim(array(
'mode' => 'production'
));
### Default mode
If the environment variable and application setting are not found, Slim will set the application mode to “development”.
## Configure Slim for a specific mode [configure-for-mode]
After you instantiate a Slim application, you may configure the Slim application for a specific mode with the `configureMode()` application instance method. This method accepts two arguments: the first is the name of the target mode, and the second is anything that returns `true` for `is_callable()` that will be immediately invoked if the first argument matches the current application mode.
In this example, assume the current application mode is “production”. Only the callable associated with the “production” mode will be invoked. The callable associated with the “development” mode will be ignored until the application mode is changed to "development".
$app = new Slim(array(
'mode' => 'production'
));
$app->configureMode('production', function () use ($app) {
$app->config(array(
'log.enable' => true,
'log.path' => '../logs',
'debug' => false
));
});
$app->configureMode('development', function () use ($app) {
$app->config(array(
'log.enable' => false,
'debug' => true
));
});

View File

@ -0,0 +1,58 @@
# Application Names and Scopes [names-and-scopes]
When you build a Slim application you will enter various scopes in your code (e.g. global scope and function scope). You will likely need a reference to your Slim application in each scope. You can use application names, or `use` with PHP >= 5.3, to obtain a reference to your Slim application.
## Application Names [application-names]
Every Slim application may be given a name. **This is optional**. Names help you get a reference to a Slim application instance in any scope throughout your code. Here is how you set and get an application's name:
$app = new Slim();
$app->setName('foo');
$theName = $app->getName(); //returns "foo"
## Scope Resolution [scope-resolution]
So how do you get a reference to your Slim application? The example below demonstrates how to obtain a reference to a Slim application within a route callback function. The Slim `$app` variable is accessed in the global scope to define the GET route. We also need to access the Slim `$app` variable within the routes callback scope to render a template.
$app = new Slim();
$app->get('/foo', function () {
$app->render('foo.php'); //<--ERROR
});
This fails because we cannot access the Slim `$app` variable inside of the route callback function. In PHP >= 5.3 we can inject the Slim `$app` variable into the anonymous function scope with the `use` keyword:
$app = new Slim();
$app->get('/foo', function () use ($app) {
$app->render('foo.php'); //<--SUCCESS
});
Now it works correctly. In PHP < 5.3, you can use `Slim::getInstance()` instead.
$app = new Slim();
$app->get('/foo', 'foo');
function foo() {
$app = Slim::getInstance();
$app->render('foo.php');
}
The first instantiated Slim application is automatically assigned the name "default". If you invoke `Slim::getInstance()` without an argument, it will return the Slim application that is named "default".
If you instantiate multiple Slim applications with PHP < 5.3, it is important that you assign each Slim application a name.
$app1 = new Slim();
$app1->setName('myApp1');
$app2 = new Slim();
$app2->setName('myApp2');
$app1->get('/foo', 'appOneCallback');
function appOneCallback() {
$app = Slim::getInstance('myApp1');
}
$app2->get('/foo', 'appTwoCallback');
function appTwoCallback() {
$app = Slim::getInstance('myApp2');
}
Invoking `Slim::getInstance()` without an argument will return a reference to `$app1` because that is the first Slim application instantiated.

View File

@ -0,0 +1,24 @@
# Request Cookies [request-cookies] #
## Get Cookies [request-cookies-basic] ##
A Slim application will automatically parse cookies sent with the current HTTP request. You can fetch cookie values with the Slim application's `getCookie()` instance method like this:
$foo = $app->getCookie('foo');
Only Cookies **sent** with the current HTTP request are accessible with this method. If you set a cookie during the current request, it will not be accessible with this method until the subsequent request. If you want to fetch an array of all cookies sent with the current request, you must use the Request object's `cookies()` instance method like this:
//Get all cookies as associative array
$cookies = $app->request()->cookies();
## Get Encrypted Cookies [request-cookies-encrypted] ##
If you previously set an encrypted cookie, you can fetch its decrypted value with the Slim application's `getEncryptedCookie()` instance method like this:
$cookieValue = $app->getEncryptedCookie('foo');
If the cookie was modified while with the HTTP client, Slim will automatically destroy the cookie's value and invalidate the cookie in the next HTTP response. You can disable this behavior by passing `false` as the second argument:
$cookieValue = $app->getEncryptedCookie('foo', false);
Whether you destroy invalid cookies or not, `NULL` is returned if the cookie does not exist or is invalid.

View File

@ -0,0 +1,15 @@
# Request Headers [request-headers] #
A Slim application will automatically parse all HTTP request headers. You can access the Request headers using the Request `headers()` instance method.
$app = new Slim();
//Fetch all request headers as associative array
$headers = $app->request()->headers();
//Fetch only the ACCEPT_CHARSET header
$charset = $app->request()->headers('ACCEPT_CHARSET'); //returns string or NULL
In the second example, the `headers()` method will either return a string value or `NULL` if the header with the given name does not exist.
The HTTP specification states that HTTP header names may be uppercase, lowercase, or mixed-case. Slim is smart enough to parse and return header values whether you request a header value using upper, lower, or mixed case header name, with either underscores or dashes. So use the naming convention with which you are most comfortable.

View File

@ -0,0 +1,46 @@
# Request Helpers [request-helpers] #
Slim provides several helper methods that help you fetch common HTTP request information.
//Fetch HTTP request content type (e.g. "application/json;charset=utf-8"
$contentType = $app->request()->getContentType();
//Fetch HTTP request media type (e.g "application/json")
$mediaType = $app->request()->getMediaType();
//Fetch HTTP request media type params (e.g [charset => "utf-8"])
$mediaTypeParams = $app->request()->getMediaTypeParams();
//Fetch HTTP request content type charset (e.g. "utf-8")
$charset = $app->request()->getContentCharset();
//Fetch HTTP request content length
$contentLength = $app->request()->getContentLength();
//Fetch HTTP request host (e.g. "slimframework.com")
$host = $app->request()->getHost();
//Fetch HTTP request host with port (e.g. "slimframework.com:80")
$hostAndPort = $app->request()->getHostWithPort();
//Fetch HTTP request port (e.g. 80)
$port = $app->request()->getPort();
//Fetch HTTP request scheme (e.g. "http" or "https")
$scheme = $app->request()->getScheme();
//Fetch HTTP request URI path (root URI + resource URI)
$path = $app->request()->getPath();
//Fetch HTTP request URL (scheme + host [ + port if non-standard ])
$url = $app->request()->getUrl();
//Fetch HTTP request IP address
$ip = $app->request()->getIp();
//Fetch HTTP request referer
$ref = $app->request()->getReferer();
$ref = $app->request()->getReferrer();
//Fetch HTTP request user agent string
$ua = $app->request()->getUserAgent();

View File

@ -0,0 +1,27 @@
# Request Method [request-method] #
Every HTTP request has a method (e.g. GET or POST). You can obtain the current HTTP request method via the Slim application's Request object:
//What is the request method?
$method = $app->request()->getMethod(); //returns "GET", "POST", etc.
//Is this a GET request?
$app->request()->isGet(); //true or false
//Is this a POST request?
$app->request()->isPost(); //true or false
//Is this a PUT request?
$app->request()->isPut(); //true or false
//Is this a DELETE request?
$app->request()->isDelete(); //true or false
//Is this a HEAD request?
$app->request()->isHead(); //true or false
//Is this a OPTIONS request?
$app->request()->isOptions(); //true or false
//Is this a request made with Ajax/XHR?
$app->request()->isAjax(); //true or false

View File

@ -0,0 +1,24 @@
# Request Parameters [request-parameters] #
An HTTP request may have associated parameters (not to be confused with [Route parameters](#routing-paramters)). The GET, POST, or PUT parameters sent with the current HTTP request are exposed via the Slim application's Request object.
If you want to quickly fetch a request parameter value without considering its type, use the `params()` Request method:
$paramValue = $app->request()->params('paramName');
The `params()` Request instance method will first search **PUT** parameters, then **POST** parameters, then **GET** parameters. If no parameter is found, `NULL` is returned. If you only want to search for a specific type of parameter, you can use these Request instance methods instead:
//GET parameter
$paramValue = $app->request()->get('paramName');
//POST parameter
$paramValue = $app->request()->post('paramName');
//PUT parameter
$paramValue = $app->request()->put('paramName');
If a parameter does not exist, each method above will return `NULL`. You can also invoke any of these functions without an argument to obtain an array of all parameters of the given type:
$allGetParams = $app->request()->get();
$allPostParams = $app->request()->post();
$allPutParams = $app->request()->put();

View File

@ -0,0 +1,19 @@
# Request Paths [request-paths] #
Every HTTP request received by a Slim application will have a root URI and a resource URI.
The **root URI** is the physical URL path of the directory in which the Slim application is instantiated and run. If a Slim application is instantiated in **index.php** within the top-most directory of the virtual host's document root, the root URI will be an empty string. If a Slim application is instantiated and run in **index.php** within a physical subdirectory of the virtual host's document root, the root URI will be the path to that subdirectory *with* a leading slash and *without* a trailing slash.
The **resource URI** is the virtual URI path of an application resource. The resource URI will be matched to the Slim application's routes.
Here's an example. Assume the Slim application is installed in a physical subdirectory **/foo** beneath your virtual host's document root. Also assume the full HTTP request URL (what you'd see in the browser location bar) is **/foo/books/1**. The root URI is **/foo** (the path to the physical directory in which the Slim application is instantiated) and the resource URI is **/books/1** (the path to the application resource).
You can get the Requests root URI and resource URI like this:
$app = new Slim();
//Get the Request root URI
$rootUri = $app->request()->getRootUri();
//Get the Request resource URI
$resourceUri = $app->request()->getResourceUri();

View File

@ -0,0 +1,8 @@
# XMLHttpRequest [request-xhr] #
When using a Javascript framework like MooTools or jQuery to execute an XMLHttpRequest, the XMLHttpRequest will usually be sent with a 'X-Requested-With' HTTP header. The Slim application will detect the HTTP request's X-Requested-With header and flag the request as such. If for some reason an XMLHttpRequest cannot be sent with the 'X-Requested-With' HTTP header, you can force the Slim application to assume an HTTP request is an XMLHttpRequest by setting a GET, POST, or PUT parameter in the HTTP request named “isajax” with a truthy value.
Here's how you tell if the current request is an XHR/Ajax request:
$isXHR = $app->request()->isAjax(); //true or false
$isXHR = $app->request()->isXhr(); //true or false; alias of `isAjax()`

7
docs/request.markdown Normal file
View File

@ -0,0 +1,7 @@
# The Request Object [request] #
Each Slim application instance has one Request object. The Request object is an abstraction of the current HTTP request and allows you to easily interact with the [Environment](#environment) variables. Although each Slim application includes a default Request object, the `Slim_Http_Request` class is idempotent; you may instantiate the class at will (in [Middleware](#middleware) or elsewhere in your Slim application) without affecting the application as a whole.
You can obtain a reference to the Slim application's Request object like this:
$app->request();

View File

@ -0,0 +1,16 @@
# Response Body [response-body] #
The HTTP response returned to the client will have a body. The HTTP body is the actual content of the HTTP response delivered to the client. You can use the Slim application's Response object to set the HTTP response's body like this:
$response = $app->response();
$response->body('Foo'); //The body is now "Foo" (overwrites)
$response->write('Bar'); //The body is now "FooBar" (appends)
When you overwrite or append the Response's body, the Response object will automatically set the `Content-Length` header based on the byte size of the new response body.
You can fetch the Response object's body using the same Response `body()` instance method without an argument like this:
$response = $app->response();
$body = $response->body();
Usually, you will never need to manually set the Response body with the Response `body()` or `write()` methods; instead, the Slim application will do this for you. Whenever you `echo()` content from within a route callback, the `echo()`'d content is captured in an output buffer and later appended to the Response body before the HTTP response is returned to the client.

View File

@ -0,0 +1,47 @@
# Response Cookies [response-cookies] #
The Slim application instance provides several helper methods to send cookies with the HTTP response.
## Set Cookie ##
This example demonstrates how to use the Slim application's `setCookie()` instance method to create a Cookie that will be sent with the HTTP response:
$app->setCookie('foo', 'bar', '2 days');
This creates a cookie with name **foo** and value **bar** that expires two days from now. You may also provide additional cookie properties, including path, domain, secure, and httponly. The Slim application's `setCookie()` method uses the same signature as PHP's native `setCookie()` function.
$app->setCookie($name, $value, $expiresAt, $path, $domain, $secure, $httponly);
The last argument, `$httpOnly`, was added in PHP 5.2. However, because Slim's underlying cookie implementation does not rely on PHP's native `setCookie()` function, you may use the `$httpOnly` cookie property even with PHP 5.1.
## Set Encrypted Cookie [response-cookies-encrypted] ##
You may also create encrypted cookies using the Slim application's `setEncryptedCookie()` instance method. This method acts the same as the Slim application's `setCookie()` instance method demonstrated above, but it will encrypt the cookie value using the AES-256 cipher and your own secret key. To use encryption, you **must** define your encryption key when you instantiate your Slim application like this:
$app = new Slim(array(
'cookies.secret_key' => 'my_secret_key'
));
If you prefer, you may also change the default cipher and cipher mode, too:
$app = new Slim(array(
'cookies.secret_key' => 'my_secret_key',
'cookies.cipher' => MCRYPT_RIJNDAEL_256,
'cookies.cipher_mode' => MCRYPT_MODE_CBC
));
The encrypted cookie value is hashed and later verified to ensure data integrity so that its value is not changed while on the HTTP client.
## Delete Cookie [response-cookies-delete] ##
You can delete a cookie using the Slim application's `deleteCookie()` instance method. This will remove the cookie from the HTTP client before the next HTTP request. This method accepts the same signature as the Slim application's `setCookie()` instance method, just without the `$expires` argument. Only the first argument is required.
$app->deleteCookie('foo');
Or if you need to also specify the **path** and **domain**:
$app->deleteCookie('foo', '/', 'foo.com');
You may also further specify the **secure** and **httponly** properties, too:
$app->deleteCookie('foo', '/', 'foo.com', true, true);

View File

@ -0,0 +1,15 @@
# Response Header [response-header] #
The HTTP response returned to the HTTP client will have a header. The HTTP header is a list of keys and values that provide metadata about the HTTP response. You can use the Slim application's Response object to set the HTTP response's header. The Response object is special because it acts like an array. Here's an example.
$response = $app->response();
$response['Content-Type'] = 'application/json';
$response['X-Powered-By'] = 'Slim';
Just the same, you can also fetch headers from the Response object like this:
$response = $app->response();
$contentType = $response['Content-Type'];
$poweredBy = $response['X-Powered-By'];
If a header with the given name does not exist, `NULL` is returned instead. You may specify header names with upper, lower, or mixed case with dashes or underscores. Use the naming convention with which you are most comfortable.

View File

@ -0,0 +1,52 @@
# Response Helpers [response-helpers] #
The Response object provides several instance methods to help you inspect and interact with the underlying HTTP response.
## Finalize [response-helpers-finalize] ##
The Response object's `finalize()` method returns a numeric array of status, header, and body. The status is an integer; the header is an iterable data structure; and the body is a string. Were you to create a new Response object in the Slim application or in middleware, you would call this method to produce the status, header, and body for the underlying response.
$res = new Slim_Http_Response();
$res->status(400);
$res->write('You made a bad request');
$res['Content-Type'] = 'text/plain';
$array = $res->finalize(); //returns [200, ['Content-type' => 'text/plain'], 'You made a bad request']
## Redirect [response-helpers-redirect] ##
The Response object's `redirect()` method will help you quickly set the status and **Location:** header needed to return a **3xx Redirect** response.
$app->response()->redirect('/foo', 303);
In this example, the Response will now have a **Location:** header with value "/foo" and a 303 status code.
## Status Inspection [response-helpers-inspection] ##
The Response object provides several methods to help you quickly inspect the type of Response based on its status. All return a boolean value. They are:
//Is this an informational response?
$app->response()->isInformational();
//Is this a 200 OK response?
$app->response()->isOk();
//Is this a 2xx successful response?
$app->response()->isSuccessful();
//Is this a 3xx redirection response?
$app->response()->isRedirection();
//Is this a specific redirect response? (301, 302, 303, 307)
$app->response()->isRedirect();
//Is this a forbidden response?
$app->response()->isForbidden();
//Is this a not found response?
$app->response()->isNotFound();
//Is this a client error response?
$app->response()->isClientError();
//Is this a server error response?
$app->response()->isServerError();

View File

@ -0,0 +1,9 @@
# Response Status [response-status] #
The HTTP response returned to the client will have a status code indicating the response's type (e.g. 200 OK, 400 Bad Request, or 500 Server Error). You can use the Slim application's Response object to set the HTTP response's status like this:
$app->response()->status(400);
You only need to set the Response object's status if you intend to return an HTTP response that does not have a **200 OK** status. You can just as easily fetch the Response object's current HTTP status by invoking the same method without an argument, like this:
$status = $app->response()->status(); //returns int

9
docs/response.markdown Normal file
View File

@ -0,0 +1,9 @@
# The Response Object [response] #
Each Slim application instance has one Response object. The Response object is a high-level interface that allows you to easily interact with the HTTP response that is returned to the HTTP client. Although each Slim application includes a default Response object, the `Slim_Http_Response` class is idempotent; you may instantiate the class at will (in [Middleware](#middleware) or elsewhere in your Slim application) without affecting the application as a whole.
You can obtain a reference to the Slim application's Response object like this:
$app->response();
An HTTP response has three primary properties: the status code, the header, and the body. The Response object provides several helper methods, described next, that help you interact with these HTTP response properties in your Slim application. The default Response object in each Slim application will return a **200 OK** HTTP response with the **text/html** content type.

View File

@ -0,0 +1,30 @@
# Route Conditions [routing-conditions] #
Slim lets you assign conditions to route parameters. If the specified conditions are not met, the route is not run. For example, if you need a route with a second segment that must be a valid 4-digit year, you could enforce this condition like this:
$app = new Slim();
$app->get('/archive/:year', function ($year) {
echo "You are viewing archives from $year";
})->conditions(array('year' => '(19|20)\d\d'));
Invoke the `conditions()` Route method. The first and only argument is an associative array with keys that match any of the routes parameters and values that are regular expressions.
## Application-wide Route Conditions
If many of your Slim application Routes accept the same parameters and use the same conditions, you can define default application-wide Route conditions like this:
Slim_Route::setDefaultConditions(array(
'firstName' => '[a-zA-Z]{3,}'
));
Define application-wide route conditions before you define application routes. When you define a route, the route will automatically be assigned any application-wide Route conditions defined with `Slim\_Route::setDefaultConditions()`. If for whatever reason you need to get the application-wide default route conditions, you can fetch them with `Slim_Route::getDefaultConditions()`; this static method returns an array exactly as the default route conditions were defined.
You may override a default route condition by redefining the routes condition when you define the route, like this:
$app = new Slim();
$app->get('/hello/:firstName', $callable)->conditions(array('firstName' => '[a-z]{10,}'));
You may append new conditions to a given route like this:
$app = new Slim();
$app->get('/hello/:firstName/:lastName', $callable)->conditions(array('lastName' => '[a-z]{10,}'));

View File

@ -0,0 +1,29 @@
# Custom Routes [routing-custom] #
## One Route, Multiple HTTP Methods ##
Sometimes you may need a route to respond to multiple HTTP methods; sometimes you may need a route to respond to a custom HTTP method. You can accomplish both with the `via()` Route method. This example demonstrates how to map a resource URI to a callback that responds to multiple HTTP methods.
$app = new Slim();
$app->map('/foo/bar', function() {
echo "I respond to multiple HTTP methods!";
})->via('GET', 'POST');
$app->run();
The route defined in this example will respond to both GET and POST requests for the resource identified by "/foo/bar". Specify each appropriate HTTP method as a separate string argument to the `via()` Route method. Like other Route methods (e.g. `name()` and `conditions()`), the `via()` Route method is chainable:
$app = new Slim();
$app->map('/foo/bar', function() {
echo "Fancy, huh?";
})->via('GET', 'POST')->name('foo');
$app->run();
## One Route, Custom HTTP Methods ##
The `via()` Route method is not limited to just GET, POST, PUT, DELETE, and OPTIONS methods. You may also specify your own custom HTTP methods (e.g. if you were responding to WebDAV HTTP requests). You can define a route that responds to a custom "FOO" HTTP method like this:
$app = new Slim();
$app->map('/hello', function() {
echo "Hello";
})->via('FOO');
$app->run();

View File

@ -0,0 +1,32 @@
# DELETE Routes [routing-delete] #
Use the `delete()` application instance method to map a callback function to a resource URI that is requested with the HTTP DELETE method.
$app = new Slim();
//For PHP >= 5.3
$app->delete('/books/:id', function ($id) {
//Delete book identified by $id
});
//For PHP < 5.3
$app->delete('/books/:id', 'delete_book');
function delete_book($id) {
//Delete book identified by $id
}
In this example, an HTTP DELETE request for “/books/1” will invoke the associated callback function.
The first argument of the `delete()` application instance method is the resource URI. The last argument is anything that returns `true` for `is_callable()`. I encourage you to use PHP >= 5.3 so you may take advantage of anonymous functions.
## Method Override ##
Unfortunately, modern browsers do not provide native support for HTTP DELETE requests. To work around this limitation, ensure your HTML forms **method** attribute is “post”, then add a method override parameter to your HTML form like this:
<form action="/books/1" method="post">
... other form fields here...
<input type="hidden" name="_METHOD" value="DELETE"/>
<input type="submit" value="Delete Book"/>
</form>
If you are using [Backbone.js](http://documentcloud.github.com/backbone/) or a command-line HTTP client, you may also override the HTTP method by using the `X-HTTP-Method-Override` header.

View File

@ -0,0 +1,11 @@
# Generic Routes [routing-generic] #
Slim provides the `map()` application instance method to define generic routes that are not immediately associated with an HTTP method.
$app = new Slim();
$app->map('/generic/route', function () {
echo "I'm a generic route!";
});
$app->run();
This example always returns a **404 Not Found** response because the "/generic/route" route does not respond to any HTTP methods. Use the [via()](#routing-custom) method (available on Route objects), to assign one or many HTTP methods to a generic route.

Some files were not shown because too many files have changed in this diff Show More