PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/core/Rack.php

https://github.com/llambeau/rack-php
PHP | 141 lines | 91 code | 23 blank | 27 comment | 4 complexity | 431ea2fb312689989f0fd9284464fbd8 MD5 | raw file
  1. <?
  2. namespace core;
  3. class Rack
  4. {
  5. private static $middleware = array();
  6. // This converts the native PHP $_SERVER array into a rack hash and then removes the contents of
  7. // the $_SERVER variable. This ensures loose coupling and allows for middleware and mock requests.
  8. protected static function get_env()
  9. {
  10. // This is modeled after the Rack standard <http://rack.rubyforge.org/doc/SPEC.html>
  11. $script_name = dirname($_SERVER['SCRIPT_NAME']);
  12. $full_info = str_replace($script_name, '', $_SERVER['REQUEST_URI']);
  13. $p = strpos($full_info, '?');
  14. if ($p === false) $p = strlen($full_info);
  15. $env = array(
  16. // The HTTP request method, such as “GET” or “POST”. This cannot ever be an empty string, and
  17. // so is always required.
  18. 'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'],
  19. // The initial portion of the request URL’s “path” that corresponds to the application object,
  20. // so that the application knows its virtual “location”. This may be an empty string, if the
  21. // application corresponds to the “root” of the server.
  22. 'SCRIPT_NAME' => $script_name,
  23. // The remainder of the request URL’s “path”, designating the virtual “location” of the
  24. // request’s target within the application. This may be an empty string, if the request URL
  25. // targets the application root and does not have a trailing slash. This value may be
  26. // percent-encoded when I originating from a URL.
  27. 'PATH_INFO' => substr($full_info, 0, $p),
  28. // The portion of the request URL that follows the ?, if any. May be empty, but is always required!
  29. 'QUERY_STRING' => substr($full_info, $p+1),
  30. // When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to complete the
  31. // URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME
  32. // for reconstructing the request URL. SERVER_NAME and SERVER_PORT can never be empty strings,
  33. // and so are always required.
  34. 'SERVER_NAME' => $_SERVER['SERVER_NAME'],
  35. 'SERVER_PORT' => $_SERVER['SERVER_PORT'],
  36. // rack.version must be an array of Integers.
  37. 'rack.version' => array(1,0),
  38. // rack.url_scheme must either be http or https.
  39. 'rack.url_scheme' => (@$_SERVER['HTTPS'] ? 'https' : 'http'),
  40. // There must be a valid input stream in rack.input.
  41. 'rack.input' => fopen('php://input', 'r'),
  42. // There must be a valid error stream in rack.errors.
  43. 'rack.errors' => fopen('php://stderr', 'w'),
  44. 'rack.multithread' => false,
  45. 'rack.multiprocess' => false,
  46. 'rack.run_once' => false,
  47. );
  48. // HTTP_ Variables:
  49. // Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose
  50. // names begin with HTTP_). The presence or absence of these variables should correspond with
  51. // the presence or absence of the appropriate HTTP header in the request.
  52. //
  53. // Also include the rest just for fun and clear out $_SERVER.
  54. foreach(array_keys($_SERVER) as $key)
  55. {
  56. if (!array_key_exists($key, $env))
  57. {
  58. $env[$key] = $_SERVER[$key];
  59. }
  60. unset($_SERVER[$key]);
  61. }
  62. return $env;
  63. }
  64. public static function run($app)
  65. {
  66. $env =& static::get_env();
  67. ob_start();
  68. $result = self::runMiddleware($app, $env);
  69. $output = ob_get_clean();
  70. if ($output)
  71. {
  72. $result[1]["X-Output"] = json_encode($output);
  73. }
  74. static::execute($result, $env);
  75. }
  76. private static function execute($result, $env)
  77. {
  78. list($status, $headers, $body) = $result;
  79. fclose($env['rack.input']);
  80. fclose($env['rack.errors']);
  81. $headers['X-Powered-By'] = "rack-php ".implode('.',$env['rack.version']);
  82. $headers['Status'] = $status;
  83. foreach($headers as $key=>$value)
  84. {
  85. header("$key: $value");
  86. }
  87. foreach($body as $section)
  88. {
  89. print $section;
  90. }
  91. exit;
  92. }
  93. public static function runMiddleware($inner_app, $env)
  94. {
  95. self::$middleware = array_reverse(self::$middleware);
  96. self::useMiddleware('core\ShowExceptions');
  97. if (!empty(self::$middleware)) {
  98. foreach (self::$middleware as $app) {
  99. $inner_app = $app($inner_app);
  100. }
  101. }
  102. return $inner_app($env);
  103. }
  104. public static function useMiddleware($middleware, $options = array())
  105. {
  106. array_push(self::$middleware, function ($app) use ($middleware, $options) {
  107. return new $middleware($app, $options);
  108. });
  109. }
  110. public static function clearMiddleware()
  111. {
  112. self::$middleware = array();
  113. }
  114. public static function middleware()
  115. {
  116. return self::$middleware;
  117. }
  118. }