mirror of https://github.com/flightphp/core
commit
ce8dbfc435
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2011 Mike Cao <mike@mikecao.com>
|
||||
|
||||
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,0 +1,13 @@
|
||||
# Flight
|
||||
|
||||
Flight is an extensible micro-framework for PHP.
|
||||
|
||||
## Example
|
||||
|
||||
include 'flight/Flight.php';
|
||||
|
||||
Flight::route('/', function(){
|
||||
echo 'hello world!';
|
||||
});
|
||||
|
||||
Flight::start();
|
@ -0,0 +1,546 @@
|
||||
<?php
|
||||
/**
|
||||
* Flight: an extensible PHP micro-framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php
|
||||
* @version 0.1
|
||||
*/
|
||||
class Flight {
|
||||
/**
|
||||
* Stored variables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $vars = array();
|
||||
|
||||
/**
|
||||
* Registered classes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $classes = array();
|
||||
|
||||
/**
|
||||
* Mapped methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $methods = array();
|
||||
|
||||
/**
|
||||
* Method filters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $filters = array();
|
||||
|
||||
// Don't allow object instantiation
|
||||
private function __construct() {}
|
||||
private function __destruct() {}
|
||||
private function __clone() {}
|
||||
|
||||
/**
|
||||
* Handles calls to static methods.
|
||||
*
|
||||
* @param string $name Method name
|
||||
* @param array $args Method parameters
|
||||
*/
|
||||
public static function __callStatic($name, $params) {
|
||||
// Check if call is mapped to a method
|
||||
if (isset(self::$methods[$name]) || method_exists(__CLASS__, '_'.$name)) {
|
||||
$method = self::$methods[$name] ?: array(__CLASS__, '_'.$name);
|
||||
|
||||
// Run pre-filters
|
||||
if (!empty(self::$filters['before'][$name])) {
|
||||
self::filter(self::$filters['before'][$name], $params);
|
||||
}
|
||||
|
||||
// Run requested method
|
||||
$output = self::execute($method, $params);
|
||||
|
||||
// Run post-filters
|
||||
if (!empty(self::$filters['after'][$name])) {
|
||||
self::filter(self::$filters['after'][$name], $output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
// Otherwise try to autoload class
|
||||
return self::load($name, (bool)$params[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a callback to a framework method.
|
||||
*
|
||||
* @param string $name Method name
|
||||
* @param callback $callback Callback function
|
||||
*/
|
||||
public static function map($name, $callback) {
|
||||
if (method_exists(__CLASS__, $name)) {
|
||||
throw new Exception('Cannot override an existing framework method.');
|
||||
}
|
||||
self::$methods[$name] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a class to a framework method.
|
||||
*
|
||||
* @param string $name Method name
|
||||
* @param string $class Class name
|
||||
* @param array $params Class initialization parameters
|
||||
* @param callback $callback Function to call after object instantiation
|
||||
*/
|
||||
public static function register($name, $class, array $params = array(), $callback = null) {
|
||||
if (method_exists(__CLASS__, $name)) {
|
||||
throw new Exception('Cannot override an existing framework method.');
|
||||
}
|
||||
self::$classes[$name] = array($class, $params, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a registered class.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param array $method List of methods to load
|
||||
*/
|
||||
public static function load($name, $shared = true) {
|
||||
if (isset(self::$classes[$name])) {
|
||||
list($class, $params, $callback) = self::$classes[$name];
|
||||
|
||||
$obj = ($shared) ?
|
||||
self::getInstance($class, $params) :
|
||||
self::getClass($class, $params);
|
||||
|
||||
if ($callback) self::execute($callback, $ref = array($obj));
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
return self::getInstance(ucfirst($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pre-filter to a method.
|
||||
*
|
||||
* @param string $name Method name
|
||||
* @param callback $callback Callback function
|
||||
*/
|
||||
public static function before($name, $callback) {
|
||||
self::$filters['before'][$name][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a post-filter to a method.
|
||||
*
|
||||
* @param string $name Method name
|
||||
* @param callback $callback Callback function
|
||||
*/
|
||||
public static function after($name, $callback) {
|
||||
self::$filters['after'][$name][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a callback function.
|
||||
*
|
||||
* @param callback $callback Callback function
|
||||
* @param array $params Function parameters
|
||||
* @return mixed Function results
|
||||
*/
|
||||
public static function execute($callback, &$params) {
|
||||
if (is_callable($callback)) {
|
||||
return is_array($callback) ?
|
||||
self::invokeMethod($callback, $params) :
|
||||
self::callFunction($callback, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a chain of method filters.
|
||||
*
|
||||
* @param array $filters Chain of filters
|
||||
* @param array $params Method parameters
|
||||
* @param mixed $data Method output
|
||||
*/
|
||||
public static function filter($filters, &$data) {
|
||||
foreach ($filters as $callback) {
|
||||
$continue = self::execute($callback, $params = array(&$data));
|
||||
if ($continue === false) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function.
|
||||
*
|
||||
* @param string $func Name of function to call
|
||||
* @param array $params Function parameters
|
||||
*/
|
||||
public static function callFunction($func, array &$params = array()) {
|
||||
switch (count($params)) {
|
||||
case 0:
|
||||
return $func();
|
||||
case 1:
|
||||
return $func($params[0]);
|
||||
case 2:
|
||||
return $func($params[0], $params[1]);
|
||||
case 3:
|
||||
return $func($params[0], $params[1], $params[2]);
|
||||
case 4:
|
||||
return $func($params[0], $params[1], $params[2], $params[3]);
|
||||
case 5:
|
||||
return $func($params[0], $params[1], $params[2], $params[3], $params[4]);
|
||||
default:
|
||||
return call_user_func_array($func, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a method.
|
||||
*
|
||||
* @param mixed $func Class method as either an array or string
|
||||
* @param array $params Class initialization parameters
|
||||
*/
|
||||
public static function invokeMethod($func, array &$params = array()) {
|
||||
list($class, $method) = $func;
|
||||
|
||||
switch (count($params)) {
|
||||
case 0:
|
||||
return $class::$method();
|
||||
case 1:
|
||||
return $class::$method($params[0]);
|
||||
case 2:
|
||||
return $class::$method($params[0], $params[1]);
|
||||
case 3:
|
||||
return $class::$method($params[0], $params[1], $params[2]);
|
||||
case 4:
|
||||
return $class::$method($params[0], $params[1], $params[2], $params[3]);
|
||||
case 5:
|
||||
return $class::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
|
||||
default:
|
||||
return call_user_func_array($func, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single instance of a class.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param array $params Class initialization parameters
|
||||
*/
|
||||
public static function getInstance($class, array $params = array()) {
|
||||
static $instances = array();
|
||||
|
||||
if (!isset($instances[$class])) {
|
||||
$instances[$class] = self::getClass($class, $params);
|
||||
}
|
||||
|
||||
return $instances[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a class object.
|
||||
*
|
||||
* @param string $class Class name
|
||||
* @param array $params Class initialization parameters
|
||||
*/
|
||||
public static function getClass($class, array $params = array()) {
|
||||
switch (count($params)) {
|
||||
case 0:
|
||||
return new $class();
|
||||
case 1:
|
||||
return new $class($params[0]);
|
||||
case 2:
|
||||
return new $class($params[0], $params[1]);
|
||||
case 3:
|
||||
return new $class($params[0], $params[1], $params[2]);
|
||||
case 4:
|
||||
return new $class($params[0], $params[1], $params[2], $params[3]);
|
||||
case 5:
|
||||
return new $class($params[0], $params[1], $params[2], $params[3], $params[4]);
|
||||
default:
|
||||
$ref_class = new ReflectionClass($class);
|
||||
return $ref_class->newInstanceArgs($params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a variable.
|
||||
*
|
||||
* @param string $key Key
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key) {
|
||||
return self::$vars[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a variable.
|
||||
*
|
||||
* @param mixed $key Key
|
||||
* @param string $value Value
|
||||
*/
|
||||
public static function set($key, $value = null) {
|
||||
// If key is an array, save each key value pair
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $k => $v) {
|
||||
self::$vars[$k] = $v;
|
||||
}
|
||||
}
|
||||
// If key is an object, save each property
|
||||
else if (is_object($key)) {
|
||||
foreach (get_object_vars($key) as $k => $v) {
|
||||
self::$vars[$k] = $v;
|
||||
}
|
||||
}
|
||||
else if (is_string($key)) {
|
||||
self::$vars[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a variable exists.
|
||||
*
|
||||
* @param string $key Key
|
||||
* @return bool Variable status
|
||||
*/
|
||||
public static function exists($key) {
|
||||
return isset(self::$vars[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets a variable. If no key is passed in, clear all variables.
|
||||
*
|
||||
* @param string $key Key
|
||||
*/
|
||||
public static function clear($key = null) {
|
||||
if (is_null($key)) {
|
||||
self::$vars = array();
|
||||
}
|
||||
else {
|
||||
unset(self::$vars[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the framework.
|
||||
*/
|
||||
public static function init() {
|
||||
static $initialized = false;
|
||||
|
||||
if (!$initialized) {
|
||||
// Register autoloader
|
||||
spl_autoload_register(array(__CLASS__, 'autoload'));
|
||||
|
||||
// Handle errors internally
|
||||
set_error_handler(array(__CLASS__, 'handleError'));
|
||||
|
||||
// Handle exceptions internally
|
||||
set_exception_handler(array(__CLASS__, 'handleException'));
|
||||
|
||||
// Turn off notices
|
||||
error_reporting (E_ALL ^ E_NOTICE);
|
||||
|
||||
// Fix magic quotes
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$func = function ($value) use (&$func) {
|
||||
return is_array($value) ? array_map($func, $value) : stripslashes($value);
|
||||
};
|
||||
$_GET = array_map($func, $_GET);
|
||||
$_POST = array_map($func, $_POST);
|
||||
$_COOKIE = array_map($func, $_COOKIE);
|
||||
}
|
||||
|
||||
// Enable output buffering
|
||||
ob_start();
|
||||
|
||||
$initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoloads classes.
|
||||
*
|
||||
* @param string $class Class name
|
||||
*/
|
||||
public static function autoload($class) {
|
||||
$file = str_replace('\\', '/', str_replace('_', '/', $class)).'.php';
|
||||
$base = (strpos($file, '/') === false) ? __DIR__ : (self::get('flight.lib.path') ?: '.');
|
||||
|
||||
if (file_exists($base.'/'.$file)) {
|
||||
require $base.'/'.$file;
|
||||
}
|
||||
else {
|
||||
throw new Exception('Unable to load file: '.$base.'/'.$file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom error handler.
|
||||
*/
|
||||
public static function handleError($errno, $errstr, $errfile, $errline) {
|
||||
if (in_array($errno, array(E_USER_ERROR, E_RECOVERABLE_ERROR))) {
|
||||
static::error(new ErrorException($errstr, 0, $errno, $errfile, $errline));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom exception handler.
|
||||
*/
|
||||
public static function handleException(Exception $e) {
|
||||
try {
|
||||
static::error($e);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
exit(
|
||||
'<h1>500 Internal Server Error</h1>'.
|
||||
'<h3>'.$ex->getMessage().'</h3>'.
|
||||
'<pre>'.$ex->getTraceAsString().'</pre>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes a URL to a callback function.
|
||||
*
|
||||
* @param string $pattern URL pattern to match
|
||||
* @param callback $callback Callback function
|
||||
*/
|
||||
public static function _route($pattern, $callback) {
|
||||
self::router()->map($pattern, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the framework.
|
||||
*/
|
||||
public static function _start() {
|
||||
// Route the request
|
||||
$result = self::router()->route(self::request());
|
||||
|
||||
if ($result !== false) {
|
||||
list($callback, $params) = $result;
|
||||
|
||||
self::execute($callback, $params);
|
||||
}
|
||||
else {
|
||||
self::notFound();
|
||||
}
|
||||
|
||||
// Disable caching for AJAX requests
|
||||
if (self::request()->isAjax) {
|
||||
self::response()->cache(false);
|
||||
}
|
||||
|
||||
// Allow post-filters to run
|
||||
self::after('start', array(__CLASS__, 'stop'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the framework and outputs the current response.
|
||||
*/
|
||||
public static function _stop() {
|
||||
self::response()->
|
||||
write(ob_get_clean())->
|
||||
send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops processing and returns a given response.
|
||||
*
|
||||
* @param int $code HTTP status code
|
||||
* @param int $msg Response text
|
||||
*/
|
||||
public static function _halt($code = 200, $text = '') {
|
||||
self::response(false)->
|
||||
status($code)->
|
||||
write($text)->
|
||||
cache(false)->
|
||||
send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP 500 response for any errors.
|
||||
*
|
||||
* @param object $ex Exception
|
||||
*/
|
||||
public static function _error(Exception $e) {
|
||||
self::response(false)->
|
||||
status(500)->
|
||||
write(
|
||||
'<h1>500 Internal Server Error</h1>'.
|
||||
'<h3>'.$e->getMessage().'</h3>'.
|
||||
'<pre>'.$e->getTraceAsString().'</pre>'
|
||||
)->
|
||||
send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP 404 response when a URL is not found.
|
||||
*/
|
||||
public static function _notFound() {
|
||||
self::response(false)->
|
||||
status(404)->
|
||||
write(
|
||||
'<h1>404 Not Found</h1>'.
|
||||
'<h3>The page you have requested could not be found.</h3>'.
|
||||
str_repeat(' ', 512)
|
||||
)->
|
||||
send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects the current request to another URL.
|
||||
*
|
||||
* @param string $url URL
|
||||
*/
|
||||
public static function _redirect($url, $code = 303) {
|
||||
self::response(false)->
|
||||
status($code)->
|
||||
header('Location', $url)->
|
||||
write($url)->
|
||||
send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template.
|
||||
*
|
||||
* @param string $file Template file
|
||||
* @param array $data Template data
|
||||
*/
|
||||
public static function _render($file, $data = null) {
|
||||
self::view()->render($file, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ETag HTTP caching.
|
||||
*
|
||||
* @param string $id ETag identifier
|
||||
* @param string $type ETag type
|
||||
*/
|
||||
public static function _etag($id, $type = 'strong') {
|
||||
$id = (($type === 'weak') ? 'W/' : '').$id;
|
||||
|
||||
self::response()->header('ETag', $id);
|
||||
|
||||
if ($_SERVER['HTTP_IF_NONE_MATCH'] === $id) {
|
||||
self::halt(304);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles last modified HTTP caching.
|
||||
*
|
||||
* @param int $time Unix timestamp
|
||||
*/
|
||||
public static function _lastModified($time) {
|
||||
self::response()->header('Last-Modified', date(DATE_RFC1123, $time));
|
||||
|
||||
if (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $time) {
|
||||
self::halt(304);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize framework on include
|
||||
Flight::init();
|
||||
?>
|
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* Flight: an extensible PHP micro-framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php
|
||||
* @version 0.1
|
||||
*/
|
||||
class Request {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config Request configuration
|
||||
*/
|
||||
public function __construct($config = array()) {
|
||||
// Default properties
|
||||
if (empty($config)) {
|
||||
$config = array(
|
||||
'url' => $_SERVER['REQUEST_URI'],
|
||||
'base' => str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])),
|
||||
'method' => $_SERVER['REQUEST_METHOD'],
|
||||
'referrer' => $_SERVER['HTTP_REFERER'],
|
||||
'ipAddress' => $_SERVER['REMOTE_ADDR'],
|
||||
'isAjax' => ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'),
|
||||
'query' => array(),
|
||||
'data' => $_POST,
|
||||
'cookies' => $_COOKIE,
|
||||
'files' => $_FILES
|
||||
);
|
||||
}
|
||||
|
||||
self::init($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize request properties.
|
||||
*
|
||||
* @param array $properties Array of request properties
|
||||
*/
|
||||
public function init($properties) {
|
||||
foreach ($properties as $name => $value) {
|
||||
$this->{$name} = $value;
|
||||
}
|
||||
|
||||
if ($this->base != '/' && strpos($this->url, $this->base) === 0) {
|
||||
$this->url = substr($this->url, strlen($this->base));
|
||||
}
|
||||
|
||||
$this->query = self::parseQuery($this->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse query parameters from a URL.
|
||||
*/
|
||||
public function parseQuery($url) {
|
||||
$params = array();
|
||||
|
||||
$args = parse_url($url);
|
||||
if (isset($args['query'])) {
|
||||
parse_str($args['query'], $params);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
?>
|
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/**
|
||||
* Flight: an extensible PHP micro-framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php
|
||||
* @version 0.1
|
||||
*/
|
||||
class Response {
|
||||
protected $headers = array();
|
||||
protected $status = 200;
|
||||
protected $body;
|
||||
|
||||
public static $codes = array(
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported'
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the HTTP status of the response.
|
||||
*
|
||||
* @param int $code HTTP status code.
|
||||
*/
|
||||
public function status($code) {
|
||||
if (array_key_exists($code, self::$codes)) {
|
||||
if (strpos(php_sapi_name(), 'cgi') !== false) {
|
||||
header('Status: '.$code.' '.self::$codes[$code], true);
|
||||
}
|
||||
else {
|
||||
header(($_SERVER['SERVER_PROTOCOL'] ?: 'HTTP/1.1').' '.self::$codes[$code], true, $code);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Exception('Invalid status code.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a header to the response.
|
||||
*
|
||||
* @param string|array $key Header name or array of names and values
|
||||
* @param string $value Header value
|
||||
*/
|
||||
public function header($name, $value = null) {
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $k => $v) {
|
||||
$this->headers[$k] = $v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->headers[$name] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes content to the response body.
|
||||
*
|
||||
* @param string $str Response content
|
||||
*/
|
||||
public function write($str) {
|
||||
$this->body .= $str;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the response.
|
||||
*/
|
||||
public function clear() {
|
||||
$this->headers = array();
|
||||
$this->status = 200;
|
||||
$this->body = '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets caching headers for the response.
|
||||
*
|
||||
* @param int|string $expires Expiration time
|
||||
*/
|
||||
public function cache($expires) {
|
||||
if ($expires === false) {
|
||||
$this->headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
|
||||
$this->headers['Cache-Control'] = array(
|
||||
'no-store, no-cache, must-revalidate',
|
||||
'post-check=0, pre-check=0',
|
||||
'max-age=0'
|
||||
);
|
||||
$this->headers['Pragma'] = 'no-cache';
|
||||
}
|
||||
else {
|
||||
$expires = is_int($expires) ? $expires : strtotime($expires);
|
||||
$this->headers['Expires'] = gmdate('D, d M Y H:i:s', $expires) . ' GMT';
|
||||
$this->headers['Cache-Control'] = 'max-age='.($expires - time());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the response and exits the program.
|
||||
*/
|
||||
public function send() {
|
||||
ob_end_clean();
|
||||
|
||||
if (!headers_sent()) {
|
||||
foreach ($this->headers as $field => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
header($field.': '.$v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
header($field.': '.$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit($this->body);
|
||||
}
|
||||
}
|
||||
?>
|
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Flight: an extensible PHP micro-framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php
|
||||
* @version 0.1
|
||||
*/
|
||||
class Router {
|
||||
protected $routes = array();
|
||||
|
||||
/**
|
||||
* Maps a URL pattern to a callback function.
|
||||
*
|
||||
* @param string $pattern URL pattern to match
|
||||
* @param callback $callback Callback function
|
||||
*/
|
||||
public function map($pattern, $callback) {
|
||||
list($method, $url) = explode(' ', trim($pattern), 2);
|
||||
|
||||
if (!is_null($url)) {
|
||||
foreach (explode('|', $method) as $value) {
|
||||
$this->routes[$value][$url] = $callback;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->routes['*'][$pattern] = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to match a requst to a route. Also parses named parameters in the url.
|
||||
*
|
||||
* @param string $pattern URL pattern
|
||||
* @param object $request Request object
|
||||
*/
|
||||
public function match($pattern, $url, array &$params = array()) {
|
||||
$ids = array();
|
||||
|
||||
// Build the regex for matching
|
||||
$regex = '/^'.implode('\/', array_map(
|
||||
function($str) use (&$ids){
|
||||
if ($str == '*') {
|
||||
$str = '(.*)';
|
||||
}
|
||||
else if (@$str{0} == '@') {
|
||||
if (preg_match('/@(\w+)(\:([^\/]*))?/', $str, $matches)) {
|
||||
$ids[$matches[1]] = true;
|
||||
return '(?P<'.$matches[1].'>'.(isset($matches[3]) ? $matches[3] : '[^(\/|\?)]*').')';
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
},
|
||||
explode('/', $pattern)
|
||||
)).'\/?(?:\?.*)?$/i';
|
||||
|
||||
// Attempt to match route and named parameters
|
||||
if (preg_match($regex, $url, $matches)) {
|
||||
if (!empty($ids)) {
|
||||
$params = array_intersect_key($matches, $ids);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes the current request.
|
||||
*
|
||||
* @param object $request Request object
|
||||
*/
|
||||
public function route(&$request) {
|
||||
$params = array();
|
||||
$routes = $this->routes[$request->method] + ($this->routes['*'] ?: array());
|
||||
|
||||
foreach ($routes as $pattern => $callback) {
|
||||
if ($request->url === $pattern || self::match($pattern, $request->url, $params)) {
|
||||
$request->matched = $pattern;
|
||||
return array($callback, array($params));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets mapped routes.
|
||||
*
|
||||
* @return array Array of routes
|
||||
*/
|
||||
public function getRoutes() {
|
||||
return $this->routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the router.
|
||||
*/
|
||||
public function clear() {
|
||||
$this->routes = array();
|
||||
}
|
||||
}
|
||||
?>
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* Flight: an extensible PHP micro-framework.
|
||||
*
|
||||
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
|
||||
* @license http://www.opensource.org/licenses/mit-license.php
|
||||
* @version 0.1
|
||||
*/
|
||||
class View {
|
||||
protected $templatePath;
|
||||
|
||||
public function __construct($templatePath = null) {
|
||||
$this->templatePath = $templatePath ?: './views';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template.
|
||||
*
|
||||
* @param string $file Template file
|
||||
* @param array $data Template data
|
||||
*/
|
||||
public function render($file, $data = null) {
|
||||
// Bind template data to view
|
||||
if (!is_null($data)) {
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
else if (is_object($data)) {
|
||||
foreach (get_object_vars($data) as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display template
|
||||
include $this->templatePath.'/'.((substr($file,-4) == '.php') ? $file : $file.'.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output of a template.
|
||||
*
|
||||
* @param string $file Template file
|
||||
* @param array $data Template data
|
||||
*/
|
||||
public function fetch($file, $data = null) {
|
||||
ob_start();
|
||||
|
||||
$this->render($file, $data);
|
||||
$output = ob_get_contents();
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays escaped output.
|
||||
*
|
||||
* @param string $str String to escape
|
||||
*/
|
||||
public function e($str) {
|
||||
echo htmlentities($str);
|
||||
}
|
||||
}
|
||||
?>
|
Loading…
Reference in new issue