blob: 48cdbc690d91b42964c1ba786de6f1b6820723b3 [file] [log] [blame]
<?php
/*
* SimpleWeb
*
* Copyright (C) Kelvin Mo 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/**
* Simpleweb is a minimalist web framework. It is similar to {@link http://webpy.org web.py},
* but in PHP.
*
* The key to Simpleweb is the <i>route array</i>. The route array is an array that maps
* URLs (called <i>patterns</i>) to PHP functions or methods (called <i>routes</i>).
*
* Patterns are regular expressions, which are tested against the URL one at a time.
* Subpatterns (i.e. patterns within parentheses) are then passed on as arguments
* to the route.
*
* Routes are either functions, static methods or object methods. A function is
* denoted by the function name. A static method is denoted by the class name,
* followed by :: then the method name. An object method is denoted by the class
* name, followed by -&gt; then the method name. An instance of the class will be
* created before an object method is called.
*
* An example of a routes array is given below:
*
* <code>
* <?php
* $routes = array(
* 'a' => 'function1',
* 'b/(.+)' => 'function2', // arguments
* 'c' => 'ClassA::method', // static method
* 'd' => 'ClassB->method', // object method
* );
* ?>
* </code>
*
* Once the route array is populated, the {@link simpleweb_run()} function
* is then called to handle the URL.
*
* @package simpleweb
* @since 0.7
*/
/**
* Handles a supplied request, based on a set of routes.
*
* @param array $routes the routes array, as described in {@link simpleweb.inc this page}
* @param string $request_path the request path against which the routes are applied. If
* NULL, then the request URI supplied by the web server will be used.
* @param string $not_found_route the default route if none of the patterns match. If
* NULL, then an HTTP 404 error is raised
* @return mixed the result from calling the route.
*
*/
function simpleweb_run($routes, $request_path = NULL, $not_found_route = NULL) {
if ($request_path == NULL) {
// We take the request path from the request URI
$request_path = $_SERVER['REQUEST_URI'];
// Strip off all parts to the script file name. Sadly, PHP is historically
// buggy in its treatment of SCRIPT_NAME, so we need to try a few methods
// to strip them
$script_name = basename($_SERVER['SCRIPT_NAME']);
$script_dir = dirname($_SERVER['SCRIPT_NAME']);
if (strpos($request_path, $script_name) !== false) {
$request_path = substr($request_path, strpos($request_path, $script_name) + strlen($script_name));
} elseif ($script_dir != '/') {
$request_path = str_replace($script_dir, '', $request_path);
}
$request_path = trim($request_path, '/');
}
// Strip off GET parameters when passed in SAPI CGI mode
$request_path = strtok($request_path, '?');
foreach ($routes as $pattern => $route) {
if (!isset($route)) continue;
$regex = '#^' . trim($pattern, '/') . '$#i';
if (!preg_match($regex, $request_path, $args) > 0) continue;
$args = (count($args) > 1) ? array_slice($args, 1) : array();
return _simpleweb_invoke($route, $args);
}
if ($not_found_route) return _simpleweb_invoke($not_found_route, array($request_path));
_simpleweb_not_found();
}
/**
* Invokes a route.
*
* @param string $route the route
* @param array $args the arguments
* @return mixed the result from calling the route.
*/
function _simpleweb_invoke($route, $args = array()) {
if (strpos($route, '::') !== false) {
list($class, $method) = split($route, '::', 2);
return call_user_func_array(array($class, $method), $args);
} elseif(strpos($route, '->') !== false) {
list($class, $method) = split($route, '->', 2);
$object &= new $class;
return call_user_func_array(array($object, $method), $args);
} else {
return call_user_func_array($route, $args);
}
}
/**
* Displays a HTTP 404 Not Found error and exits.
*/
function _simpleweb_not_found() {
switch ($_SERVER['REDIRECT_STATUS']) {
case '403':
$status = '403 Forbidden';
break;
case '404':
default:
$status = '404 Not Found';
break;
}
if (substr(PHP_SAPI, 0, 3) === 'cgi') {
header('Status: ' . $status);
} else {
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $status);
}
header('Content-Type: text/html');
print '<!doctype html><html><head><title>' . $status . '</title></head><body><h1>' . $status . '</h1></body></html>';
exit;
}
?>