/lib/core/Rack.php
PHP | 141 lines | 91 code | 23 blank | 27 comment | 4 complexity | 431ea2fb312689989f0fd9284464fbd8 MD5 | raw file
- <?
- namespace core;
- class Rack
- {
- private static $middleware = array();
-
- // This converts the native PHP $_SERVER array into a rack hash and then removes the contents of
- // the $_SERVER variable. This ensures loose coupling and allows for middleware and mock requests.
- protected static function get_env()
- {
- // This is modeled after the Rack standard <http://rack.rubyforge.org/doc/SPEC.html>
- $script_name = dirname($_SERVER['SCRIPT_NAME']);
- $full_info = str_replace($script_name, '', $_SERVER['REQUEST_URI']);
- $p = strpos($full_info, '?');
- if ($p === false) $p = strlen($full_info);
- $env = array(
- // The HTTP request method, such as “GET” or “POST”. This cannot ever be an empty string, and
- // so is always required.
- 'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'],
-
- // The initial portion of the request URL’s “path” that corresponds to the application object,
- // so that the application knows its virtual “location”. This may be an empty string, if the
- // application corresponds to the “root” of the server.
- 'SCRIPT_NAME' => $script_name,
-
- // The remainder of the request URL’s “path”, designating the virtual “location” of the
- // request’s target within the application. This may be an empty string, if the request URL
- // targets the application root and does not have a trailing slash. This value may be
- // percent-encoded when I originating from a URL.
- 'PATH_INFO' => substr($full_info, 0, $p),
-
- // The portion of the request URL that follows the ?, if any. May be empty, but is always required!
- 'QUERY_STRING' => substr($full_info, $p+1),
-
- // When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the
- // URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME
- // for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings,
- // and so are always required.
- 'SERVER_NAME' => $_SERVER['SERVER_NAME'],
- 'SERVER_PORT' => $_SERVER['SERVER_PORT'],
-
- // rack.version must be an array of Integers.
- 'rack.version' => array(1,0),
-
- // rack.url_scheme must either be http or https.
- 'rack.url_scheme' => (@$_SERVER['HTTPS'] ? 'https' : 'http'),
- // There must be a valid input stream in rack.input.
- 'rack.input' => fopen('php://input', 'r'),
- // There must be a valid error stream in rack.errors.
- 'rack.errors' => fopen('php://stderr', 'w'),
- 'rack.multithread' => false,
- 'rack.multiprocess' => false,
- 'rack.run_once' => false,
- );
- // HTTP_ Variables:
- // Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose
- // names begin with HTTP_). The presence or absence of these variables should correspond with
- // the presence or absence of the appropriate HTTP header in the request.
- //
- // Also include the rest just for fun and clear out $_SERVER.
- foreach(array_keys($_SERVER) as $key)
- {
- if (!array_key_exists($key, $env))
- {
- $env[$key] = $_SERVER[$key];
- }
- unset($_SERVER[$key]);
- }
-
- return $env;
- }
-
- public static function run($app)
- {
- $env =& static::get_env();
- ob_start();
- $result = self::runMiddleware($app, $env);
- $output = ob_get_clean();
-
- if ($output)
- {
- $result[1]["X-Output"] = json_encode($output);
- }
- static::execute($result, $env);
- }
-
- private static function execute($result, $env)
- {
- list($status, $headers, $body) = $result;
- fclose($env['rack.input']);
- fclose($env['rack.errors']);
- $headers['X-Powered-By'] = "rack-php ".implode('.',$env['rack.version']);
- $headers['Status'] = $status;
- foreach($headers as $key=>$value)
- {
- header("$key: $value");
- }
- foreach($body as $section)
- {
- print $section;
- }
- exit;
- }
-
- public static function runMiddleware($inner_app, $env)
- {
- self::$middleware = array_reverse(self::$middleware);
- self::useMiddleware('core\ShowExceptions');
-
- if (!empty(self::$middleware)) {
- foreach (self::$middleware as $app) {
- $inner_app = $app($inner_app);
- }
- }
- return $inner_app($env);
- }
-
- public static function useMiddleware($middleware, $options = array())
- {
- array_push(self::$middleware, function ($app) use ($middleware, $options) {
- return new $middleware($app, $options);
- });
- }
-
- public static function clearMiddleware()
- {
- self::$middleware = array();
- }
-
- public static function middleware()
- {
- return self::$middleware;
- }
- }