|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZURI class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /** 00012 * Provides access to the HTTP uri 00013 00014 * The URI can be accessed one element at a time with element() and elements() and 00015 * can be iterated with increase() and the current index returned with index(). Movin 00016 * the beginning and end is done with toBeginning() and toEnd(). 00017 * The base can be retrieved with base() and the elements with elements(). 00018 * 00019 * This class also supports the attribute system. 00020 * 00021 * 00022 * The index starts at 0 00023 * 00024 * @package eZHTTP 00025 */ 00026 00027 class eZURI 00028 { 00029 /** 00030 * The original URI string 00031 * 00032 * @var string 00033 */ 00034 public $URI; 00035 00036 /** 00037 * The URI array 00038 * 00039 * @var array 00040 */ 00041 public $URIArray; 00042 00043 /** 00044 * The current index 00045 * 00046 * @var int 00047 */ 00048 public $Index; 00049 00050 /** 00051 * User defined template variables 00052 * 00053 * @var array 00054 */ 00055 public $UserArray; 00056 00057 /** 00058 * URI transformation mode used by transformURI(). 00059 * 00060 * @var string 00061 * 00062 * @see transformURI() 00063 * @see getTransformURIMode() 00064 * @see setTransformURIMode() 00065 */ 00066 private static $transformURIMode = "relative"; 00067 00068 /** 00069 * Initializes with the URI string $uri. The URI string is split on / into an array. 00070 * 00071 * @param string $uri the URI to use 00072 * @return void 00073 */ 00074 public function __construct( $uri ) 00075 { 00076 $this->setURIString( $uri ); 00077 } 00078 00079 /** 00080 * Decodes a path string which is in IRI format and returns the new path in the internal encoding. 00081 * 00082 * More info on IRI here: {@link http://www.w3.org/International/O-URL-and-ident.html} 00083 * 00084 * @param string $str the string to decode 00085 * @return string decoded version of $str 00086 */ 00087 public static function decodeIRI( $str ) 00088 { 00089 $str = urldecode( $str ); // Decode %xx entries, we now have a utf-8 string 00090 $codec = eZTextCodec::instance( 'utf-8' ); // Make sure string is converted from utf-8 to internal encoding 00091 return $codec->convertString( $str ); 00092 } 00093 00094 /** 00095 * Encodes path string in internal encoding to a new string which conforms to the IRI specification. 00096 * 00097 * More info on IRI here: {@link http://www.w3.org/International/O-URL-and-ident.html} 00098 * 00099 * @param string $str the IRI to encode 00100 * @return string $str encoded as IRU 00101 */ 00102 public static function encodeIRI( $str ) 00103 { 00104 $codec = eZTextCodec::instance( false, 'utf-8' ); 00105 $str = $codec->convertString( $str ); // Make sure the string is in utf-8 00106 $out = explode( "/", $str ); // Don't encode the slashes 00107 foreach ( $out as $i => $o ) 00108 { 00109 if ( preg_match( "#^[\(]([a-zA-Z0-9_]+)[\)]#", $o, $m ) ) 00110 { 00111 // Don't encode '(' and ')' in user parameters 00112 $out[$i] = '(' . urlencode( $m[1] ) . ')'; 00113 } 00114 else 00115 { 00116 $out[$i] = urlencode( $o ); // Let PHP do the rest 00117 } 00118 } 00119 $tmp = join( "/", $out ); 00120 // Don't encode '~' in URLs 00121 $tmp = str_replace( '%7E', '~', $tmp ); 00122 return $tmp; 00123 } 00124 00125 /** 00126 * Parse URL and encode/decode its path string 00127 * 00128 * @param string $url the URL to parse 00129 * @param boolean $encode tells to encode the URI 00130 * @return string the parsed url 00131 */ 00132 public static function codecURL( $url, $encode ) 00133 { 00134 $originalLocale = setlocale( LC_CTYPE, "0" ); 00135 setlocale( LC_CTYPE, 'C' ); 00136 // Parse URL and encode the path. 00137 $data = parse_url( $url ); 00138 setlocale( LC_CTYPE, $originalLocale ); 00139 00140 if ( isset( $data['path'] ) ) 00141 { 00142 if ( $encode ) 00143 $data['path'] = eZURI::encodeIRI( $data['path'] ); // Make sure it is encoded to IRI format 00144 else 00145 $data['path'] = eZURI::decodeIRI( $data['path'] ); // Make sure it is dencoded to internal encoding 00146 } 00147 00148 // Reconstruct the URL 00149 $host = ''; 00150 $preHost = ''; 00151 if ( isset( $data['user'] ) ) 00152 { 00153 if ( isset( $data['pass'] ) ) 00154 $preHost .= $data['user'] . ':' . $data['pass'] . '@'; 00155 else 00156 $preHost .= $data['user'] . '@'; 00157 } 00158 if ( isset( $data['host'] ) ) 00159 { 00160 if ( isset( $data['port'] ) ) 00161 $host = $preHost . $data['host'] . ':' . $data['port']; 00162 else 00163 $host = $preHost . $data['host']; 00164 } 00165 $url = ''; 00166 if ( isset( $data['scheme'] ) ) 00167 $url = $data['scheme'] . '://' . $host; 00168 else if ( strlen( $host ) > 0 ) 00169 $url = '//' . $host; 00170 if ( isset( $data['path'] ) ) 00171 { 00172 $url .= $data['path']; 00173 } 00174 if ( isset( $data['query'] ) ) 00175 { 00176 $url .= '?' . $data['query']; 00177 } 00178 if ( isset( $data['fragment'] ) ) 00179 { 00180 $url .= '#' . $data['fragment']; 00181 } 00182 00183 return $url; 00184 } 00185 00186 /** 00187 * Encodes path string of URL in internal encoding to a new string which conforms to the IRI specification. 00188 * 00189 * @param type $url 00190 * @return string the encoded url 00191 */ 00192 public static function encodeURL( $url ) 00193 { 00194 return eZURI::codecURL( $url, true ); 00195 } 00196 00197 /** 00198 * Decodes URL which has path string is in IRI format and returns the new URL with path in the internal encoding. 00199 * 00200 * @param string $url url to decode 00201 * @return string the decoded url 00202 */ 00203 public static function decodeURL( $url ) 00204 { 00205 return eZURI::codecURL( $url, false ); 00206 } 00207 00208 /** 00209 * Sets uri string for instance 00210 * 00211 * Sets the current URI string to $uri, the URI is then split into array elements 00212 * and index reset to 1. 00213 * 00214 * @param string $uri 00215 * @param boolean $fullInitialize 00216 * @return void 00217 */ 00218 public function setURIString( $uri, $fullInitialize = true ) 00219 { 00220 if ( strlen( $uri ) > 0 and 00221 $uri[0] == '/' ) 00222 $uri = substr( $uri, 1 ); 00223 00224 $uri = eZURI::decodeIRI( $uri ); 00225 00226 $this->URI = $uri; 00227 $this->URIArray = explode( '/', $uri ); 00228 $this->Index = 0; 00229 00230 if ( $fullInitialize ) 00231 { 00232 $this->OriginalURI = $uri; 00233 $this->UserArray = array(); 00234 00235 $ini = eZINI::instance( 'template.ini' ); 00236 00237 if ( $ini->variable( 'ControlSettings', 'OldStyleUserVariables' ) == 'enabled' ) 00238 { 00239 foreach( array_keys( $this->URIArray ) as $key ) 00240 { 00241 if ( isset( $this->URIArray[$key] ) && preg_match( "(^[\(][a-zA-Z0-9_]+[\)])", $this->URIArray[$key] ) ) 00242 { 00243 $this->UserArray[substr( $this->URIArray[$key], 1, strlen( $this->URIArray[$key] ) - 2 )] = $this->URIArray[$key+1]; 00244 unset( $this->URIArray[$key] ); 00245 unset( $this->URIArray[$key+1] ); 00246 } 00247 } 00248 } 00249 else 00250 { 00251 unset( $paramName ); 00252 unset( $paramValue ); 00253 foreach( array_keys( $this->URIArray ) as $key ) 00254 { 00255 if ( isset( $this->URIArray[$key] ) ) 00256 { 00257 if ( preg_match( "/^[\(][a-zA-Z0-9_]+[\)]/", $this->URIArray[$key] ) ) 00258 { 00259 if ( isset( $paramName ) and isset( $paramValue ) ) 00260 { 00261 $this->UserArray[ $paramName ] = $paramValue; 00262 unset( $paramName ); 00263 unset( $paramValue ); 00264 } 00265 $paramName = substr( $this->URIArray[$key], 1, strlen( $this->URIArray[$key] ) - 2 ); 00266 if ( isset( $this->URIArray[$key+1] ) ) 00267 { 00268 $this->UserArray[ $paramName ] = $this->URIArray[$key+1]; 00269 unset( $this->URIArray[$key+1] ); 00270 } 00271 else 00272 $this->UserArray[ $paramName ] = ""; 00273 unset( $this->URIArray[$key] ); 00274 } 00275 else 00276 { 00277 if ( isset( $paramName ) ) 00278 { 00279 if ( !empty( $this->URIArray[$key] ) ) 00280 $this->UserArray[ $paramName ] .= '/' . $this->URIArray[$key]; 00281 unset( $this->URIArray[$key] ); 00282 } 00283 } 00284 } 00285 } 00286 } 00287 00288 // Remake the URI without any user parameters 00289 $this->URI = implode( '/', $this->URIArray ); 00290 00291 $ini = eZINI::instance( 'template.ini' ); 00292 if ( $ini->variable( 'ControlSettings', 'AllowUserVariables' ) == 'false' ) 00293 { 00294 $this->UserArray = array(); 00295 } 00296 // Convert filter string to current locale 00297 $this->convertFilterString(); 00298 } 00299 } 00300 00301 /** 00302 * Get the uri string 00303 * 00304 * The URI will not include the leading / if $withLeadingSlash is true. 00305 * 00306 * @param boolean $withLeadingSlash prefix the uri with / 00307 * @return string the URI passed as to the object 00308 */ 00309 public function uriString( $withLeadingSlash = false ) 00310 { 00311 $uri = $this->URI; 00312 if ( $withLeadingSlash ) 00313 $uri = "/$uri"; 00314 return $uri; 00315 } 00316 00317 /** 00318 * Return the original URI 00319 * 00320 * the URI will not include the leading / if $withLeadingSlash is true. 00321 * 00322 * @param boolean $withLeadingSlash prefix the uri with / 00323 * @return string the URI passed to the object with user parameters (if any). 00324 */ 00325 public function originalURIString( $withLeadingSlash = false ) 00326 { 00327 $uri = $this->OriginalURI; 00328 if ( $withLeadingSlash ) 00329 $uri = "/$uri"; 00330 return $uri; 00331 } 00332 00333 /** 00334 * Check if there URI is set 00335 * 00336 * @return boolean true if the URI is empty, ie it's equal to / or empty string. 00337 */ 00338 public function isEmpty() 00339 { 00340 return $this->URI == '' or $this->URI == '/'; 00341 } 00342 00343 /** 00344 * Get element index from uri 00345 * 00346 * @param integer $index the index of URI to return 00347 * @param boolean $relative if index is relative to the internal pointer 00348 * @return string|null the element at $index 00349 */ 00350 public function element( $index = 0, $relative = true ) 00351 { 00352 $pos = $index; 00353 if ( $relative ) 00354 $pos += $this->Index; 00355 if ( isset( $this->URIArray[$pos] ) ) 00356 return $this->URIArray[$pos]; 00357 $ret = null; 00358 return $ret; 00359 } 00360 00361 /** 00362 * Return all URI elements 00363 * 00364 * @param boolean $as_text return the elements as string 00365 * @return array|string all elements as string/array depending on $as_text 00366 */ 00367 public function elements( $as_text = true ) 00368 { 00369 $elements = array_slice( $this->URIArray, $this->Index ); 00370 if ( $as_text ) 00371 { 00372 $retValue = implode( '/', $elements ); 00373 return $retValue; 00374 } 00375 else 00376 return $elements; 00377 } 00378 00379 /** 00380 * Converts filter string to current locale. When an user types in browser 00381 * url like: "/content/view/full/2/(namefilter)/a" 'a' letter should be 00382 * urldecoded and converted from utf-8 to current locale. 00383 * 00384 * @return string converted string 00385 */ 00386 public function convertFilterString() 00387 { 00388 foreach ( array_keys( $this->UserArray ) as $paramKey ) 00389 { 00390 if ( $paramKey == 'namefilter' ) 00391 { 00392 $char = $this->UserArray[$paramKey]; 00393 $char = urldecode( $char ); 00394 00395 $codec = eZTextCodec::instance( 'utf-8', false ); 00396 if ( $codec ) 00397 $char = $codec->convertString( $char ); 00398 } 00399 } 00400 } 00401 00402 /** 00403 * Get user variables 00404 * 00405 * @return array all the user defined variables 00406 */ 00407 public function userParameters() 00408 { 00409 return $this->UserArray; 00410 } 00411 00412 /** 00413 * Reset the internal pointer 00414 * 00415 * @return void 00416 */ 00417 public function toBeginning() 00418 { 00419 $this->Index = 0; 00420 } 00421 00422 /** 00423 * Moves the index to the end. 00424 * 00425 * @return void 00426 */ 00427 public function toEnd() 00428 { 00429 $this->Index = count( $this->URIArray ); 00430 } 00431 00432 /** 00433 * Moves the index 1 step up or $num if specified. 00434 * 00435 * @param int $num number of steps to move pointer 00436 * @return void 00437 */ 00438 public function increase( $num = 1 ) 00439 { 00440 $this->Index += $num; 00441 if ( $this->Index < 0 ) 00442 $this->Index = 0; 00443 } 00444 00445 /** 00446 * Removes all elements below the current index, recreates the URI string 00447 * and sets index to 0. 00448 * 00449 * @return void 00450 */ 00451 public function dropBase() 00452 { 00453 $elements = array_slice( $this->URIArray, $this->Index ); 00454 $this->URIArray = $elements; 00455 $this->URI = implode( '/', $this->URIArray ); 00456 $uri = $this->URI; 00457 foreach ( $this->UserArray as $name => $value ) 00458 { 00459 $uri .= '/(' . $name . ')/' . $value; 00460 } 00461 $this->OriginalURI = $uri; 00462 $this->Index = 0; 00463 } 00464 00465 /** 00466 * Return the current position of pointer 00467 * 00468 * @return int the current pointer position. 00469 */ 00470 public function index() 00471 { 00472 return $this->Index; 00473 } 00474 00475 /** 00476 * Return the elements before pointer 00477 * 00478 * @param type $as_text return as text or array 00479 * @return string|array the base string or the base elements as an array if $as_text is true. 00480 */ 00481 public function base( $as_text = true ) 00482 { 00483 $elements = array_slice( $this->URIArray, 0, $this->Index ); 00484 if ( $as_text ) 00485 { 00486 $baseAsText = '/' . implode( '/', $elements ); 00487 return $baseAsText; 00488 } 00489 else 00490 return $elements; 00491 } 00492 00493 /** 00494 * Tries to match the base of $uri against this base and returns the result. 00495 * A match is made if all elements of this object match the base elements of 00496 * the $uri object, this means that $uri's base may be longer than this base but 00497 * not shorter. 00498 * 00499 * @param eZURI $uri the uri to match against 00500 * @return boolean 00501 */ 00502 public function matchBase( eZURI $uri ) 00503 { 00504 if ( !( $uri instanceof eZURI ) ) 00505 { 00506 return false; 00507 } 00508 if ( count( $this->URIArray ) == 0 or 00509 count( $uri->URIArray ) == 0 ) 00510 { 00511 return false; 00512 } 00513 for ( $i = 0; $i < count( $this->URIArray ); ++$i ) 00514 { 00515 if ( $this->URIArray[$i] != $uri->URIArray[$i] ) 00516 { 00517 return false; 00518 } 00519 } 00520 return true; 00521 } 00522 00523 /** 00524 * Export all attributes of the object 00525 * 00526 * @return array the attributes for the object 00527 */ 00528 public function attributes() 00529 { 00530 return array( 'element', 00531 'base', 00532 'tail', 00533 'index', 00534 'uri', 00535 'original_uri', 00536 'query_string' ); 00537 } 00538 00539 /** 00540 * Check if attribute exsits 00541 * 00542 * @param string $attr the attrbiute to check if exists 00543 * @return boolean 00544 */ 00545 public function hasAttribute( $attr ) 00546 { 00547 return in_array( $attr, $this->attributes() ); 00548 } 00549 00550 /** 00551 * Get value for an attribute 00552 * 00553 * @param string $attr 00554 * @return boolean the value for attribute $attr or null if it does not exist. 00555 */ 00556 public function attribute( $attr ) 00557 { 00558 switch ( $attr ) 00559 { 00560 case 'element': 00561 return $this->element(); 00562 break; 00563 case 'tail': 00564 return $this->elements(); 00565 break; 00566 case 'base': 00567 return $this->base(); 00568 break; 00569 case 'index': 00570 return $this->index(); 00571 break; 00572 case 'uri': 00573 return $this->uriString(); 00574 break; 00575 case 'original_uri': 00576 return $this->originalURIString(); 00577 break; 00578 case 'query_string': 00579 return eZSys::queryString(); 00580 break; 00581 default: 00582 { 00583 eZDebug::writeError( "Attribute '$attr' does not exist", __METHOD__ ); 00584 return null; 00585 } break; 00586 } 00587 } 00588 00589 /** 00590 * Returns a shared instance of the eZURI class IF $uri is false or the same as current 00591 * request uri, if not then a new non shared instance is created. 00592 * 00593 * @param false|string $uri Shared uri instance if false 00594 * @return eZURI 00595 */ 00596 public static function instance( $uri = false ) 00597 { 00598 // If $uri is false we assume the caller wants eZSys::requestURI() 00599 if ( $uri === false or $uri == eZSys::requestURI() ) 00600 { 00601 if ( !isset( $GLOBALS['eZURIRequestInstance'] ) ) 00602 { 00603 $GLOBALS['eZURIRequestInstance'] = new eZURI( eZSys::requestURI() ); 00604 } 00605 return $GLOBALS['eZURIRequestInstance']; 00606 } 00607 00608 return new eZURI( $uri ); 00609 } 00610 00611 /** 00612 * Implementation of an 'ezurl' template operator 00613 * Makes valid eZ Publish urls to use in links 00614 * 00615 * @param string &$href 00616 * @param boolean $ignoreIndexDir 00617 * @param string $serverURL full|relative 00618 * @return string the link to use 00619 */ 00620 public static function transformURI( &$href, $ignoreIndexDir = false, $serverURL = null ) 00621 { 00622 if ( $serverURL === null ) 00623 { 00624 $serverURL = self::$transformURIMode; 00625 } 00626 00627 if ( preg_match( "#^[a-zA-Z0-9]+:#", $href ) || substr( $href, 0, 2 ) == '//' ) 00628 return false; 00629 00630 if ( strlen( $href ) == 0 ) 00631 $href = '/'; 00632 else if ( $href[0] == '#' ) 00633 { 00634 $href = htmlspecialchars( $href ); 00635 return true; 00636 } 00637 else if ( $href[0] != '/' ) 00638 { 00639 $href = '/' . $href; 00640 } 00641 00642 $sys = eZSys::instance(); 00643 $dir = !$ignoreIndexDir ? $sys->indexDir() : $sys->wwwDir(); 00644 $serverURL = $serverURL === 'full' ? $sys->serverURL() : '' ; 00645 $href = $serverURL . $dir . $href; 00646 if ( !$ignoreIndexDir ) 00647 { 00648 $href = preg_replace( "#^(//)#", "/", $href ); 00649 $href = preg_replace( "#(^.*)(/+)$#", "\$1", $href ); 00650 } 00651 $href = str_replace( '&amp;', '&', htmlspecialchars( $href ) ); 00652 00653 if ( $href == "" ) 00654 $href = "/"; 00655 00656 return true; 00657 } 00658 00659 /** 00660 * Returns the current mode used for transformURI(). 00661 * 00662 * @see transformURI() 00663 * @see setTransformURIMode() 00664 * 00665 * @return string 00666 */ 00667 public static function getTransformURIMode() 00668 { 00669 return self::$transformURIMode; 00670 } 00671 00672 /** 00673 * Sets the current mode used for transformURI() to $mode. 00674 * 00675 * @see transformURI() 00676 * @see getTransformURIMode() 00677 * 00678 * @param string $mode 00679 */ 00680 public static function setTransformURIMode( $mode ) 00681 { 00682 self::$transformURIMode = $mode; 00683 } 00684 00685 } 00686 00687 ?>