URI.php

Go to the documentation of this file.
00001 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
00002 /**
00003  * CodeIgniter
00004  *
00005  * An open source application development framework for PHP 4.3.2 or newer
00006  *
00007  * @package             CodeIgniter
00008  * @author              ExpressionEngine Dev Team
00009  * @copyright   Copyright (c) 2006, EllisLab, Inc.
00010  * @license             http://codeigniter.com/user_guide/license.html
00011  * @link                http://codeigniter.com
00012  * @since               Version 1.0
00013  * @filesource
00014  */
00015 
00016 // ------------------------------------------------------------------------
00017 
00018 /**
00019  * URI Class
00020  *
00021  * Parses URIs and determines routing
00022  *
00023  * @package             CodeIgniter
00024  * @subpackage  Libraries
00025  * @category    URI
00026  * @author              ExpressionEngine Dev Team
00027  * @link                http://codeigniter.com/user_guide/libraries/uri.html
00028  */
00029 class CI_URI {
00030 
00031         var     $keyval = array();
00032         var $uri_string;
00033         var $segments           = array();
00034         var $rsegments          = array();
00035 
00036         /**
00037          * Constructor
00038          *
00039          * Simply globalizes the $RTR object.  The front
00040          * loads the Router class early on so it's not available
00041          * normally as other classes are.
00042          *
00043          * @access      public
00044          */             
00045         function CI_URI()
00046         {
00047                 $this->config =& load_class('Config');
00048                 log_message('debug', "URI Class Initialized");
00049         }
00050         
00051         
00052         // --------------------------------------------------------------------
00053         
00054         /**
00055          * Get the URI String
00056          *
00057          * @access      private
00058          * @return      string
00059          */     
00060         function _fetch_uri_string()
00061         {       
00062                 if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
00063                 {
00064                         // If the URL has a question mark then it's simplest to just
00065                         // build the URI string from the zero index of the $_GET array.
00066                         // This avoids having to deal with $_SERVER variables, which
00067                         // can be unreliable in some environments
00068                         if (is_array($_GET) AND count($_GET) == 1 AND trim(key($_GET), '/') != '')
00069                         {
00070                                 $this->uri_string = key($_GET);                 
00071                                 return;
00072                         }
00073                 
00074                         // Is there a PATH_INFO variable?
00075                         // Note: some servers seem to have trouble with getenv() so we'll test it two ways              
00076                         $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');                  
00077                         if (trim($path, '/') != '' AND $path != "/".SELF)
00078                         {
00079                                 $this->uri_string = $path;
00080                                 return;
00081                         }
00082                                         
00083                         // No PATH_INFO?... What about QUERY_STRING?
00084                         $path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');        
00085                         if (trim($path, '/') != '')
00086                         {
00087                                 $this->uri_string = $path;
00088                                 return;
00089                         }
00090                         
00091                         // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
00092                         $path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');   
00093                         if (trim($path, '/') != '' AND $path != "/".SELF)
00094                         {
00095                                 // remove path and script information so we have good URI data
00096                                 $this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);
00097                                 return;
00098                         }
00099 
00100                         // We've exhausted all our options...
00101                         $this->uri_string = '';
00102                 }
00103                 else
00104                 {
00105                         $uri = strtoupper($this->config->item('uri_protocol'));
00106                         
00107                         if ($uri == 'REQUEST_URI')
00108                         {
00109                                 $this->uri_string = $this->_parse_request_uri();
00110                                 return;
00111                         }
00112                         
00113                         $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
00114                 }
00115                 
00116                 // If the URI contains only a slash we'll kill it
00117                 if ($this->uri_string == '/')
00118                 {
00119                         $this->uri_string = '';
00120                 }               
00121         }
00122         
00123         // --------------------------------------------------------------------
00124         
00125         /**
00126          * Parse the REQUEST_URI
00127          *
00128          * Due to the way REQUEST_URI works it usually contains path info
00129          * that makes it unusable as URI data.  We'll trim off the unnecessary
00130          * data, hopefully arriving at a valid URI that we can use.
00131          *
00132          * @access      private
00133          * @return      string
00134          */     
00135         function _parse_request_uri()
00136         {
00137                 if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
00138                 {
00139                         return '';
00140                 }
00141                 
00142                 $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
00143 
00144                 if ($request_uri == '' OR $request_uri == SELF)
00145                 {
00146                         return '';
00147                 }
00148                 
00149                 $fc_path = FCPATH;              
00150                 if (strpos($request_uri, '?') !== FALSE)
00151                 {
00152                         $fc_path .= '?';
00153                 }
00154                 
00155                 $parsed_uri = explode("/", $request_uri);
00156                                 
00157                 $i = 0;
00158                 foreach(explode("/", $fc_path) as $segment)
00159                 {
00160                         if (isset($parsed_uri[$i]) AND $segment == $parsed_uri[$i])
00161                         {
00162                                 $i++;
00163                         }
00164                 }
00165                 
00166                 $parsed_uri = implode("/", array_slice($parsed_uri, $i));
00167                 
00168                 if ($parsed_uri != '')
00169                 {
00170                         $parsed_uri = '/'.$parsed_uri;
00171                 }
00172 
00173                 return $parsed_uri;
00174         }
00175 
00176         // --------------------------------------------------------------------
00177         
00178         /**
00179          * Filter segments for malicious characters
00180          *
00181          * @access      private
00182          * @param       string
00183          * @return      string
00184          */     
00185         function _filter_uri($str)
00186         {
00187                 if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
00188                 {
00189                         if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
00190                         {
00191                                 exit('The URI you submitted has disallowed characters.');
00192                         }
00193                 }
00194                         
00195                 return $str;
00196         }
00197 
00198         // --------------------------------------------------------------------
00199         
00200         /**
00201          * Remove the suffix from the URL if needed
00202          *
00203          * @access      private
00204          * @return      void
00205          */     
00206         function _remove_url_suffix()
00207         {
00208                 if  ($this->config->item('url_suffix') != "")
00209                 {
00210                         $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
00211                 }
00212         }
00213         
00214         // --------------------------------------------------------------------
00215         
00216         /**
00217          * Explode the URI Segments. The individual segments will
00218          * be stored in the $this->segments array.      
00219          *
00220          * @access      private
00221          * @return      void
00222          */             
00223         function _explode_segments()
00224         {
00225                 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
00226                 {
00227                         // Filter segments for security
00228                         $val = trim($this->_filter_uri($val));
00229                         
00230                         if ($val != '')
00231                                 $this->segments[] = $val;
00232                 }
00233         }
00234         
00235         // -------------------------------------------------------------------- 
00236         /**
00237          * Re-index Segments
00238          *
00239          * This function re-indexes the $this->segment array so that it
00240          * starts at 1 rather then 0.  Doing so makes it simpler to
00241          * use functions like $this->uri->segment(n) since there is
00242          * a 1:1 relationship between the segment array and the actual segments.
00243          *
00244          * @access      private
00245          * @return      void
00246          */     
00247         function _reindex_segments()
00248         {
00249                 array_unshift($this->segments, NULL);
00250                 array_unshift($this->rsegments, NULL);
00251                 unset($this->segments[0]);
00252                 unset($this->rsegments[0]);
00253         }       
00254         
00255         // --------------------------------------------------------------------
00256         
00257         /**
00258          * Fetch a URI Segment
00259          *
00260          * This function returns the URI segment based on the number provided.
00261          *
00262          * @access      public
00263          * @param       integer
00264          * @param       bool
00265          * @return      string
00266          */
00267         function segment($n, $no_result = FALSE)
00268         {
00269                 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
00270         }
00271 
00272         // --------------------------------------------------------------------
00273         
00274         /**
00275          * Fetch a URI "routed" Segment
00276          *
00277          * This function returns the re-routed URI segment (assuming routing rules are used)
00278          * based on the number provided.  If there is no routing this function returns the
00279          * same result as $this->segment()
00280          *
00281          * @access      public
00282          * @param       integer
00283          * @param       bool
00284          * @return      string
00285          */
00286         function rsegment($n, $no_result = FALSE)
00287         {
00288                 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
00289         }
00290 
00291         // --------------------------------------------------------------------
00292         
00293         /**
00294          * Generate a key value pair from the URI string
00295          *
00296          * This function generates and associative array of URI data starting
00297          * at the supplied segment. For example, if this is your URI:
00298          *
00299          *      example.com/user/search/name/joe/location/UK/gender/male
00300          *
00301          * You can use this function to generate an array with this prototype:
00302          *
00303          * array (
00304          *                      name => joe
00305          *                      location => UK
00306          *                      gender => male
00307          *               )
00308          *
00309          * @access      public
00310          * @param       integer the starting segment number
00311          * @param       array   an array of default values
00312          * @return      array
00313          */
00314         function uri_to_assoc($n = 3, $default = array())
00315         {
00316                 return $this->_uri_to_assoc($n, $default, 'segment');
00317         }
00318         /**
00319          * Identical to above only it uses the re-routed segment array
00320          *
00321          */
00322         function ruri_to_assoc($n = 3, $default = array())
00323         {
00324                 return $this->_uri_to_assoc($n, $default, 'rsegment');
00325         }
00326 
00327         // --------------------------------------------------------------------
00328         
00329         /**
00330          * Generate a key value pair from the URI string or Re-routed URI string
00331          *
00332          * @access      private
00333          * @param       integer the starting segment number
00334          * @param       array   an array of default values
00335          * @param       string  which array we should use
00336          * @return      array
00337          */
00338         function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
00339         {
00340                 if ($which == 'segment')
00341                 {
00342                         $total_segments = 'total_segments';
00343                         $segment_array = 'segment_array';
00344                 }
00345                 else
00346                 {
00347                         $total_segments = 'total_rsegments';
00348                         $segment_array = 'rsegment_array';
00349                 }
00350                 
00351                 if ( ! is_numeric($n))
00352                 {
00353                         return $default;
00354                 }
00355         
00356                 if (isset($this->keyval[$n]))
00357                 {
00358                         return $this->keyval[$n];
00359                 }
00360         
00361                 if ($this->$total_segments() < $n)
00362                 {
00363                         if (count($default) == 0)
00364                         {
00365                                 return array();
00366                         }
00367                         
00368                         $retval = array();
00369                         foreach ($default as $val)
00370                         {
00371                                 $retval[$val] = FALSE;
00372                         }               
00373                         return $retval;
00374                 }
00375 
00376                 $segments = array_slice($this->$segment_array(), ($n - 1));
00377 
00378                 $i = 0;
00379                 $lastval = '';
00380                 $retval  = array();
00381                 foreach ($segments as $seg)
00382                 {
00383                         if ($i % 2)
00384                         {
00385                                 $retval[$lastval] = $seg;
00386                         }
00387                         else
00388                         {
00389                                 $retval[$seg] = FALSE;
00390                                 $lastval = $seg;
00391                         }
00392                 
00393                         $i++;
00394                 }
00395 
00396                 if (count($default) > 0)
00397                 {
00398                         foreach ($default as $val)
00399                         {
00400                                 if ( ! array_key_exists($val, $retval))
00401                                 {
00402                                         $retval[$val] = FALSE;
00403                                 }
00404                         }
00405                 }
00406 
00407                 // Cache the array for reuse
00408                 $this->keyval[$n] = $retval;
00409                 return $retval;
00410         }
00411 
00412         // --------------------------------------------------------------------
00413 
00414         /**
00415          * Generate a URI string from an associative array
00416          *
00417          *
00418          * @access      public
00419          * @param       array   an associative array of key/values
00420          * @return      array
00421          */     
00422         function assoc_to_uri($array)
00423         {       
00424                 $temp = array();
00425                 foreach ((array)$array as $key => $val)
00426                 {
00427                         $temp[] = $key;
00428                         $temp[] = $val;
00429                 }
00430                 
00431                 return implode('/', $temp);
00432         }
00433 
00434         // --------------------------------------------------------------------
00435         
00436         /**
00437          * Fetch a URI Segment and add a trailing slash
00438          *
00439          * @access      public
00440          * @param       integer
00441          * @param       string
00442          * @return      string
00443          */
00444         function slash_segment($n, $where = 'trailing')
00445         {
00446                 return $this->_slash_segment($n, $where, 'segment');
00447         }
00448 
00449         // --------------------------------------------------------------------
00450         
00451         /**
00452          * Fetch a URI Segment and add a trailing slash
00453          *
00454          * @access      public
00455          * @param       integer
00456          * @param       string
00457          * @return      string
00458          */
00459         function slash_rsegment($n, $where = 'trailing')
00460         {
00461                 return $this->_slash_segment($n, $where, 'rsegment');
00462         }
00463         
00464         // --------------------------------------------------------------------
00465         
00466         /**
00467          * Fetch a URI Segment and add a trailing slash - helper function
00468          *
00469          * @access      private
00470          * @param       integer
00471          * @param       string
00472          * @param       string
00473          * @return      string
00474          */
00475         function _slash_segment($n, $where = 'trailing', $which = 'segment')
00476         {       
00477                 if ($where == 'trailing')
00478                 {
00479                         $trailing       = '/';
00480                         $leading        = '';
00481                 }
00482                 elseif ($where == 'leading')
00483                 {
00484                         $leading        = '/';
00485                         $trailing       = '';
00486                 }
00487                 else
00488                 {
00489                         $leading        = '/';
00490                         $trailing       = '/';
00491                 }
00492                 return $leading.$this->$which($n).$trailing;
00493         }
00494         
00495         // --------------------------------------------------------------------
00496         
00497         /**
00498          * Segment Array
00499          *
00500          * @access      public
00501          * @return      array
00502          */
00503         function segment_array()
00504         {
00505                 return $this->segments;
00506         }
00507 
00508         // --------------------------------------------------------------------
00509         
00510         /**
00511          * Routed Segment Array
00512          *
00513          * @access      public
00514          * @return      array
00515          */
00516         function rsegment_array()
00517         {
00518                 return $this->rsegments;
00519         }
00520         
00521         // --------------------------------------------------------------------
00522         
00523         /**
00524          * Total number of segments
00525          *
00526          * @access      public
00527          * @return      integer
00528          */
00529         function total_segments()
00530         {
00531                 return count($this->segments);
00532         }
00533 
00534         // --------------------------------------------------------------------
00535         
00536         /**
00537          * Total number of routed segments
00538          *
00539          * @access      public
00540          * @return      integer
00541          */
00542         function total_rsegments()
00543         {
00544                 return count($this->rsegments);
00545         }
00546         
00547         // --------------------------------------------------------------------
00548         
00549         /**
00550          * Fetch the entire URI string
00551          *
00552          * @access      public
00553          * @return      string
00554          */
00555         function uri_string()
00556         {
00557                 return $this->uri_string;
00558         }
00559 
00560         
00561         // --------------------------------------------------------------------
00562         
00563         /**
00564          * Fetch the entire Re-routed URI string
00565          *
00566          * @access      public
00567          * @return      string
00568          */
00569         function ruri_string()
00570         {
00571                 return '/'.implode('/', $this->rsegment_array()).'/';
00572         }
00573 
00574 }
00575 // END URI Class
00576 
00577 /* End of file URI.php */
00578 /* Location: ./system/libraries/URI.php */