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

/cms/includes/router.php

https://github.com/iconifyit/SkyBlue-1.1
PHP | 471 lines | 251 code | 71 blank | 149 comment | 55 complexity | b260115cf2a34f2048aa0eadf9734848 MD5 | raw file
  1. <?php
  2. defined('SKYBLUE') or die(basename(__FILE__)."\n");
  3. /**
  4. * The Router class replaces the hard-coded redirection in the .htaccess file
  5. * for providing a flexible base for url-rewriting
  6. * Examples: http://mydomain.tld/sbc/parentpagename/pagename.html
  7. * -> http://mydomain.tld/sbc/index.php?pid=pageid
  8. * http://mydomain.tld/sbc/parentpagename/pagename.25.htm
  9. * -> http://mydomain.tld/sbc/index.php?pid=pageid&show=25
  10. */
  11. class Router {
  12. var $request;
  13. /**
  14. * Used to store the requested "file" passed to SBC via $_GET['route']
  15. * @access private
  16. * @var string
  17. */
  18. var $route;
  19. /**
  20. * The name of the current page (e.g., About.html)
  21. * @access private
  22. * @var string
  23. */
  24. var $pageName;
  25. /**
  26. * Used to store the pages form the xml File
  27. * @access private
  28. * @var Array
  29. */
  30. var $pages;
  31. /**
  32. * Used to store the xmparser
  33. * needed, because the core allready needs the pid for creating himself.
  34. * @access privat
  35. * @var xmlHandler
  36. */
  37. var $xmlHandler;
  38. /*
  39. * @constructor
  40. */
  41. function __construct($path=null) {
  42. $this->xmlHandler = new xmlHandler;
  43. $this->pages = $this->xmlHandler->ParserMain(
  44. empty($path) ? 'data/xml/page.xml' : $path . 'data/xml/page.xml'
  45. );
  46. }
  47. /*
  48. * @constructor (Legacy)
  49. */
  50. function Router($path=null) {
  51. $this->__construct($path);
  52. }
  53. /**
  54. * Retrieves the page route
  55. * @access private
  56. * @return string
  57. */
  58. function getRoute() {
  59. $this->route = null;
  60. if (isset($_GET['route'])) {
  61. $this->route = $_GET['route'];
  62. }
  63. $this->route = $this->removeLastSlash($this->route);
  64. }
  65. /**
  66. * @description Determines if the URL format is the legacy format
  67. * @access private
  68. * @return boolean
  69. */
  70. function isLegacyLink() {
  71. $isLegacyLink = false;
  72. if (preg_match_all("/pg-([0-9]+)-c([0-9]+)-([0-9]+)\.htm/i", $this->route, $matches)) {
  73. $_GET['pid'] = $matches[1][0];
  74. $_GET['cid'] = $matches[2][0];
  75. $_GET['show'] = $matches[3][0];
  76. $isLegacyLink = true;
  77. }
  78. else if (preg_match_all("/pg-([0-9]+)-c([0-9]+)\.htm/i", $this->route, $matches)) {
  79. $_GET['pid'] = $matches[1][0];
  80. $_GET['cid'] = $matches[2][0];
  81. $isLegacyLink = true;
  82. }
  83. else if (preg_match_all("/pg-([0-9]+)-([0-9]+)\.htm/i", $this->route, $matches)) {
  84. $_GET['pid'] = $matches[1][0];
  85. $_GET['show'] = $matches[2][0];
  86. $isLegacyLink = true;
  87. }
  88. else if (preg_match_all("/pg-([0-9]+)\.htm/i", $this->route, $matches)) {
  89. $_GET['pid'] = $matches[1][0];
  90. $isLegacyLink = true;
  91. }
  92. return $isLegacyLink;
  93. }
  94. /**
  95. * @description Gets the text name of the current page
  96. * @access public
  97. * @return true|false returns true if everything is gone right, false if not
  98. */
  99. function getPageName() {
  100. $Filter = new Filter;
  101. $pageName = basename($this->route);
  102. if (empty($this->route)) {
  103. $defaultPage = $this->getDefaultPage();
  104. $defaultPage = $defaultPage[0];
  105. $pageId = $Filter->get($_GET, 'pid', $defaultPage->id);
  106. $pageName = basename($this->GetSefLink($pageId));
  107. }
  108. $this->setPageName($pageName);
  109. return $this->pageName;
  110. }
  111. function setPageName($pageName) {
  112. $this->pageName = $pageName;
  113. }
  114. /**
  115. * Used to initiate the routing
  116. * @access public
  117. * @return true|false returns true if everything is gone right, false if not
  118. */
  119. function route() {
  120. $this->getRoute();
  121. // If this is not an SEF URL, let the request pass through
  122. if (empty($this->route) && !empty($_GET)) {
  123. return true;
  124. }
  125. // If this is a legacy-format link (Name-pg-N.html),
  126. // let the request pass through
  127. else if ($this->isLegacyLink()) {
  128. if (!$this->getPageById($_GET['pid'])) {
  129. $_GET['pid'] = 'notfound'; // $this->pageNotFound();
  130. }
  131. return true;
  132. }
  133. // Otherwise, process the SEF URL
  134. else {
  135. $pageTree = explode('/', $this->route);
  136. $selectedPages = array();
  137. foreach ($pageTree as $pageName) {
  138. $treelength = count($selectedPages);
  139. $parentPage = null;
  140. $parentPageId = null;
  141. if ($treelength) {
  142. $parentPage = $selectedPages[$treelength-1];
  143. $parentPageId = $parentPage->id;
  144. }
  145. $foundPages = $this->getPageByNameAndParent($pageName, $parentPageId);
  146. if (!count($foundPages)) {
  147. $_GET['pid'] = 'notfound'; // $this->pageNotFound();
  148. return false;
  149. }
  150. $isChild = false;
  151. foreach ($foundPages as $foundPage) {
  152. if ($this->checkParent($foundPage, $parentPage)) {
  153. array_push($selectedPages, $foundPage);
  154. $isChild = true;
  155. break;
  156. }
  157. }
  158. if (!$isChild) return false;
  159. }
  160. $_GET['pid'] = null;
  161. if (count($selectedPages)) {
  162. $_GET['pid'] = $selectedPages[count($selectedPages)-1]->id;
  163. }
  164. return true;
  165. }
  166. return true;
  167. }
  168. /**
  169. * GetLink returns the HREF URL in the proper format depending on whether or not
  170. * USE_SEF_URLS is set to true or not.
  171. *
  172. * @access public
  173. * @param int $PageID The id of the page to display the object.
  174. * @param array $params Key=>value pairs of URL vars
  175. * @return string $link
  176. */
  177. function GetLink($pageID, $params=array()) {
  178. if (defined('USE_SEF_URLS') && USE_SEF_URLS == 1) {
  179. $link = $this->getPageTree($pageID);
  180. if (is_array($params) && count($params)) {
  181. foreach ($params as $k=>$v) {
  182. $link .= "{$k}{$v}";
  183. }
  184. }
  185. return FULL_URL . $link . ".html";
  186. }
  187. else {
  188. return FULL_URL . "index.php?pid={$pageID}" . $this->build_query($params);
  189. }
  190. }
  191. /**
  192. * Builds a URL Query String
  193. *
  194. * @param array $params Key=>value pairs of URL vars
  195. * @return string $query
  196. */
  197. function build_query($params) {
  198. if (function_exists('http_build_query')) {
  199. return http_build_query($params);
  200. }
  201. $query = array();
  202. foreach ($params as $k=>$v) {
  203. array_push($query, "$k=$v");
  204. }
  205. return implode("&", $query);
  206. }
  207. /**
  208. * @description GetLink returns SEF URL of the requested page
  209. * @access public
  210. * @param int $PageID The id of the page to display the object.
  211. * @param array $params Key=>value pairs of URL vars
  212. * @return string $link
  213. */
  214. function GetSefLink($pageID, $params=array()) {
  215. $link = $this->getPageTree($pageID);
  216. if (is_array($params) && count($params)) {
  217. foreach ($params as $k=>$v) {
  218. $link .= "{$k}{$v}";
  219. }
  220. }
  221. return FULL_URL . $link . ".html";
  222. }
  223. /**
  224. * @description Gets a fingerprint of the current page request.
  225. * The fingerprint is used to refer to a page without having to
  226. * worry about whether the page is being requested via SEF URL or
  227. * a URL query string.
  228. * @access public
  229. * @return string A fingerprint of the current page request
  230. */
  231. function getFingerprint() {
  232. $str = $this->route;
  233. if (empty($this->route)) {
  234. foreach ($_GET as $k=>$v) {
  235. $str .= "{$k}{$v}";
  236. }
  237. }
  238. return md5($str) . ".html";
  239. }
  240. /**
  241. * removes the '.htm' or '.html' from a string
  242. * @access private
  243. * @return string
  244. */
  245. function removeFileExt($string) {
  246. if (preg_match('/^(.*)\.(htm|html)$/', $string, $matches)) {
  247. return $matches[1];
  248. }
  249. return $string;
  250. }
  251. /**
  252. * removes the last / from a string
  253. * @access private
  254. * @return string
  255. */
  256. function removeLastSlash($string) {
  257. if (preg_match('/^(.*)\/$/', $string, $matches)) {
  258. return $matches[1];
  259. }
  260. return $string;
  261. }
  262. /**
  263. * returns a pageobject identified by his name or his id (is_int(...))
  264. * @access private
  265. * @param string|int if it's an integer, the page is identified by his id if not, by his name
  266. * @return object|false
  267. */
  268. function getPageByNameAndParent($identifier, $parent) {
  269. $identifier = $this->removeFileExt($identifier);
  270. $bits = explode('.', $identifier);
  271. $identifier = $bits[0];
  272. if (count($bits) > 1) {
  273. $_GET['params'] = array_slice($bits, 1);
  274. }
  275. if (empty($identifier)) {
  276. return $this->getDefaultPage();
  277. }
  278. $selectedPages = array();
  279. foreach ($this->pages as $page) {
  280. if ($this->normalize($page->name) == strtolower($identifier)
  281. && $page->parent == $parent)
  282. {
  283. array_push($selectedPages, $page);
  284. }
  285. }
  286. return $selectedPages;
  287. }
  288. /**
  289. * Retrieves the default page
  290. * @access private
  291. * @return object
  292. */
  293. function getDefaultPage() {
  294. foreach ($this->pages as $page) {
  295. if (1 == intval($page->isdefault)) {
  296. return array($page);
  297. }
  298. }
  299. return array();
  300. }
  301. /**
  302. * Retrieves a page by its ID
  303. * @access private
  304. * @return object
  305. */
  306. function getPageById($identifier) {
  307. foreach ($this->pages as $page) {
  308. if (intval($page->id) == intval($identifier)) {
  309. return $page;
  310. }
  311. }
  312. return null;
  313. }
  314. /**
  315. * Displays a custom 404 page if it exists
  316. * @access private
  317. * @return boolean
  318. */
  319. function pageNotFound() {
  320. $errorPage = $this->getPageByNameAndParent("404-page-not-found", "");
  321. if (is_array($errorPage) && count($errorPage)) {
  322. return $errorPage[0];
  323. }
  324. else if (is_object($errorPage)) {
  325. return $errorPage;
  326. }
  327. return null;
  328. /*
  329. if (!empty($errorPage)) {
  330. return 'notfound'; // $errorPage->id;
  331. $path = null;
  332. $levels = explode('/', $this->route);
  333. if (count($levels) > 1) {
  334. $path = str_repeat('../', count($levels)-1);
  335. }
  336. header("HTTP/1.0 404 Not Found");
  337. header("Location: {$path}404-page-not-found.html");
  338. exit(404);
  339. }
  340. return false;
  341. */
  342. }
  343. /**
  344. * normalizes the string for use in an url
  345. * @access private
  346. * @return string
  347. */
  348. function normalize($str) {
  349. $str = strtolower($str);
  350. $str = str_replace(
  351. array('&auml;', '&ouml;', '&uuml;', '&szlg', '&amp;', ' & ', '&', ' - ', '/', ' / ', ' '),
  352. array('ae', 'oe', 'ue', 'ss', '-and-', '-and-', '-and-', '-', '-', '-', '-'),
  353. $str
  354. );
  355. $chars = "abcdefghijklmnopqrstuvwxyz0123456789_-";
  356. $str = strtolower($str);
  357. for ($i=0; $i<strlen($str); $i++) {
  358. if (false === strpos($chars, $str{$i})) {
  359. $str{$i} = '-';
  360. }
  361. }
  362. $max = 100;
  363. $n=0;
  364. while (strpos($str, '--') !== false && $n<$max) {
  365. $str = str_replace('--', '-', $str);
  366. $n++;
  367. }
  368. return $str;
  369. }
  370. /**
  371. * returns an array with the pagename and its parents names
  372. * @access private
  373. * @return array of objects
  374. */
  375. function getPageTree($PageID) {
  376. $pageTree = array();
  377. $page = $this->getPageById($PageID);
  378. array_push($pageTree, $this->normalize($page->name));
  379. while ($page->parent) {
  380. $page = $this->getPageById($page->parent);
  381. array_push($pageTree, $this->normalize($page->name));
  382. }
  383. $pageTree = array_reverse($pageTree);
  384. $pageTree = implode('/',$pageTree);
  385. return $pageTree;
  386. }
  387. /**
  388. * Determines if the current page is a top-level page
  389. * @access private
  390. * @return boolean
  391. */
  392. function checkParent($child, $parent) {
  393. if (!$parent || !$child) return true;
  394. if ($child->parent != $parent->id) {
  395. return false;
  396. }
  397. return true;
  398. }
  399. }
  400. ?>