Revision 2049 | Revision 2254 | Zur aktuellen Revision | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** CodeIgniter** An open source application development framework for PHP** This content is released under the MIT License (MIT)** Copyright (c) 2014 - 2018, British Columbia Institute of Technology** Permission is hereby granted, free of charge, to any person obtaining a copy* of this software and associated documentation files (the "Software"), to deal* in the Software without restriction, including without limitation the rights* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell* copies of the Software, and to permit persons to whom the Software is* furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice shall be included in* all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN* THE SOFTWARE.** @package CodeIgniter* @author EllisLab Dev Team* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)* @license http://opensource.org/licenses/MIT MIT License* @link https://codeigniter.com* @since Version 1.0.0* @filesource*/defined('BASEPATH') OR exit('No direct script access allowed');/*** Router Class** Parses URIs and determines routing** @package CodeIgniter* @subpackage Libraries* @category Libraries* @author EllisLab Dev Team* @link https://codeigniter.com/user_guide/general/routing.html*/class CI_Router {/*** CI_Config class object** @var object*/public $config;/*** List of routes** @var array*/public $routes = array();/*** Current class name** @var string*/public $class = '';/*** Current method name** @var string*/public $method = 'index';/*** Sub-directory that contains the requested controller class** @var string*/public $directory;/*** Default controller (and method if specific)** @var string*/public $default_controller;/*** Translate URI dashes** Determines whether dashes in controller & method segments* should be automatically replaced by underscores.** @var bool*/public $translate_uri_dashes = FALSE;/*** Enable query strings flag** Determines whether to use GET parameters or segment URIs** @var bool*/public $enable_query_strings = FALSE;// --------------------------------------------------------------------/*** Class constructor** Runs the route mapping function.** @param array $routing* @return void*/public function __construct($routing = NULL){$this->config =& load_class('Config', 'core');$this->uri =& load_class('URI', 'core');$this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE);// If a directory override is configured, it has to be set before any dynamic routing logicis_array($routing) && isset($routing['directory']) && $this->set_directory($routing['directory']);$this->_set_routing();// Set any routing overrides that may exist in the main index fileif (is_array($routing)){empty($routing['controller']) OR $this->set_class($routing['controller']);empty($routing['function']) OR $this->set_method($routing['function']);}log_message('info', 'Router Class Initialized');}// --------------------------------------------------------------------/*** Set route mapping** Determines what should be served based on the URI request,* as well as any "routes" that have been set in the routing config file.** @return void*/protected function _set_routing(){// Load the routes.php file. It would be great if we could// skip this for enable_query_strings = TRUE, but then// default_controller would be empty ...if (file_exists(APPPATH.'config/routes.php')){include(APPPATH.'config/routes.php');}if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/routes.php')){include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');}// Validate & get reserved routesif (isset($route) && is_array($route)){isset($route['default_controller']) && $this->default_controller = $route['default_controller'];isset($route['translate_uri_dashes']) && $this->translate_uri_dashes = $route['translate_uri_dashes'];unset($route['default_controller'], $route['translate_uri_dashes']);$this->routes = $route;}// Are query strings enabled in the config file? Normally CI doesn't utilize query strings// since URI segments are more search-engine friendly, but they can optionally be used.// If this feature is enabled, we will gather the directory/class/method a little differentlyif ($this->enable_query_strings){// If the directory is set at this time, it means an override exists, so skip the checksif ( ! isset($this->directory)){$_d = $this->config->item('directory_trigger');$_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : '';if ($_d !== ''){$this->uri->filter_uri($_d);$this->set_directory($_d);}}$_c = trim($this->config->item('controller_trigger'));if ( ! empty($_GET[$_c])){$this->uri->filter_uri($_GET[$_c]);$this->set_class($_GET[$_c]);$_f = trim($this->config->item('function_trigger'));if ( ! empty($_GET[$_f])){$this->uri->filter_uri($_GET[$_f]);$this->set_method($_GET[$_f]);}$this->uri->rsegments = array(1 => $this->class,2 => $this->method);}else{$this->_set_default_controller();}// Routing rules don't apply to query strings and we don't need to detect// directories, so we're done herereturn;}// Is there anything to parse?if ($this->uri->uri_string !== ''){$this->_parse_routes();}else{$this->_set_default_controller();}}// --------------------------------------------------------------------/*** Set request route** Takes an array of URI segments as input and sets the class/method* to be called.** @used-by CI_Router::_parse_routes()* @param array $segments URI segments* @return void*/protected function _set_request($segments = array()){$segments = $this->_validate_request($segments);// If we don't have any segments left - try the default controller;// WARNING: Directories get shifted out of the segments array!if (empty($segments)){$this->_set_default_controller();return;}if ($this->translate_uri_dashes === TRUE){$segments[0] = str_replace('-', '_', $segments[0]);if (isset($segments[1])){$segments[1] = str_replace('-', '_', $segments[1]);}}$this->set_class($segments[0]);if (isset($segments[1])){$this->set_method($segments[1]);}else{$segments[1] = 'index';}array_unshift($segments, NULL);unset($segments[0]);$this->uri->rsegments = $segments;}// --------------------------------------------------------------------/*** Set default controller** @return void*/protected function _set_default_controller(){if (empty($this->default_controller)){show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');}// Is the method being specified?if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2){$method = 'index';}if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')){// This will trigger 404 laterreturn;}$this->set_class($class);$this->set_method($method);// Assign routed segments, index starting from 1$this->uri->rsegments = array(1 => $class,2 => $method);log_message('debug', 'No URI present. Default controller set.');}// --------------------------------------------------------------------/*** Validate request** Attempts validate the URI request and determine the controller path.** @used-by CI_Router::_set_request()* @param array $segments URI segments* @return mixed URI segments*/protected function _validate_request($segments){$c = count($segments);$directory_override = isset($this->directory);// Loop through our segments and return as soon as a controller// is found or when such a directory doesn't existwhile ($c-- > 0){$test = $this->directory.ucfirst($this->translate_uri_dashes === TRUE ? str_replace('-', '_', $segments[0]) : $segments[0]);if ( ! file_exists(APPPATH.'controllers/'.$test.'.php')&& $directory_override === FALSE&& is_dir(APPPATH.'controllers/'.$this->directory.$segments[0])){$this->set_directory(array_shift($segments), TRUE);continue;}return $segments;}// This means that all segments were actually directoriesreturn $segments;}// --------------------------------------------------------------------/*** Parse Routes** Matches any routes that may exist in the config/routes.php file* against the URI to determine if the class/method need to be remapped.** @return void*/protected function _parse_routes(){// Turn the segment array into a URI string$uri = implode('/', $this->uri->segments);// Get HTTP verb$http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';// Loop through the route array looking for wildcardsforeach ($this->routes as $key => $val){// Check if route format is using HTTP verbsif (is_array($val)){$val = array_change_key_case($val, CASE_LOWER);if (isset($val[$http_verb])){$val = $val[$http_verb];}else{continue;}}// Convert wildcards to RegEx$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);// Does the RegEx match?if (preg_match('#^'.$key.'$#', $uri, $matches)){// Are we using callbacks to process back-references?if ( ! is_string($val) && is_callable($val)){// Remove the original string from the matches array.array_shift($matches);// Execute the callback using the values in matches as its parameters.$val = call_user_func_array($val, $matches);}// Are we using the default routing method for back-references?elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE){$val = preg_replace('#^'.$key.'$#', $val, $uri);}$this->_set_request(explode('/', $val));return;}}// If we got this far it means we didn't encounter a// matching route so we'll set the site default route$this->_set_request(array_values($this->uri->segments));}// --------------------------------------------------------------------/*** Set class name** @param string $class Class name* @return void*/public function set_class($class){$this->class = str_replace(array('/', '.'), '', $class);}// --------------------------------------------------------------------/*** Fetch the current class** @deprecated 3.0.0 Read the 'class' property instead* @return string*/public function fetch_class(){return $this->class;}// --------------------------------------------------------------------/*** Set method name** @param string $method Method name* @return void*/public function set_method($method){$this->method = $method;}// --------------------------------------------------------------------/*** Fetch the current method** @deprecated 3.0.0 Read the 'method' property instead* @return string*/public function fetch_method(){return $this->method;}// --------------------------------------------------------------------/*** Set directory name** @param string $dir Directory name* @param bool $append Whether we're appending rather than setting the full value* @return void*/public function set_directory($dir, $append = FALSE){if ($append !== TRUE OR empty($this->directory)){$this->directory = str_replace('.', '', trim($dir, '/')).'/';}else{$this->directory .= str_replace('.', '', trim($dir, '/')).'/';}}// --------------------------------------------------------------------/*** Fetch directory** Feches the sub-directory (if any) that contains the requested* controller class.** @deprecated 3.0.0 Read the 'directory' property instead* @return string*/public function fetch_directory(){return $this->directory;}}