eZ Publish  [4.0]
ezuri.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZURI class
00004 //
00005 // Created on: <10-Apr-2002 13:47:41 amos>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   \class eZURI ezuri.php
00033   \ingroup eZHTTP
00034   \brief Provides access to the HTTP uri
00035 
00036   The URI can be accessed one element at a time with element() and elements() and
00037   can be iterated with increase() and the current index returned with index(). Moving
00038   the beginning and end is done with toBeginning() and toEnd().
00039   The base can be retrieved with base() and the elements with elements().
00040 
00041   This class also supports the attribute system.
00042 
00043   \note The index starts at 0
00044 */
00045 
00046 class eZURI
00047 {
00048     /*!
00049      Initializes with the URI string $uri. The URI string is split on / into an array.
00050     */
00051     function eZURI( $uri )
00052     {
00053         $this->setURIString( $uri );
00054     }
00055 
00056     /*!
00057      \static
00058      Decodes a path string which is in IRI format and returns the new path in the internal encoding.
00059 
00060      More info on IRI here: http://www.w3.org/International/O-URL-and-ident.html
00061      */
00062     static function decodeIRI( $str )
00063     {
00064         $str = urldecode( $str ); // Decode %xx entries, we now have a utf-8 string
00065         $codec = eZTextCodec::instance( 'utf-8' ); // Make sure string is converted from utf-8 to internal encoding
00066         return $codec->convertString( $str );
00067     }
00068 
00069     /*!
00070      \static
00071      Encodes path string in internal encoding to a new string which conforms to the IRI specification.
00072 
00073      More info on IRI here: http://www.w3.org/International/O-URL-and-ident.html
00074      */
00075     static function encodeIRI( $str )
00076     {
00077         $codec = eZTextCodec::instance( false, 'utf-8' );
00078         $str = $codec->convertString( $str ); // Make sure the string is in utf-8
00079         $out = explode( "/", $str ); // Don't encode the slashes
00080         foreach ( $out as $i => $o )
00081         {
00082             if ( preg_match( "#^[\(]([a-zA-Z0-9_]+)[\)]#", $o, $m ) )
00083             {
00084                 // Don't encode '(' and ')' in user parameters
00085                 $out[$i] = '(' . urlencode( $m[1] ) . ')';
00086             }
00087             else
00088             {
00089                 $out[$i] = urlencode( $o ); // Let PHP do the rest
00090             }
00091         }
00092         $tmp = join( "/", $out );
00093         // Don't encode '~' in URLs
00094         $tmp = str_replace( '%7E', '~', $tmp );
00095         return $tmp;
00096     }
00097 
00098     /*!
00099      \static
00100      Parse URL and encode/decode its path string.
00101      */
00102     static function codecURL( $url, $encode )
00103     {
00104         $originalLocale = setlocale( LC_CTYPE, "0" );
00105         setlocale( LC_CTYPE, 'C' );
00106         // Parse URL and encode the path.
00107         $data = parse_url( $url );
00108         setlocale( LC_CTYPE, $originalLocale );
00109 
00110         if ( isset( $data['path'] ) )
00111         {
00112             if ( $encode )
00113                 $data['path'] = eZURI::encodeIRI( $data['path'] ); // Make sure it is encoded to IRI format
00114             else
00115                 $data['path'] = eZURI::decodeIRI( $data['path'] ); // Make sure it is dencoded to internal encoding
00116         }
00117 
00118         // Reconstruct the URL
00119         $host    = '';
00120         $preHost = '';
00121         if ( isset( $data['user'] ) )
00122         {
00123             if ( isset( $data['pass'] ) )
00124                 $preHost .= $data['user'] . ':' . $data['pass'] . '@';
00125             else
00126                 $preHost .= $data['user'] . '@';
00127         }
00128         if ( isset( $data['host'] ) )
00129         {
00130             if ( isset( $data['port'] ) )
00131                 $host = $preHost . $data['host'] . ':' . $data['port'];
00132             else
00133                 $host = $preHost . $data['host'];
00134         }
00135         $url = '';
00136         if ( isset( $data['scheme'] ) )
00137             $url = $data['scheme'] . '://' . $host;
00138         else if ( strlen( $host ) > 0 )
00139             $url = '//' . $host;
00140         if ( isset( $data['path'] ) )
00141         {
00142             $url .= $data['path'];
00143         }
00144         if ( isset( $data['query'] ) )
00145         {
00146             $url .= '?' . $data['query'];
00147         }
00148         if ( isset( $data['fragment'] ) )
00149         {
00150             $url .= '#' . $data['fragment'];
00151         }
00152 
00153         return $url;
00154     }
00155 
00156     /*!
00157      \static
00158      Encodes path string of URL in internal encoding to a new string which conforms to the IRI specification.
00159      */
00160     static function encodeURL( $url )
00161     {
00162         return eZURI::codecURL( $url, true );
00163     }
00164 
00165     /*!
00166      Decodes URL which has path string is in IRI format and returns the new URL with path in the internal encoding.
00167      */
00168     static function decodeURL( $url )
00169     {
00170         return eZURI::codecURL( $url, false );
00171     }
00172 
00173     /*!
00174      Sets the current URI string to $uri, the URI is then split into array elements
00175      and index reset to 1.
00176     */
00177     function setURIString( $uri, $fullInitialize = true )
00178     {
00179         if ( strlen( $uri ) > 0 and
00180              $uri[0] == '/' )
00181             $uri = substr( $uri, 1 );
00182 
00183         $uri = eZURI::decodeIRI( $uri );
00184 
00185         $this->URI = $uri;
00186         $this->URIArray = explode( '/', $uri );
00187         $this->Index = 0;
00188 
00189         if ( $fullInitialize )
00190         {
00191             $this->OriginalURI = $uri;
00192             $this->UserArray = array();
00193 
00194             //include_once( 'lib/ezutils/classes/ezini.php' );
00195             $ini = eZINI::instance( 'template.ini' );
00196 
00197             if ( $ini->variable( 'ControlSettings', 'OldStyleUserVariables' ) == 'enabled' )
00198             {
00199                 foreach( array_keys( $this->URIArray ) as $key )
00200                 {
00201                     if ( isset( $this->URIArray[$key] ) && preg_match( "(^[\(][a-zA-Z0-9_]+[\)])", $this->URIArray[$key] ) )
00202                     {
00203                         $this->UserArray[substr( $this->URIArray[$key], 1, strlen( $this->URIArray[$key] ) - 2 )] = $this->URIArray[$key+1];
00204                         unset( $this->URIArray[$key] );
00205                         unset( $this->URIArray[$key+1] );
00206                     }
00207                 }
00208             }
00209             else
00210             {
00211                 unset( $paramName );
00212                 unset( $paramValue );
00213                 foreach( array_keys( $this->URIArray ) as $key )
00214                 {
00215                     if ( isset( $this->URIArray[$key] ) )
00216                     {
00217                         if ( preg_match( "/^[\(][a-zA-Z0-9_]+[\)]/", $this->URIArray[$key] ) )
00218                         {
00219                             if ( isset( $paramName ) and isset( $paramValue ) )
00220                             {
00221                                 $this->UserArray[ $paramName ] = $paramValue;
00222                                 unset( $paramName );
00223                                 unset( $paramValue );
00224                             }
00225                             $paramName = substr( $this->URIArray[$key], 1, strlen( $this->URIArray[$key] ) - 2 );
00226                             if ( isset( $this->URIArray[$key+1] ) )
00227                             {
00228                                 $this->UserArray[ $paramName ] = $this->URIArray[$key+1];
00229                                 unset( $this->URIArray[$key+1] );
00230                             }
00231                             else
00232                                 $this->UserArray[ $paramName ] = "";
00233                             unset( $this->URIArray[$key] );
00234                         }
00235                         else
00236                         {
00237                             if ( isset( $paramName ) )
00238                             {
00239                                 if ( !empty( $this->URIArray[$key] ) )
00240                                     $this->UserArray[ $paramName ] .= '/' . $this->URIArray[$key];
00241                                 unset( $this->URIArray[$key] );
00242                             }
00243                         }
00244                     }
00245                 }
00246             }
00247 
00248             // Remake the URI without any user parameters
00249             $this->URI = implode( '/', $this->URIArray );
00250 
00251             //include_once( 'lib/ezutils/classes/ezini.php' );
00252             $ini = eZINI::instance( 'template.ini' );
00253             if ( $ini->variable( 'ControlSettings', 'AllowUserVariables' ) == 'false' )
00254             {
00255                 $this->UserArray = array();
00256             }
00257             // Convert filter string to current locale
00258             $this->convertFilterString();
00259         }
00260     }
00261 
00262     /*!
00263      \return the URI passed as to the object.
00264      \note the URI will not include the leading \c / if \a $withLeadingSlash is \c true.
00265     */
00266     function uriString( $withLeadingSlash = false )
00267     {
00268         $uri = $this->URI;
00269         if ( $withLeadingSlash )
00270             $uri = "/$uri";
00271         return $uri;
00272     }
00273 
00274     /*!
00275      \return the URI passed to the object with user parameters (if any).
00276      \note the URI will not include the leading \c / if \a $withLeadingSlash is \c true.
00277     */
00278     function originalURIString( $withLeadingSlash = false )
00279     {
00280         $uri = $this->OriginalURI;
00281         if ( $withLeadingSlash )
00282             $uri = "/$uri";
00283         return $uri;
00284     }
00285 
00286     /*!
00287      \return true if the URI is empty, ie it's equal to / or empty string.
00288     */
00289     function isEmpty()
00290     {
00291         return $this->URI == '' or $this->URI == '/';
00292     }
00293 
00294     /*!
00295      \return the element at $index.
00296      If $relative is true the index is relative to the current index().
00297     */
00298     function element( $index = 0, $relative = true )
00299     {
00300         $pos = $index;
00301         if ( $relative )
00302             $pos += $this->Index;
00303         if ( isset( $this->URIArray[$pos] ) )
00304             return $this->URIArray[$pos];
00305         $ret = null;
00306         return $ret;
00307     }
00308 
00309     /*!
00310      \return all elements as a string, this is all elements after the current index.
00311      If $as_text is false the returned item is an array.
00312     */
00313     function elements( $as_text = true )
00314     {
00315         $elements = array_slice( $this->URIArray, $this->Index );
00316         if ( $as_text )
00317         {
00318             $retValue = implode( '/', $elements );
00319             return $retValue;
00320         }
00321         else
00322             return $elements;
00323     }
00324 
00325     /*!
00326      Converts filter string to current locale.
00327      When an user types in browser url like:
00328      "/content/view/full/2/(namefilter)/a"
00329      'a' letter should be urldecoded and converted from utf-8 to current locale.
00330     */
00331     function convertFilterString()
00332     {
00333         foreach ( array_keys( $this->UserArray ) as $paramKey )
00334         {
00335             if ( $paramKey == 'namefilter' )
00336             {
00337                 $char = $this->UserArray[$paramKey];
00338                 $char = urldecode( $char );
00339 
00340                 //include_once( 'lib/ezi18n/classes/eztextcodec.php' );
00341                 $codec = eZTextCodec::instance( 'utf-8', false );
00342                 if ( $codec )
00343                     $char = $codec->convertString( $char );
00344             }
00345         }
00346     }
00347 
00348     /*
00349      \return all user defined variables
00350     */
00351     function userParameters()
00352     {
00353         return $this->UserArray;
00354     }
00355 
00356     /*!
00357      Moves the index to the beginning.
00358     */
00359     function toBeginning()
00360     {
00361         $this->Index = 0;
00362     }
00363 
00364     /*!
00365      Moves the index to the end.
00366     */
00367     function toEnd()
00368     {
00369         $this->Index = count( $this->URIArray );
00370     }
00371 
00372     /*!
00373      Moves the index 1 step up or $num if specified.
00374     */
00375     function increase( $num = 1 )
00376     {
00377         $this->Index += $num;
00378         if ( $this->Index < 0 )
00379             $this->Index = 0;
00380     }
00381 
00382     /*!
00383      Removes all elements below the current index, recreates the URI string
00384      and sets index to 0.
00385     */
00386     function dropBase()
00387     {
00388         $elements = array_slice( $this->URIArray, $this->Index );
00389         $this->URIArray = $elements;
00390         $this->URI = implode( '/', $this->URIArray );
00391         $uri = $this->URI;
00392         foreach ( $this->UserArray as $name => $value )
00393         {
00394             $uri .= '/(' . $name . ')/' . $value;
00395         }
00396         $this->OriginalURI = $uri;
00397         $this->Index = 0;
00398     }
00399 
00400     /*!
00401      \return the current index.
00402     */
00403     function index()
00404     {
00405         return $this->Index;
00406     }
00407 
00408     /*!
00409      \return the base string or the base elements as an array if $as_text is true.
00410      \sa elements
00411     */
00412     function base( $as_text = true )
00413     {
00414         $elements = array_slice( $this->URIArray, 0, $this->Index );
00415         if ( $as_text )
00416         {
00417             $baseAsText = '/' . implode( '/', $elements );
00418             return $baseAsText;
00419         }
00420         else
00421             return $elements;
00422     }
00423 
00424     /*!
00425      Tries to match the base of $uri against this base and returns the result.
00426      A match is made if all elements of this object match the base elements of
00427      the $uri object, this means that $uri's base may be longer than this base but
00428      not shorter.
00429      \note $uri must be a eZURI object
00430     */
00431     function matchBase( $uri )
00432     {
00433         if ( !( $uri instanceof eZURI ) )
00434         {
00435             return false;
00436         }
00437         if ( count( $this->URIArray ) == 0 or
00438              count( $uri->URIArray ) == 0 )
00439         {
00440             return false;
00441         }
00442         for ( $i = 0; $i < count( $this->URIArray ); ++$i )
00443         {
00444             if ( $this->URIArray[$i] != $uri->URIArray[$i] )
00445             {
00446                 return false;
00447             }
00448         }
00449         return true;
00450     }
00451 
00452     /*!
00453      \return the attributes for this object.
00454     */
00455     function attributes()
00456     {
00457         return array( 'element',
00458                       'base',
00459                       'tail',
00460                       'index',
00461                       'uri',
00462                       'original_uri' );
00463     }
00464 
00465     /*!
00466      \return true if the attribute $attr exist.
00467     */
00468     function hasAttribute( $attr )
00469     {
00470         return in_array( $attr, $this->attributes() );
00471     }
00472 
00473     /*!
00474      \return the value for attribute $attr or null if it does not exist.
00475     */
00476     function attribute( $attr )
00477     {
00478         switch ( $attr )
00479         {
00480             case 'element':
00481                 return $this->element();
00482                 break;
00483             case 'tail':
00484                 return $this->elements();
00485                 break;
00486             case 'base':
00487                 return $this->base();
00488                 break;
00489             case 'index':
00490                 return $this->index();
00491                 break;
00492             case 'uri':
00493                 return $this->uriString();
00494                 break;
00495             case 'original_uri':
00496                 return $this->originalURIString();
00497                 break;
00498             default:
00499             {
00500                 eZDebug::writeError( "Attribute '$attr' does not exist", 'eZURI::attribute' );
00501                 return null;
00502             } break;
00503         }
00504     }
00505 
00506     /*!
00507      \return the unique instance for the URI, if $uri is supplied it used as the global URI value.
00508     */
00509     static function instance( $uri = false )
00510     {
00511         // If $uri is false we assume the caller wants eZSys::requestURI()
00512         if ( $uri === false or $uri == eZSys::requestURI() )
00513         {
00514             if ( !isset( $GLOBALS['eZURIRequestInstance'] ) )
00515             {
00516                 $GLOBALS['eZURIRequestInstance'] = new eZURI( eZSys::requestURI() );
00517             }
00518             return $GLOBALS['eZURIRequestInstance'];
00519         }
00520 
00521         return new eZURI( $uri );
00522     }
00523 
00524     /*!
00525      Implementation of an 'ezurl' template operator.
00526      Makes valid ez publish urls to use in links.
00527     */
00528     static function transformURI( &$href, $ignoreIndexDir = false, $serverURL = 'relative' )
00529     {
00530         if ( preg_match( "#^[a-zA-Z0-9]+:#", $href ) || substr( $href, 0, 2 ) == '//' )
00531             return false;
00532 
00533         if ( strlen( $href ) == 0 )
00534             $href = '/';
00535         else if ( $href[0] == '#' )
00536         {
00537             $href = htmlspecialchars( $href );
00538             return true;
00539         }
00540         else if ( $href[0] != '/' )
00541         {
00542             $href = '/' . $href;
00543         }
00544 
00545         //include_once( 'lib/ezutils/classes/ezsys.php' );
00546         $sys = eZSys::instance();
00547         $dir = !$ignoreIndexDir ? $sys->indexDir() : $sys->wwwDir();
00548         $serverURL = $serverURL === 'full' ? $sys->serverURL() : '' ;
00549         $href = $serverURL . $dir . $href;
00550         if ( !$ignoreIndexDir )
00551         {
00552             $href = preg_replace( "#^(//)#", "/", $href );
00553             $href = preg_replace( "#(^.*)(/+)$#", "\$1", $href );
00554         }
00555         $href = htmlspecialchars( $href );
00556 
00557         if ( $href == "" )
00558             $href = "/";
00559 
00560         return true;
00561     }
00562 
00563     /// The original URI string
00564     public $URI;
00565     /// The URI array
00566     public $URIArray;
00567     /// The current index
00568     public $Index;
00569     /// User defined template variables
00570     public $UserArray;
00571 };
00572 
00573 ?>