PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/pkp/classes/core/Dispatcher.inc.php

https://github.com/lib-uoguelph-ca/ocs
PHP | 248 lines | 107 code | 38 blank | 103 comment | 20 complexity | 8130c1754908828eae239a17a561666d MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * @file classes/core/Dispatcher.inc.php
  4. *
  5. * Copyright (c) 2000-2012 John Willinsky
  6. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  7. *
  8. * @class Dispatcher
  9. * @ingroup core
  10. *
  11. * @brief Class dispatching HTTP requests to handlers.
  12. */
  13. // $Id$
  14. class Dispatcher {
  15. /** @var PKPApplication */
  16. var $_application;
  17. /** @var array an array of Router implementation class names */
  18. var $_routerNames = array();
  19. /** @var array an array of Router instances */
  20. var $_routerInstances = array();
  21. /** @var PKPRouter */
  22. var $_router;
  23. /**
  24. * Get the application
  25. * @return PKPApplication
  26. */
  27. function &getApplication() {
  28. return $this->_application;
  29. }
  30. /**
  31. * Set the application
  32. * @param $application PKPApplication
  33. */
  34. function setApplication(&$application) {
  35. $this->_application =& $application;
  36. }
  37. /**
  38. * Get the router names
  39. * @return array an array of Router names
  40. */
  41. function &getRouterNames() {
  42. return $this->_routerNames;
  43. }
  44. /**
  45. * Add a router name.
  46. *
  47. * NB: Routers will be called in the order that they
  48. * have been added to the dispatcher. The first router
  49. * that supports the request will be called. The last
  50. * router should always be a "catch-all" router that
  51. * supports all types of requests.
  52. *
  53. * NB: Routers must be part of the core package
  54. * to be accepted by this dispatcher implementation.
  55. *
  56. * @param $routerName string a class name of a router
  57. * to be given the chance to route the request.
  58. * NB: These are class names and not instantiated objects. We'll
  59. * use lazy instantiation to reduce the performance/memory impact
  60. * to a minimum.
  61. * @param $shortcut string a shortcut name for the router
  62. * to be used for quick router instance retrieval.
  63. */
  64. function addRouterName($routerName, $shortcut) {
  65. assert(is_array($this->_routerNames) && is_string($routerName));
  66. $this->_routerNames[$shortcut] = $routerName;
  67. }
  68. /**
  69. * Determine the correct router for this request. Then
  70. * let the router dispatch the request to the appropriate
  71. * handler method.
  72. * @param $request PKPRequest
  73. */
  74. function dispatch(&$request) {
  75. // Make sure that we have at least one router configured
  76. $routerNames = $this->getRouterNames();
  77. assert(count($routerNames) > 0);
  78. // Go through all configured routers by priority
  79. // and find out whether one supports the incoming request
  80. foreach($routerNames as $shortcut => $routerCandidateName) {
  81. $routerCandidate =& $this->_instantiateRouter($routerCandidateName, $shortcut);
  82. // Does this router support the current request?
  83. if ($routerCandidate->supports($request)) {
  84. // Inject router into request
  85. $request->setRouter($routerCandidate);
  86. $router =& $routerCandidate;
  87. $this->_router =& $router;
  88. // We've found our router and can go on
  89. // to handle the request.
  90. break;
  91. }
  92. }
  93. // None of the router handles this request? This is a development-time
  94. // configuration error.
  95. if (is_null($router)) fatalError('None of the configured routers supports this request.');
  96. // Can we serve a cached response?
  97. if ($router->isCacheable($request)) {
  98. if (Config::getVar('cache', 'web_cache')) {
  99. if ($this->_displayCached($router, $request)) exit(); // Success
  100. ob_start(array(&$this, '_cacheContent'));
  101. }
  102. } else {
  103. if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
  104. header('HTTP/1.0 403 Forbidden');
  105. echo '403: Forbidden<br><br>Pre-fetching not allowed.';
  106. exit;
  107. }
  108. }
  109. AppLocale::initialize();
  110. PluginRegistry::loadCategory('generic');
  111. $router->route($request);
  112. }
  113. /**
  114. * Build a handler request URL into PKPApplication.
  115. * @param $request PKPRequest the request to be routed
  116. * @param $shortcut the short name of the router that should be used to construct the URL
  117. * @param $newContext mixed Optional contextual paths
  118. * @param $handler string Optional name of the handler to invoke
  119. * @param $op string Optional name of operation to invoke
  120. * @param $path mixed Optional string or array of args to pass to handler
  121. * @param $params array Optional set of name => value pairs to pass as user parameters
  122. * @param $anchor string Optional name of anchor to add to URL
  123. * @param $escape boolean Whether or not to escape ampersands for this URL; default false.
  124. * @return string the URL
  125. */
  126. function url(&$request, $shortcut, $newContext = null, $handler = null, $op = null, $path = null,
  127. $params = null, $anchor = null, $escape = false) {
  128. // Instantiate the requested router
  129. assert(isset($this->_routerNames[$shortcut]));
  130. $routerName = $this->_routerNames[$shortcut];
  131. $router =& $this->_instantiateRouter($routerName, $shortcut);
  132. return $router->url($request, $newContext, $handler, $op, $path, $params, $anchor, $escape);
  133. }
  134. //
  135. // Private helper methods
  136. //
  137. /**
  138. * Instantiate a router
  139. * @param $routerName string
  140. * @param $shortcut string
  141. */
  142. function &_instantiateRouter($routerName, $shortcut) {
  143. if (!isset($this->_routerInstances[$shortcut])) {
  144. $routerParts = explode('.', $routerName);
  145. // Routers must belong to the core package
  146. // NB: This prevents code inclusion attacks.
  147. if (count($routerParts) != 2 || $routerParts[0] != 'core') {
  148. fatalError('Routers must belong to the core package.');
  149. }
  150. $routerClass = $routerParts[1];
  151. // Instantiate the router
  152. import($routerName);
  153. $router = new $routerClass();
  154. assert(is_a($router, 'PKPRouter'));
  155. $router->setApplication($this->_application);
  156. $router->setDispatcher($this);
  157. // Save the router instance for later re-use
  158. $this->_routerInstances[$shortcut] =& $router;
  159. }
  160. return $this->_routerInstances[$shortcut];
  161. }
  162. /**
  163. * Display the request contents from cache.
  164. * @param $router PKPRouter
  165. */
  166. function _displayCached(&$router, &$request) {
  167. $filename = $router->getCacheFilename($request);
  168. if (!file_exists($filename)) return false;
  169. // Allow a caching proxy to work its magic if possible
  170. $ifModifiedSince = $request->getIfModifiedSince();
  171. if ($ifModifiedSince !== null && $ifModifiedSince >= filemtime($filename)) {
  172. header('HTTP/1.1 304 Not Modified');
  173. exit();
  174. }
  175. $fp = fopen($filename, 'r');
  176. $data = fread($fp, filesize($filename));
  177. fclose($fp);
  178. $i = strpos($data, ':');
  179. $time = substr($data, 0, $i);
  180. $contents = substr($data, $i+1);
  181. if (mktime() > $time + Config::getVar('cache', 'web_cache_hours') * 60 * 60) return false;
  182. header('Content-Type: text/html; charset=' . Config::getVar('i18n', 'client_charset'));
  183. echo $contents;
  184. return true;
  185. }
  186. /**
  187. * Cache content as a local file.
  188. * @param $contents string
  189. * @return string
  190. */
  191. function _cacheContent($contents) {
  192. assert(is_a($this->_router, 'PKPRouter'));
  193. $filename = $this->_router->getCacheFilename();
  194. $fp = fopen($filename, 'w');
  195. if ($fp) {
  196. fwrite($fp, mktime() . ':' . $contents);
  197. fclose($fp);
  198. }
  199. return $contents;
  200. }
  201. /**
  202. * Handle a 404 error (page not found).
  203. */
  204. function handle404() {
  205. PKPRequest::_checkThis();
  206. header('HTTP/1.0 404 Not Found');
  207. fatalError('404 Not Found');
  208. }
  209. }
  210. ?>