1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8// Adding support for an other web server? Check the end of the file 9 10/** 11 * Routing method, receives the path portion of the URL relative to tiki root. 12 * http://example.com/tiki/hello-world?foo-bar 13 * $path is expectedto be hello-world 14 */ 15function tiki_route($path) 16{ 17 /* 18 // If you are converting to Tiki and want to preserve some URLs, map the urls and remove the comment block 19 $urlMapping = array( 20 'wiki/old-page-name' => 'PageName', 21 'corporate/Privacy+Policy.pdf' => 'dl123', 22 ); 23 24 if (isset($urlMapping[$path])) { 25 $path = $urlMapping[$path]; 26 } 27 */ 28 29 30 $simple = [ 31 'articles' => 'tiki-view_articles.php', 32 'blogs' => 'tiki-list_blogs.php', 33 'calendar' => 'tiki-calendar.php', 34 'categories' => 'tiki-browse_categories.php', 35 'chat' => 'tiki-chat.php', 36 'contact' => 'tiki-contact.php', 37 'directories' => 'tiki-directory_browse.php', 38 'faqs' => 'tiki-list_faqs.php', 39 'filelist' => 'tiki-list_file_gallery.php', 40 'forums' => 'tiki-forums.php', 41 'galleries' => 'tiki-galleries.php', 42 'login' => 'tiki-login_scr.php', 43 'logout' => 'tiki-logout.php', 44 'me' => 'tiki-user_information.php', 45 'my' => 'tiki-my_tiki.php', 46 'newsletters' => 'tiki-newsletters.php', 47 'quizzes' => 'tiki-list_quizzes.php', 48 'register' => 'tiki-register.php', 49 'sheets' => 'tiki-sheets.php', 50 'statistics' => 'tiki-stats.php', 51 'surveys' => 'tiki-list_surveys.php', 52 'trackers' => 'tiki-list_trackers.php', 53 'users' => 'tiki-list_users.php', 54 'tiki-check' => 'tiki-check.php', 55 ]; 56 57 foreach ($simple as $key => $file) { 58 tiki_route_attempt("|^$key$|", $file); 59 } 60 61 /* 62 Valid: 63 64 art123 65 article123 66 art123-XYZ 67 article123-XYZ 68 */ 69 tiki_route_attempt('/^(art|article)(\d+)(\-.*)?$/', 'tiki-read_article.php', tiki_route_single(2, 'articleId')); 70 71 tiki_route_attempt('|^blog(\d+)(\-.*)?$|', 'tiki-view_blog.php', tiki_route_single(1, 'blogId')); 72 tiki_route_attempt('|^blogpost(\d+)(\-.*)?$|', 'tiki-view_blog_post.php', tiki_route_single(1, 'postId')); 73 tiki_route_attempt('|^cat(\d+)(\-.*)?$|', 'tiki-browse_categories.php', tiki_route_single(1, 'parentId')); 74 tiki_route_attempt_prefix('browseimage', 'tiki-browse_image.php', 'imageId'); 75 tiki_route_attempt('/^event(\d+)(\-.*)?$/', 'tiki-calendar_edit_item.php', tiki_route_single(1, 'viewcalitemId')); 76 77 tiki_route_attempt( 78 '|^cal(\d[\d,]*)$|', 79 'tiki-calendar.php', 80 function ($parts) { 81 $ids = explode(',', $parts[1]); 82 $ids = array_filter($ids); 83 return ['calIds' => $ids]; 84 } 85 ); 86 87 tiki_route_attempt_prefix('directory', 'tiki-directory_browse.php', 'parent'); 88 tiki_route_attempt_prefix('dirlink', 'tiki-directory_redirect.php', 'siteId'); 89 90 tiki_route_attempt_prefix('faq', 'tiki-view_faq.php', 'faqId'); 91 tiki_route_attempt_prefix('file', 'tiki-list_file_gallery.php', 'galleryId'); 92 tiki_route_attempt_prefix('forum', 'tiki-view_forum.php', 'forumId'); 93 tiki_route_attempt('|^forumthread(\d+)(\-.*)?$|', 'tiki-view_forum_thread.php', tiki_route_single(1, 'comments_parentId')); 94 tiki_route_attempt_prefix('calevent', 'tiki-calendar_edit_item.php', 'viewcalitemId'); 95 tiki_route_attempt_prefix('gallery', 'tiki-browse_gallery.php', 'galleryId'); 96 tiki_route_attempt_prefix('img', 'show_image.php', 'id'); 97 tiki_route_attempt_prefix('image', 'show_image.php', 'id'); 98 tiki_route_attempt( 99 '|^imagescale(\d+)/(\d+)$|', 100 'show_image.php', 101 function ($parts) { 102 return [ 103 'id' => $parts[1], 104 'scalesize' => $parts[2], 105 ]; 106 } 107 ); 108 tiki_route_attempt('|^item(\d+)(\-.*)?$|', 'tiki-view_tracker_item.php', tiki_route_single(1, 'itemId')); 109 tiki_route_attempt_prefix('int', 'tiki-integrator.php', 'repID'); 110 tiki_route_attempt_prefix('newsletter', 'tiki-newsletters.php', 'nlId', ['info' => '1']); 111 tiki_route_attempt_prefix('nl', 'tiki-newsletters.php', 'nlId', ['info' => '1']); 112 tiki_route_attempt_prefix('poll', 'tiki-poll_form.php', 'pollId'); 113 tiki_route_attempt_prefix('quiz', 'tiki-take_quiz.php', 'quizId'); 114 tiki_route_attempt_prefix('survey', 'tiki-take_survey.php', 'surveyId'); 115 tiki_route_attempt_prefix('tracker', 'tiki-view_tracker.php', 'trackerId'); 116 tiki_route_attempt_prefix('sheet', 'tiki-view_sheets.php', 'sheetId'); 117 tiki_route_attempt_prefix('user', 'tiki-user_information.php', 'userId'); 118 tiki_route_attempt('|^userinfo$|', 'tiki-view_tracker_item.php', function () { 119 return ['view' => ' user']; 120 }); 121 122 tiki_route_attempt_prefix('dl', 'tiki-download_file.php', 'fileId'); 123 tiki_route_attempt_prefix('thumbnail', 'tiki-download_file.php', 'fileId', ['thumbnail' => '']); 124 tiki_route_attempt_prefix('display', 'tiki-download_file.php', 'fileId', ['display' => '']); 125 tiki_route_attempt_prefix('preview', 'tiki-download_file.php', 'fileId', ['preview' => '']); 126 127 tiki_route_attempt( 128 '/^(wiki|page)\-(.+)$/', 129 'tiki-index.php', 130 function ($parts) { 131 return ['page' => $parts[2]]; 132 } 133 ); 134 tiki_route_attempt( 135 '/^show:(.+)$/', 136 'tiki-slideshow.php', 137 function ($parts) { 138 return ['page' => urldecode($parts[1])]; 139 } 140 ); 141 142 tiki_route_attempt( 143 '/([^\/]+).xml$/', 144 'tiki-sitemap.php', 145 function ($parts) { 146 return ['file' => $parts[0]]; 147 } 148 ); 149 150 tiki_route_attempt( 151 '|^tiki\-(\w+)\-(\w+)$|', 152 'tiki-ajax_services.php', 153 function ($parts) { 154 if ($parts[2] == 'x') { 155 return [ 156 'controller' => $parts[1], 157 ]; 158 } else { 159 return [ 160 'controller' => $parts[1], 161 'action' => $parts[2], 162 ]; 163 } 164 } 165 ); 166 167 if (false !== $dot = strrpos($path, '.')) { 168 // Prevent things that look like filenames from being considered for wiki page names 169 $extension = substr($path, $dot + 1); 170 if (in_array($extension, ['css', 'gif', 'jpg', 'png', 'php', 'html', 'js', 'htm', 'shtml', 'cgi', 'sql', 'phtml', 'txt', 'ihtml'])) { 171 return; 172 } 173 } 174 175 tiki_route_attempt_custom_route_redirect(); 176 177 tiki_route_attempt( 178 '|.*|', 179 'tiki-index.php', 180 function ($parts) { 181 return ['page' => urldecode($parts[0])]; 182 } 183 ); 184} 185 186function tiki_route_attempt($pattern, $file, $callback = null, $extra = []) 187{ 188 global $path, $inclusion, $base, $full; 189 190 if ($inclusion) { 191 return; 192 } 193 194 if (preg_match($pattern, $path, $parts)) { 195 $inclusion = $file; 196 197 $full = $base . $file; 198 199 if ($callback && is_callable($callback)) { 200 $_GET = array_merge($_GET, $callback($parts), $extra); 201 } 202 } 203} 204 205function tiki_route_attempt_prefix($prefix, $file, $key, $extra = []) 206{ 207 tiki_route_attempt("|^$prefix(\d+)$|", $file, tiki_route_single(1, $key), $extra); 208} 209 210function tiki_route_single($index, $name) 211{ 212 return function ($parts) use ($index, $name) { 213 return [$name => $parts[$index]]; 214 }; 215} 216 217/** 218 * Attempts to route based on custom routes, defined by the admin. 219 * If a suitable rule is found an HTTP redirect will be issued and the user sent to the right page/URL. 220 * Custom routes rules are only processed if none of the built in rules were successful 221 * This function also loads the minimal amount of framework to be able to query the db. 222 */ 223function tiki_route_attempt_custom_route_redirect() 224{ 225 global $path, $inclusion, $prefs, $tikiroot, $tikipath, $base, $full; 226 227 if ($inclusion || empty($path)) { 228 return; 229 } 230 231 // bootstrap the essentials to be able to use tiki db and libraries 232 // in a sane state that allows tiki to be fallback to the default entrypoints 233 // if a custom route is not match 234 require_once __DIR__ . '/tiki-filter-base.php'; // sets $tikiroot, $tikipath 235 $GLOBALS['tikiroot'] = $tikiroot; 236 $GLOBALS['tikipath'] = $tikipath; 237 238 require_once __DIR__ . '/db/tiki-db.php'; 239 240 if (! TikiDb::get()) { 241 exit; 242 } 243 244 require_once __DIR__ . '/lib/tikilib.php'; 245 246 $tikilib = new TikiLib; 247 $GLOBALS['tikilib'] = $tikilib; 248 249 $prefereces = [ 250 'feature_sefurl' => 'n', 251 'feature_sefurl_routes' => 'n', 252 ]; 253 254 $tikilib->get_preferences($prefereces, true, true); 255 // ~ bootstrap 256 257 if ($prefs['feature_sefurl_routes'] === 'y') { 258 $route = \Tiki\CustomRoute\CustomRoute::matchRoute($path); 259 if ($route) { 260 $routeParameters = \Tiki\CustomRoute\CustomRoute::getInPlaceRoutingParameters($route, $path); 261 if ($routeParameters !== false) { 262 $inclusion = $routeParameters['file']; 263 $full = $base . $inclusion; 264 $_GET = array_merge($_GET, $routeParameters['get_param']); 265 } else { 266 require_once __DIR__ . '/tiki-setup.php'; 267 // Reload necessary preferences for SEF url 268 $tikilib->get_preferences($prefereces, true, true); 269 \Tiki\CustomRoute\CustomRoute::executeRoute($route, $path); 270 } 271 } 272 } 273} 274 275$sapi = php_sapi_name(); 276$base = null; 277$path = null; 278$inclusion = null; 279 280// This portion may need to vary depending on the webserver/configuration 281 282switch ($sapi) { 283 case 'apache2handler': 284 default: 285 // Fix $_SERVER['REQUEST_URI', which is ASCII encoded on IIS 286 // Convert the SERVER variable itself, to fix $_SERVER['REQUEST_URI'] access everywhere 287 // route.php comes first in the processing. Avoid dependencies. 288 if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'IIS') !== false) { 289 if (mb_detect_encoding($_SERVER['REQUEST_URI'], 'UTF-8', true) == false) { 290 $_SERVER['REQUEST_URI'] = utf8_encode($_SERVER['REQUEST_URI']); 291 } 292 } 293 294 if (isset($_SERVER['SCRIPT_URL'])) { 295 $full = $_SERVER['SCRIPT_URL']; 296 } elseif (isset($_SERVER['REQUEST_URI'])) { 297 $full = $_SERVER['REQUEST_URI']; 298 if (strpos($full, '?') !== false) { 299 $full = substr($full, 0, strpos($full, '?')); 300 } 301 } elseif (isset($_SERVER['REDIRECT_URL'])) { 302 $full = $_SERVER['REDIRECT_URL']; 303 } elseif (isset($_SERVER['UNENCODED_URL'])) { // For IIS 304 $full = $_SERVER['UNENCODED_URL']; 305 } else { 306 break; 307 } 308 309 $file = basename(__FILE__); 310 $base = substr($_SERVER['PHP_SELF'], 0, -strlen($file)); 311 $path = substr($full, strlen($base)); 312 break; 313} 314 315// Global check 316 317if (is_null($base) || is_null($path)) { 318 header('HTTP/1.0 500 Internal Server Error'); 319 header('Content-Type: text/plain; charset=utf-8'); 320 321 echo "Request could not be understood. Verify routing file."; 322 exit; 323} 324 325tiki_route($path); 326 327if ($inclusion) { 328 $_SERVER['PHP_SELF'] = $base . $inclusion; 329 $_SERVER['SCRIPT_NAME'] = $base . basename($inclusion); 330 include __DIR__ . '/' . $inclusion; 331} else { 332 error_log("No route found - full:$full query:{$_SERVER['QUERY_STRING']}"); 333 334 // Route to the "no-route" URL, if found 335 require_once('lib/init/initlib.php'); 336 $local_php = TikiInit::getCredentialsFile(); 337 if (file_exists($local_php)) { 338 include($local_php); 339 } 340 if (empty($noroute_url)) { 341 // Fail 342 header('HTTP/1.0 404 Not Found'); 343 header('Content-Type: text/plain; charset=utf-8'); 344 345 echo "No route found. Please see http://dev.tiki.org/URL+Rewriting+Revamp"; 346 } else { 347 header('Location: ' . $noroute_url); 348 } 349 exit; 350} 351