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

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

https://github.com/lib-uoguelph-ca/ocs
PHP | 417 lines | 222 code | 45 blank | 150 comment | 66 complexity | 9501b0dcc1f3f7e68827f50c5f48fc0e MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * @file classes/core/PKPPageRouter.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 PKPPageRouter
  9. * @ingroup core
  10. *
  11. * @brief Class mapping an HTTP request to a handler or context.
  12. */
  13. // $Id$
  14. define('ROUTER_DEFAULT_PAGE', 'pages/index/index.php');
  15. define('ROUTER_DEFAULT_OP', 'index');
  16. import('core.PKPRouter');
  17. class PKPPageRouter extends PKPRouter {
  18. /** @var array pages that don't need an installed system to be displayed */
  19. var $_installationPages = array('install', 'help');
  20. //
  21. // Internal state cache variables
  22. // NB: Please do not access directly but
  23. // only via their respective getters/setters
  24. //
  25. /** @var string the requested page */
  26. var $_page;
  27. /** @var string the requested operation */
  28. var $_op;
  29. /** @var string index url */
  30. var $_indexUrl;
  31. /** @var string cache filename */
  32. var $_cacheFilename;
  33. /**
  34. * get the installation pages
  35. * @return array
  36. */
  37. function getInstallationPages() {
  38. return $this->_installationPages;
  39. }
  40. /**
  41. * get the cacheable pages
  42. * @return array
  43. */
  44. function getCacheablePages() {
  45. // Can be overridden by sub-classes.
  46. return array();
  47. }
  48. /**
  49. * Determine whether or not the request is cacheable.
  50. * @param $request PKPRequest
  51. * @return boolean
  52. */
  53. function isCacheable(&$request) {
  54. if (defined('SESSION_DISABLE_INIT')) return false;
  55. if (!Config::getVar('general', 'installed')) return false;
  56. if (!empty($_POST) || Validation::isLoggedIn()) return false;
  57. if ($request->isPathInfoEnabled()) {
  58. if (!empty($_GET)) return false;
  59. } else {
  60. $application =& $this->getApplication();
  61. $ok = array_merge($application->getContextList(), array('page', 'op', 'path'));
  62. if (!empty($_GET) && count(array_diff(array_keys($_GET), $ok)) != 0) {
  63. return false;
  64. }
  65. }
  66. if (in_array($this->getRequestedPage($request), $this->getCacheablePages())) return true;
  67. return false;
  68. }
  69. /**
  70. * Get the filename to use for cached content for the current request.
  71. * @param $request PKPRequest
  72. * @return string
  73. */
  74. function getCacheFilename(&$request) {
  75. if (!isset($this->_cacheFilename)) {
  76. if ($request->isPathInfoEnabled()) {
  77. $id = isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'index';
  78. $id .= '-' . AppLocale::getLocale();
  79. } else {
  80. $id = '';
  81. $application =& $this->getApplication();
  82. foreach($application->getContextList() as $contextName) {
  83. $id .= $request->getUserVar($contextName) . '-';
  84. }
  85. $id .= $request->getUserVar('page') . '-' . $request->getUserVar('op') . '-' . $request->getUserVar('path') . '-' . AppLocale::getLocale();
  86. }
  87. $path = dirname(INDEX_FILE_LOCATION);
  88. $this->_cacheFilename = $path . '/cache/wc-' . md5($id) . '.html';
  89. }
  90. return $this->_cacheFilename;
  91. }
  92. /**
  93. * Routes the given request to a page handler
  94. * @param $request PKPRequest
  95. */
  96. function route(&$request) {
  97. // Determine the requested page and operation
  98. $page = $this->getRequestedPage($request);
  99. $op = $this->getRequestedOp($request);
  100. // If the application has not yet been installed we only
  101. // allow installer pages to be displayed.
  102. if (!Config::getVar('general', 'installed')) {
  103. define('SESSION_DISABLE_INIT', 1);
  104. if (!in_array($page, $this->getInstallationPages())) {
  105. // A non-installation page was called although
  106. // the system is not yet installed. Redirect to
  107. // the installation page.
  108. $redirectMethod = array($request, 'redirect');
  109. // The correct redirection for the installer page
  110. // depends on the context depth of this application.
  111. $application =& $this->getApplication();
  112. $contextDepth = $application->getContextDepth();
  113. // The context will be filled with all nulls
  114. $redirectArguments = array_pad(array('install'), - $contextDepth - 1, null);
  115. // Call request's redirect method
  116. call_user_func_array($redirectMethod, $redirectArguments);
  117. }
  118. }
  119. // Determine the page index file. This file contains the
  120. // logic to resolve a page to a specific handler class.
  121. $sourceFile = sprintf('pages/%s/index.php', $page);
  122. // If a hook has been registered to handle this page, give it the
  123. // opportunity to load required resources and set HANDLER_CLASS.
  124. if (!HookRegistry::call('LoadHandler', array(&$page, &$op, &$sourceFile))) {
  125. if (file_exists($sourceFile) || file_exists('lib/pkp/'.$sourceFile)) require($sourceFile);
  126. elseif (empty($page)) require(ROUTER_DEFAULT_PAGE);
  127. else {
  128. $dispatcher =& $this->getDispatcher();
  129. $dispatcher->handle404();
  130. }
  131. }
  132. if (!defined('SESSION_DISABLE_INIT')) {
  133. // Initialize session
  134. $sessionManager =& SessionManager::getManager();
  135. }
  136. // Call the selected handler's index operation if
  137. // no operation was defined in the request.
  138. if (empty($op)) $op = ROUTER_DEFAULT_OP;
  139. // Redirect to 404 if the operation doesn't exist
  140. // for the handler.
  141. $methods = array_map('strtolower', get_class_methods(HANDLER_CLASS));
  142. if (!in_array(strtolower($op), $methods)) {
  143. $dispatcher =& $this->getDispatcher();
  144. $dispatcher->handle404();
  145. }
  146. // Instantiate the handler class
  147. $HandlerClass = HANDLER_CLASS;
  148. $handler = new $HandlerClass($request);
  149. // Pass the dispatcher to the handler (if supported by the handler).
  150. if (in_array('setdispatcher', $methods)) $handler->setDispatcher($this->getDispatcher());
  151. // Route the request to the handler operation
  152. $handler->$op($this->getRequestedArgs($request), $request);
  153. }
  154. /**
  155. * Get the page requested in the URL.
  156. * @param $request PKPRequest the request to be routed
  157. * @return String the page path (under the "pages" directory)
  158. */
  159. function getRequestedPage(&$request) {
  160. assert(is_a($request->getRouter(), 'PKPPageRouter'));
  161. if (!isset($this->_page)) {
  162. if ($request->isPathInfoEnabled()) {
  163. $application = $this->getApplication();
  164. $contextDepth = $application->getContextDepth();
  165. if (isset($_SERVER['PATH_INFO'])) {
  166. $vars = explode('/', trim($_SERVER['PATH_INFO'], '/'));
  167. if (count($vars) > $contextDepth) {
  168. $this->_page = $vars[$contextDepth];
  169. }
  170. }
  171. } else {
  172. $this->_page = $request->getUserVar('page');
  173. }
  174. $this->_page = Core::cleanFileVar(is_null($this->_page) ? '' : $this->_page);
  175. }
  176. return $this->_page;
  177. }
  178. /**
  179. * Get the operation requested in the URL (assumed to exist in the requested page handler).
  180. * @param $request PKPRequest the request to be routed
  181. * @return string
  182. */
  183. function getRequestedOp(&$request) {
  184. assert(is_a($request->getRouter(), 'PKPPageRouter'));
  185. if (!isset($this->_op)) {
  186. $this->_op = '';
  187. if ($request->isPathInfoEnabled()) {
  188. $application = $this->getApplication();
  189. $contextDepth = $application->getContextDepth();
  190. if (isset($_SERVER['PATH_INFO'])) {
  191. $vars = explode('/', trim($_SERVER['PATH_INFO'], '/'));
  192. if (count($vars) > $contextDepth+1) {
  193. $this->_op = $vars[$contextDepth+1];
  194. }
  195. }
  196. } else {
  197. $this->_op = $request->getUserVar('op');
  198. }
  199. $this->_op = Core::cleanFileVar(empty($this->_op) ? 'index' : $this->_op);
  200. }
  201. return $this->_op;
  202. }
  203. /**
  204. * Get the arguments requested in the URL (not GET/POST arguments, only arguments appended to the URL separated by "/").
  205. * @param $request PKPRequest the request to be routed
  206. * @return array
  207. */
  208. function getRequestedArgs(&$request) {
  209. if ($request->isPathInfoEnabled()) {
  210. $args = array();
  211. if (isset($_SERVER['PATH_INFO'])) {
  212. $application = $this->getApplication();
  213. $contextDepth = $application->getContextDepth();
  214. $vars = explode('/', $_SERVER['PATH_INFO']);
  215. if (count($vars) > $contextDepth+3) {
  216. $args = array_slice($vars, $contextDepth+3);
  217. for ($i=0, $count=count($args); $i<$count; $i++) {
  218. $args[$i] = Core::cleanVar(get_magic_quotes_gpc() ? stripslashes($args[$i]) : $args[$i]);
  219. }
  220. }
  221. }
  222. } else {
  223. $args = $request->getUserVar('path');
  224. if (empty($args)) $args = array();
  225. elseif (!is_array($args)) $args = array($args);
  226. }
  227. return $args;
  228. }
  229. /**
  230. * Build a page request URL into PKPApplication.
  231. * @param $request PKPRequest the request to be routed
  232. * @param $newContext mixed Optional contextual paths
  233. * @param $page string Optional name of page to invoke
  234. * @param $op string Optional name of operation to invoke
  235. * @param $path mixed Optional string or array of args to pass to handler
  236. * @param $params array Optional set of name => value pairs to pass as user parameters
  237. * @param $anchor string Optional name of anchor to add to URL
  238. * @param $escape boolean Whether or not to escape ampersands for this URL; default false.
  239. * @return string the URL
  240. */
  241. function url(&$request, $newContext = null, $page = null, $op = null, $path = null,
  242. $params = null, $anchor = null, $escape = false) {
  243. $pathInfoEnabled = $request->isPathInfoEnabled();
  244. //
  245. // Base URL and Context
  246. //
  247. $newContext = $this->_urlCanonicalizeNewContext($newContext);
  248. $baseUrlAndContext = $this->_urlGetBaseAndContext($request, $newContext);
  249. $baseUrl = array_shift($baseUrlAndContext);
  250. $context = $baseUrlAndContext;
  251. //
  252. // Additional path info
  253. //
  254. if (empty($path)) {
  255. $additionalPath = array();
  256. } else {
  257. if (is_array($path)) {
  258. $additionalPath = array_map('rawurlencode', $path);
  259. } else {
  260. $additionalPath = array(rawurlencode($path));
  261. }
  262. // If path info is disabled then we have to
  263. // encode the path as query parameters.
  264. if (!$pathInfoEnabled) {
  265. $pathKey = 'path%5B%5D=';
  266. foreach($additionalPath as $key => $pathElement) {
  267. $additionalPath[$key] = $pathKey.$pathElement;
  268. }
  269. }
  270. }
  271. //
  272. // Page and Operation
  273. //
  274. // Are we in a page request?
  275. $currentRequestIsAPageRequest = is_a($request->getRouter(), 'PKPPageRouter');
  276. // Determine the operation
  277. if ($op) {
  278. // If an operation has been explicitly set then use it.
  279. $op = rawurlencode($op);
  280. } else {
  281. // No operation has been explicitly set so let's determine a sensible
  282. // default operation.
  283. if (empty($newContext) && empty($page) && $currentRequestIsAPageRequest) {
  284. // If we remain in the existing context and on the existing page then
  285. // we will default to the current operation. We can only determine a
  286. // current operation if the current request is a page request.
  287. $op = $this->getRequestedOp($request);
  288. } else {
  289. // If a new context (or page) has been set then we'll default to the
  290. // index operation within the new context (or on the new page).
  291. if (empty($additionalPath)) {
  292. // If no additional path is set we can simply leave the operation
  293. // undefined which automatically defaults to the index operation
  294. // but gives shorter (=nicer) URLs.
  295. $op = null;
  296. } else {
  297. // If an additional path is set then we have to explicitly set the
  298. // index operation to disambiguate the path info.
  299. $op = 'index';
  300. }
  301. }
  302. }
  303. // Determine the page
  304. if ($page) {
  305. // If a page has been explicitly set then use it.
  306. $page = rawurlencode($page);
  307. } else {
  308. // No page has been explicitly set so let's determine a sensible default page.
  309. if (empty($newContext) && $currentRequestIsAPageRequest) {
  310. // If we remain in the existing context then we will default to the current
  311. // page. We can only determine a current page if the current request is a
  312. // page request.
  313. $page = $this->getRequestedPage($request);
  314. } else {
  315. // If a new context has been set then we'll default to the index page
  316. // within the new context.
  317. if (empty($op)) {
  318. // If no explicit operation is set we can simply leave the page
  319. // undefined which automatically defaults to the index page but gives
  320. // shorter (=nicer) URLs.
  321. $page = null;
  322. } else {
  323. // If an operation is set then we have to explicitly set the index
  324. // page to disambiguate the path info.
  325. $page = 'index';
  326. }
  327. }
  328. }
  329. //
  330. // Additional query parameters
  331. //
  332. $additionalParameters = $this->_urlGetAdditionalParameters($request, $params);
  333. //
  334. // Anchor
  335. //
  336. $anchor = (empty($anchor) ? '' : '#'.rawurlencode($anchor));
  337. //
  338. // Assemble URL
  339. //
  340. if ($pathInfoEnabled) {
  341. // If path info is enabled then context, page,
  342. // operation and additional path go into the
  343. // path info.
  344. $pathInfoArray = $context;
  345. if (!empty($page)) {
  346. $pathInfoArray[] = $page;
  347. if (!empty($op)) {
  348. $pathInfoArray[] = $op;
  349. }
  350. }
  351. $pathInfoArray = array_merge($pathInfoArray, $additionalPath);
  352. // Query parameters
  353. $queryParametersArray = $additionalParameters;
  354. } else {
  355. // If path info is disabled then context, page,
  356. // operation and additional path are encoded as
  357. // query parameters.
  358. $pathInfoArray = array();
  359. // Query parameters
  360. $queryParametersArray = $context;
  361. if (!empty($page)) {
  362. $queryParametersArray[] = "page=$page";
  363. if (!empty($op)) {
  364. $queryParametersArray[] = "op=$op";
  365. }
  366. }
  367. $queryParametersArray = array_merge($queryParametersArray, $additionalPath, $additionalParameters);
  368. }
  369. return $this->_urlFromParts($baseUrl, $pathInfoArray, $queryParametersArray, $anchor, $escape);
  370. }
  371. }
  372. ?>