PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/php/Genghis/App.php

https://github.com/bobthecow/genghis
PHP | 210 lines | 169 code | 33 blank | 8 comment | 35 complexity | f07e574a59f7a26ca848671bc6336e5a MD5 | raw file
  1. <?php
  2. class Genghis_App
  3. {
  4. protected $loader;
  5. protected $baseUrl;
  6. public function __construct(Genghis_AssetLoader $loader)
  7. {
  8. $this->loader = $loader;
  9. }
  10. public function run()
  11. {
  12. set_error_handler(array('Genghis_ErrorException', 'throwException'));
  13. try {
  14. $response = $this->route($this->getRequestMethod(), $this->getRequestPath());
  15. if ($response instanceof Genghis_Response) {
  16. $response->render();
  17. } else {
  18. throw new Genghis_HttpException(500);
  19. }
  20. } catch (Genghis_HttpException $e) {
  21. $this->errorResponse($e->getMessage(), $e->getStatus())->render();
  22. } catch (Exception $e) {
  23. $this->errorResponse($e->getMessage())->render();
  24. }
  25. }
  26. public function route($method, $path)
  27. {
  28. if ($this->isJsonRequest() || $this->isGridFsRequest()) {
  29. return $this->getApi()->route($method, $path);
  30. } elseif ($this->isAssetRequest($path)) {
  31. return $this->getAsset(substr($path, 8));
  32. } else {
  33. // not an api request, we'll return index.html and render the page in javascript.
  34. return $this->renderTemplate('index.html.mustache');
  35. }
  36. }
  37. protected function isJsonRequest()
  38. {
  39. if (in_array($this->getRequestMethod(), array('POST', 'PUT'))) {
  40. if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
  41. $type = $_SERVER['HTTP_CONTENT_TYPE'];
  42. } elseif (array_key_exists('CONTENT_TYPE', $_SERVER)) {
  43. $type = $_SERVER['CONTENT_TYPE'];
  44. } else {
  45. $type = 'x-www-form-urlencoded';
  46. }
  47. } else {
  48. $type = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : 'text/html';
  49. }
  50. return strpos($type, 'application/json') !== false || strpos($type, 'application/javascript') !== false;
  51. }
  52. protected function isGridFsRequest()
  53. {
  54. return $this->getRequestMethod() == 'GET' && preg_match(Genghis_Api::GRIDFS_ROUTE, $this->getRequestPath());
  55. }
  56. protected function isAssetRequest($path)
  57. {
  58. return (strpos($path, '/assets/') === 0);
  59. }
  60. protected function getBaseUrl()
  61. {
  62. if (!isset($this->baseUrl)) {
  63. $this->baseUrl = $this->prepareBaseUrl();
  64. }
  65. return $this->baseUrl;
  66. }
  67. protected function prepareBaseUrl()
  68. {
  69. $filename = basename($_SERVER['SCRIPT_FILENAME']);
  70. foreach (array('SCRIPT_NAME', 'PHP_SELF', 'ORIG_SCRIPT_NAME') as $key) {
  71. if (isset($_SERVER[$key]) && basename($_SERVER[$key]) == $filename) {
  72. $baseUrl = $_SERVER[$key];
  73. break;
  74. }
  75. }
  76. if (!isset($baseUrl)) {
  77. $path = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '';
  78. $file = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : '';
  79. $chunks = array_reverse(explode('/', trim($file, '/')));
  80. $index = 0;
  81. $last = count($chunks);
  82. $baseUrl = '';
  83. do {
  84. $seg = $chunks[$index];
  85. $baseUrl = '/'.$seg.$baseUrl;
  86. ++$index;
  87. } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
  88. }
  89. // Does the baseUrl have anything in common with the request_uri?
  90. $requestUri = $_SERVER['REQUEST_URI'];
  91. if ($baseUrl && 0 === strpos($requestUri, $baseUrl)) {
  92. // full $baseUrl matches
  93. return $baseUrl;
  94. }
  95. if ($baseUrl && 0 === strpos($requestUri, dirname($baseUrl))) {
  96. // directory portion of $baseUrl matches
  97. return rtrim(dirname($baseUrl), '/');
  98. }
  99. $truncatedRequestUri = $requestUri;
  100. if (($pos = strpos($requestUri, '?')) !== false) {
  101. $truncatedRequestUri = substr($requestUri, 0, $pos);
  102. }
  103. $basename = basename($baseUrl);
  104. if (empty($basename) || !strpos($truncatedRequestUri, $basename)) {
  105. // no match whatsoever; set it blank
  106. return '';
  107. }
  108. // If using mod_rewrite or ISAPI_Rewrite strip the script filename
  109. // out of baseUrl. $pos !== 0 makes sure it is not matching a value
  110. // from PATH_INFO or QUERY_STRING
  111. if ((strlen($requestUri) >= strlen($baseUrl)) && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) {
  112. $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
  113. }
  114. return rtrim($baseUrl, '/');
  115. }
  116. protected function getRequestMethod()
  117. {
  118. return $_SERVER['REQUEST_METHOD'];
  119. }
  120. protected function getRequestPath()
  121. {
  122. if (isset($_SERVER['PATH_INFO'])) {
  123. return $_SERVER['PATH_INFO'];
  124. } elseif (isset($_SERVER['REQUEST_URI'])) {
  125. return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
  126. } else {
  127. return '/';
  128. }
  129. }
  130. protected function getQueryParams()
  131. {
  132. global $_GET;
  133. return $_GET;
  134. }
  135. protected function getQueryParam($name, $default = null)
  136. {
  137. $params = $this->getQueryParams();
  138. if (isset($params[$name])) {
  139. return $params[$name];
  140. } else {
  141. return $default;
  142. }
  143. }
  144. protected function renderTemplate($name, $status = 200, array $vars = array())
  145. {
  146. $tpl = $this->loader->loadRaw($name);
  147. $defaults = array(
  148. 'base_url' => $this->getBaseUrl(),
  149. 'genghis_version' => GENGHIS_VERSION,
  150. );
  151. return new Genghis_Response(strtr($tpl, $this->prepareVars(array_merge($defaults, $vars))), $status);
  152. }
  153. protected function prepareVars($vars)
  154. {
  155. $ret = array();
  156. foreach ($vars as $name => $var) {
  157. $ret['{{ '.$name.' }}'] = $var;
  158. }
  159. return $ret;
  160. }
  161. protected function getAsset($name)
  162. {
  163. try {
  164. return $this->loader->load($name);
  165. } catch (InvalidArgumentException $e) {
  166. throw new Genghis_HttpException(404);
  167. }
  168. }
  169. protected function getApi()
  170. {
  171. return new Genghis_Api;
  172. }
  173. protected function errorResponse($message, $status = 500)
  174. {
  175. return $this->renderTemplate('error.html.mustache', $status, compact('message', 'status'));
  176. }
  177. }