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) 2008, 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) && count($_GET) == 1 && 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, '/') != '' && $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, '/') != '' && $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]) && $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 != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
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                 // Convert programatic characters to entities
00196                 $bad    = array('$',            '(',            ')',            '%28',          '%29');
00197                 $good   = array('&#36;',        '&#40;',        '&#41;',        '&#40;',        '&#41;');
00198                 
00199                 return str_replace($bad, $good, $str);
00200         }
00201 
00202         // --------------------------------------------------------------------
00203         
00204         /**
00205          * Remove the suffix from the URL if needed
00206          *
00207          * @access      private
00208          * @return      void
00209          */     
00210         function _remove_url_suffix()
00211         {
00212                 if  ($this->config->item('url_suffix') != "")
00213                 {
00214                         $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
00215                 }
00216         }
00217         
00218         // --------------------------------------------------------------------
00219         
00220         /**
00221          * Explode the URI Segments. The individual segments will
00222          * be stored in the $this->segments array.      
00223          *
00224          * @access      private
00225          * @return      void
00226          */             
00227         function _explode_segments()
00228         {
00229                 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
00230                 {
00231                         // Filter segments for security
00232                         $val = trim($this->_filter_uri($val));
00233                         
00234                         if ($val != '')
00235                         {
00236                                 $this->segments[] = $val;
00237                         }
00238                 }
00239         }
00240         
00241         // -------------------------------------------------------------------- 
00242         /**
00243          * Re-index Segments
00244          *
00245          * This function re-indexes the $this->segment array so that it
00246          * starts at 1 rather than 0.  Doing so makes it simpler to
00247          * use functions like $this->uri->segment(n) since there is
00248          * a 1:1 relationship between the segment array and the actual segments.
00249          *
00250          * @access      private
00251          * @return      void
00252          */     
00253         function _reindex_segments()
00254         {
00255                 array_unshift($this->segments, NULL);
00256                 array_unshift($this->rsegments, NULL);
00257                 unset($this->segments[0]);
00258                 unset($this->rsegments[0]);
00259         }       
00260         
00261         // --------------------------------------------------------------------
00262         
00263         /**
00264          * Fetch a URI Segment
00265          *
00266          * This function returns the URI segment based on the number provided.
00267          *
00268          * @access      public
00269          * @param       integer
00270          * @param       bool
00271          * @return      string
00272          */
00273         function segment($n, $no_result = FALSE)
00274         {
00275                 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
00276         }
00277 
00278         // --------------------------------------------------------------------
00279         
00280         /**
00281          * Fetch a URI "routed" Segment
00282          *
00283          * This function returns the re-routed URI segment (assuming routing rules are used)
00284          * based on the number provided.  If there is no routing this function returns the
00285          * same result as $this->segment()
00286          *
00287          * @access      public
00288          * @param       integer
00289          * @param       bool
00290          * @return      string
00291          */
00292         function rsegment($n, $no_result = FALSE)
00293         {
00294                 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
00295         }
00296 
00297         // --------------------------------------------------------------------
00298         
00299         /**
00300          * Generate a key value pair from the URI string
00301          *
00302          * This function generates and associative array of URI data starting
00303          * at the supplied segment. For example, if this is your URI:
00304          *
00305          *      example.com/user/search/name/joe/location/UK/gender/male
00306          *
00307          * You can use this function to generate an array with this prototype:
00308          *
00309          * array (
00310          *                      name => joe
00311          *                      location => UK
00312          *                      gender => male
00313          *               )
00314          *
00315          * @access      public
00316          * @param       integer the starting segment number
00317          * @param       array   an array of default values
00318          * @return      array
00319          */
00320         function uri_to_assoc($n = 3, $default = array())
00321         {
00322                 return $this->_uri_to_assoc($n, $default, 'segment');
00323         }
00324         /**
00325          * Identical to above only it uses the re-routed segment array
00326          *
00327          */
00328         function ruri_to_assoc($n = 3, $default = array())
00329         {
00330                 return $this->_uri_to_assoc($n, $default, 'rsegment');
00331         }
00332 
00333         // --------------------------------------------------------------------
00334         
00335         /**
00336          * Generate a key value pair from the URI string or Re-routed URI string
00337          *
00338          * @access      private
00339          * @param       integer the starting segment number
00340          * @param       array   an array of default values
00341          * @param       string  which array we should use
00342          * @return      array
00343          */
00344         function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
00345         {
00346                 if ($which == 'segment')
00347                 {
00348                         $total_segments = 'total_segments';
00349                         $segment_array = 'segment_array';
00350                 }
00351                 else
00352                 {
00353                         $total_segments = 'total_rsegments';
00354                         $segment_array = 'rsegment_array';
00355                 }
00356                 
00357                 if ( ! is_numeric($n))
00358                 {
00359                         return $default;
00360                 }
00361         
00362                 if (isset($this->keyval[$n]))
00363                 {
00364                         return $this->keyval[$n];
00365                 }
00366         
00367                 if ($this->$total_segments() < $n)
00368                 {
00369                         if (count($default) == 0)
00370                         {
00371                                 return array();
00372                         }
00373                         
00374                         $retval = array();
00375                         foreach ($default as $val)
00376                         {
00377                                 $retval[$val] = FALSE;
00378                         }               
00379                         return $retval;
00380                 }
00381 
00382                 $segments = array_slice($this->$segment_array(), ($n - 1));
00383 
00384                 $i = 0;
00385                 $lastval = '';
00386                 $retval  = array();
00387                 foreach ($segments as $seg)
00388                 {
00389                         if ($i % 2)
00390                         {
00391                                 $retval[$lastval] = $seg;
00392                         }
00393                         else
00394                         {
00395                                 $retval[$seg] = FALSE;
00396                                 $lastval = $seg;
00397                         }
00398                 
00399                         $i++;
00400                 }
00401 
00402                 if (count($default) > 0)
00403                 {
00404                         foreach ($default as $val)
00405                         {
00406                                 if ( ! array_key_exists($val, $retval))
00407                                 {
00408                                         $retval[$val] = FALSE;
00409                                 }
00410                         }
00411                 }
00412 
00413                 // Cache the array for reuse
00414                 $this->keyval[$n] = $retval;
00415                 return $retval;
00416         }
00417 
00418         // --------------------------------------------------------------------
00419 
00420         /**
00421          * Generate a URI string from an associative array
00422          *
00423          *
00424          * @access      public
00425          * @param       array   an associative array of key/values
00426          * @return      array
00427          */     
00428         function assoc_to_uri($array)
00429         {       
00430                 $temp = array();
00431                 foreach ((array)$array as $key => $val)
00432                 {
00433                         $temp[] = $key;
00434                         $temp[] = $val;
00435                 }
00436                 
00437                 return implode('/', $temp);
00438         }
00439 
00440         // --------------------------------------------------------------------
00441         
00442         /**
00443          * Fetch a URI Segment and add a trailing slash
00444          *
00445          * @access      public
00446          * @param       integer
00447          * @param       string
00448          * @return      string
00449          */
00450         function slash_segment($n, $where = 'trailing')
00451         {
00452                 return $this->_slash_segment($n, $where, 'segment');
00453         }
00454 
00455         // --------------------------------------------------------------------
00456         
00457         /**
00458          * Fetch a URI Segment and add a trailing slash
00459          *
00460          * @access      public
00461          * @param       integer
00462          * @param       string
00463          * @return      string
00464          */
00465         function slash_rsegment($n, $where = 'trailing')
00466         {
00467                 return $this->_slash_segment($n, $where, 'rsegment');
00468         }
00469         
00470         // --------------------------------------------------------------------
00471         
00472         /**
00473          * Fetch a URI Segment and add a trailing slash - helper function
00474          *
00475          * @access      private
00476          * @param       integer
00477          * @param       string
00478          * @param       string
00479          * @return      string
00480          */
00481         function _slash_segment($n, $where = 'trailing', $which = 'segment')
00482         {       
00483                 if ($where == 'trailing')
00484                 {
00485                         $trailing       = '/';
00486                         $leading        = '';
00487                 }
00488                 elseif ($where == 'leading')
00489                 {
00490                         $leading        = '/';
00491                         $trailing       = '';
00492                 }
00493                 else
00494                 {
00495                         $leading        = '/';
00496                         $trailing       = '/';
00497                 }
00498                 return $leading.$this->$which($n).$trailing;
00499         }
00500         
00501         // --------------------------------------------------------------------
00502         
00503         /**
00504          * Segment Array
00505          *
00506          * @access      public
00507          * @return      array
00508          */
00509         function segment_array()
00510         {
00511                 return $this->segments;
00512         }
00513 
00514         // --------------------------------------------------------------------
00515         
00516         /**
00517          * Routed Segment Array
00518          *
00519          * @access      public
00520          * @return      array
00521          */
00522         function rsegment_array()
00523         {
00524                 return $this->rsegments;
00525         }
00526         
00527         // --------------------------------------------------------------------
00528         
00529         /**
00530          * Total number of segments
00531          *
00532          * @access      public
00533          * @return      integer
00534          */
00535         function total_segments()
00536         {
00537                 return count($this->segments);
00538         }
00539 
00540         // --------------------------------------------------------------------
00541         
00542         /**
00543          * Total number of routed segments
00544          *
00545          * @access      public
00546          * @return      integer
00547          */
00548         function total_rsegments()
00549         {
00550                 return count($this->rsegments);
00551         }
00552         
00553         // --------------------------------------------------------------------
00554         
00555         /**
00556          * Fetch the entire URI string
00557          *
00558          * @access      public
00559          * @return      string
00560          */
00561         function uri_string()
00562         {
00563                 return $this->uri_string;
00564         }
00565 
00566         
00567         // --------------------------------------------------------------------
00568         
00569         /**
00570          * Fetch the entire Re-routed URI string
00571          *
00572          * @access      public
00573          * @return      string
00574          */
00575         function ruri_string()
00576         {
00577                 return '/'.implode('/', $this->rsegment_array()).'/';
00578         }
00579 
00580 }
00581 // END URI Class
00582 
00583 /* End of file URI.php */
00584 /* Location: ./system/libraries/URI.php */