|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZSys class. 00004 * 00005 * Portions are modifications of patches by Andreas Böckler and Francis Nart 00006 * 00007 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00008 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00009 * @version //autogentag// 00010 * @package lib 00011 */ 00012 00013 /** 00014 * Easy access to various system settings 00015 * 00016 * The system is checked to see whether a virtualhost-less setup is used and 00017 * sets the appropriate variables which can be fetched with siteDir(), wwwDir() 00018 * and indexFile(). 00019 * It also detects file and environment separators, fetch them with 00020 * fileSeparator() and envSeparator(). 00021 * 00022 * <code> 00023 * // Run the init in the index file 00024 * eZSys::init( 'index.php', $ini->variable( 'SiteAccessSettings', 'ForceVirtualHost' ) === 'true' ); 00025 * echo eZSys::indexFile(); 00026 * echo eZSys::wwwDir(); 00027 * </code> 00028 * 00029 * @package lib 00030 * @subpackage ezutils 00031 */ 00032 class eZSys 00033 { 00034 /** 00035 * The line separator used in files, "\n" / "\n\r" / "\r" 00036 * 00037 * @var string 00038 */ 00039 public $LineSeparator; 00040 00041 /** 00042 * The directory separator used for files, '/' or '\' 00043 * 00044 * @var string 00045 */ 00046 public $FileSeparator; 00047 00048 /** 00049 * The list separator used for env variables (':' or ';') 00050 * 00051 * @var string 00052 */ 00053 public $EnvSeparator; 00054 00055 /** 00056 * The absolute path to the root directory. 00057 * 00058 * @var string 00059 */ 00060 public $RootDir; 00061 00062 /** 00063 * The system path to where all the code resides 00064 * 00065 * @var string 00066 */ 00067 public $SiteDir; 00068 00069 /** 00070 * The access path of the current site view, associated array of associated arrays. 00071 * 00072 * On first level key is 'siteaccess' and 'path' to distinguish between siteaccess 00073 * and general path. On second level you have (string)'name' and (array)'url', 00074 * where url is the path and name is the name of the source (used to match siteaccess 00075 * in {@link eZSys::indexFile()} for RemoveSiteAccessIfDefaultAccess matching) . 00076 * 00077 * @var array 00078 */ 00079 protected $AccessPath; 00080 00081 /** 00082 * The relative directory path of the vhless setup 00083 * 00084 * @var string 00085 */ 00086 public $WWWDir; 00087 00088 /** 00089 * The index file name (eg: 'index.php') 00090 * 00091 * @var string 00092 */ 00093 public $IndexFile; 00094 00095 /** 00096 * The uri which is used for parsing module/view information from, may differ from $_SERVER['REQUEST_URI'] 00097 * 00098 * @var string 00099 */ 00100 public $RequestURI; 00101 00102 /** 00103 * The type of filesystem, is either win32 or unix. This often used to determine OS specific paths. 00104 * 00105 * @var string 00106 */ 00107 public $FileSystemType; 00108 00109 /** 00110 * The character to be used in shell escaping, this character is OS specific 00111 * 00112 * @var stringt 00113 */ 00114 public $ShellEscapeCharacter; 00115 00116 /** 00117 * The type of OS, is either win32, mac or unix. 00118 * 00119 * @var string 00120 */ 00121 public $OSType; 00122 00123 /** 00124 * Holds server variables as read automatically or provided by unit tests 00125 * Only used by init functionality as other calls will need to use live data direclty from globals. 00126 * 00127 * @var array 00128 */ 00129 protected $Params; 00130 00131 /** 00132 * Holds eZSys instance 00133 * 00134 * @var eZSys|null 00135 */ 00136 protected static $instance = null; 00137 00138 /** 00139 * Query string for the current request 00140 * In the form of "?param1=value1¶m2=value2 00141 * 00142 * @var string 00143 */ 00144 protected $QueryString; 00145 00146 /** 00147 * Initialize the object with settings taken from the current script run. 00148 * 00149 * @param array $serverParams For unit testing use, see first few lines for content 00150 */ 00151 public function __construct( array $serverParams = array() ) 00152 { 00153 $this->Params = $serverParams + array( 00154 'PHP_OS' => PHP_OS, 00155 'DIRECTORY_SEPARATOR' => DIRECTORY_SEPARATOR, 00156 'PATH_SEPARATOR' => PATH_SEPARATOR, 00157 '_SERVER' => $_SERVER, 00158 ); 00159 00160 if ( isset( $this->Params['_SERVER']['REQUEST_TIME'] ) ) 00161 { 00162 // REQUEST_TIME is a float and includes microseconds in PHP > 5.4.0 00163 // It should be casted to int in order to keep BC 00164 $this->Params['_SERVER']['REQUEST_TIME'] = (int)$this->Params['_SERVER']['REQUEST_TIME']; 00165 } 00166 00167 $this->Attributes = array( 'magickQuotes' => true, 00168 'hostname' => true ); 00169 $this->FileSeparator = $this->Params['DIRECTORY_SEPARATOR']; 00170 $this->EnvSeparator = $this->Params['PATH_SEPARATOR']; 00171 00172 // Determine OS specific settings 00173 if ( $this->Params['PHP_OS'] === 'WINNT' ) 00174 { 00175 $this->OSType = "win32"; 00176 $this->OS = "windows"; 00177 $this->FileSystemType = "win32"; 00178 $this->LineSeparator = "\r\n"; 00179 $this->ShellEscapeCharacter = '"'; 00180 $this->BackupFilename = '.bak'; 00181 } 00182 else 00183 { 00184 $this->OSType = 'unix'; 00185 if ( $this->Params['PHP_OS'] === 'Linux' ) 00186 { 00187 $this->OS = 'linux'; 00188 } 00189 else if ( $this->Params['PHP_OS'] === 'FreeBSD' ) 00190 { 00191 $this->OS = 'freebsd'; 00192 } 00193 else if ( $this->Params['PHP_OS'] === 'Darwin' ) 00194 { 00195 $this->OS = 'darwin'; 00196 } 00197 else 00198 { 00199 $this->OS = false; 00200 } 00201 $this->FileSystemType = "unix"; 00202 $this->LineSeparator = "\n"; 00203 $this->ShellEscapeCharacter = "'"; 00204 $this->BackupFilename = '~'; 00205 } 00206 00207 if ( get_magic_quotes_gpc() == 1 ) 00208 { 00209 self::removeMagicQuotes(); 00210 } 00211 00212 $this->AccessPath = array( 'siteaccess' => array( 'name' => '', 'url' => array() ), 00213 'path' => array( 'name' => '', 'url' => array() ) ); 00214 } 00215 00216 /** 00217 * Removes magic quotes 00218 * 00219 * @deprecated Since 4.5, magic quotes setting has been deprecated in PHP 5.3 00220 * 00221 * @return void 00222 */ 00223 public static function removeMagicQuotes() 00224 { 00225 $globalVariables = array( '_SERVER', '_ENV' ); 00226 foreach ( $globalVariables as $globalVariable ) 00227 { 00228 foreach ( array_keys( $GLOBALS[$globalVariable] ) as $key ) 00229 { 00230 if ( !is_array( $GLOBALS[$globalVariable][$key] ) ) 00231 { 00232 $GLOBALS[$globalVariable][$key] = stripslashes( $GLOBALS[$globalVariable][$key] ); 00233 } 00234 } 00235 } 00236 } 00237 00238 /** 00239 * Returns the OS type 00240 * 00241 * Possible values: win32, unix 00242 * 00243 * @return string 00244 */ 00245 public static function osType() 00246 { 00247 return self::instance()->OSType; 00248 } 00249 00250 /** 00251 * Returns the current OS name or false if it can not be determined. 00252 * 00253 * Possible values: windows, linux, freebsd, darwin 00254 * 00255 * @return string|bool 00256 */ 00257 public static function osName() 00258 { 00259 return self::instance()->OS; 00260 } 00261 00262 /** 00263 * Returns the filesystem type 00264 * 00265 * Possible values: win32, unix 00266 * 00267 * @return string 00268 */ 00269 public static function filesystemType() 00270 { 00271 return self::instance()->FileSystemType; 00272 } 00273 00274 /** 00275 * Returns the string used as the file separator on the current system 00276 * 00277 * @return string 00278 */ 00279 public static function fileSeparator() 00280 { 00281 return self::instance()->FileSeparator; 00282 } 00283 00284 /** 00285 * The PHP version as text. 00286 * 00287 * @deprecated Since 4.5, use PHP_VERSION 00288 * 00289 * @return string 00290 */ 00291 public static function phpVersionText() 00292 { 00293 return PHP_VERSION; 00294 } 00295 00296 /** 00297 * Returns the PHP version as an array with the version elements. 00298 * 00299 * @deprecated Since 4.5 00300 * 00301 * @return array 00302 */ 00303 public static function phpVersion() 00304 { 00305 $elements = explode( '.', PHP_VERSION ); 00306 return $elements; 00307 } 00308 00309 /** 00310 * Checks if the given version is greater than or equal to the current PHP version 00311 * 00312 * Usage: 00313 * <code> 00314 * eZSys::isPHPVersionSufficient( array( 4, 1, 0 ) ); 00315 * </code> 00316 * 00317 * @deprecated Since 4.5 00318 * @param array $requiredVersion Must be an array with version number 00319 * @return bool 00320 */ 00321 static function isPHPVersionSufficient( $requiredVersion ) 00322 { 00323 if ( !is_array( $requiredVersion ) ) 00324 return false; 00325 $phpVersion = self::phpVersion(); 00326 $len = min( count( $phpVersion ), count( $requiredVersion ) ); 00327 00328 for ( $i = 0; $i < $len; ++$i ) 00329 { 00330 if ( (int) $phpVersion[$i] > (int) $requiredVersion[$i] ) 00331 return true; 00332 if ( (int) $phpVersion[$i] < (int) $requiredVersion[$i] ) 00333 return false; 00334 } 00335 00336 return true; 00337 } 00338 00339 /** 00340 * Determines if the current process has been started from the web or the shell 00341 * 00342 * @return bool 00343 */ 00344 public static function isShellExecution() 00345 { 00346 $sapiType = php_sapi_name(); 00347 00348 if ( $sapiType == 'cli' ) 00349 return true; 00350 00351 // For CGI we have to check, if the script has been executed over shell. 00352 // Currently it looks like the HTTP_HOST variable is the most reasonable to check. 00353 if ( substr( $sapiType, 0, 3 ) == 'cgi' ) 00354 { 00355 if ( !self::serverVariable( 'HTTP_HOST', true ) ) 00356 return true; 00357 else 00358 return false; 00359 } 00360 return false; 00361 } 00362 00363 /** 00364 * Returns an escaped string to be used as a shell argument 00365 * 00366 * @param string $argument 00367 * @return string 00368 */ 00369 public static function escapeShellArgument( $argument ) 00370 { 00371 $escapeChar = self::instance()->ShellEscapeCharacter; 00372 $argument = str_replace( "\\", "\\\\", $argument ); 00373 if ( $escapeChar == "'" ) 00374 { 00375 $argument = str_replace( $escapeChar, $escapeChar . "\\" . $escapeChar . $escapeChar, $argument ); 00376 } 00377 else 00378 { 00379 $argument = str_replace( $escapeChar, "\\" . $escapeChar, $argument ); 00380 } 00381 $argument = $escapeChar . $argument . $escapeChar; 00382 return $argument; 00383 } 00384 00385 /** 00386 * Replaces % elements in $argumentText using $replaceList, and also 00387 * properly escape the argument 00388 * 00389 * @param string $argumentText 00390 * @param array $replaceList 00391 * @return string 00392 */ 00393 public static function createShellArgument( $argumentText, array $replaceList ) 00394 { 00395 $instance = self::instance(); 00396 $elements = $instance->splitArgumentIntoElements( $argumentText ); 00397 $replacedElements = array(); 00398 foreach ( $elements as $element ) 00399 { 00400 if ( is_string( $element ) ) 00401 { 00402 $replacedElements[] = strtr( $element, $replaceList ); 00403 continue; 00404 } 00405 $replacedElements[] = $element; 00406 } 00407 $text = $instance->mergeArgumentElements( $replacedElements ); 00408 return $text; 00409 } 00410 00411 /** 00412 * Splits $argumentText on boundaries formed by one or more spaces and save 00413 * them into an array of separate arguments. 00414 * 00415 * The number of spaces between to arguments is inserted as an integer value 00416 * between two argument values. 00417 * 00418 * Example: 00419 * <code> 00420 * $list = splitArgumentIntoElements( "-geometry 100x100" ); 00421 * var_dump( $list ); // Output: array( "-geometry", 1, "100x100" ); 00422 * </code> 00423 * 00424 * You can then easily modify the elements separately and create the argument 00425 * text with eZSys::mergeArgumentElements() 00426 * 00427 * @param string $argumentText 00428 * @return array 00429 */ 00430 public static function splitArgumentIntoElements( $argumentText ) 00431 { 00432 $argumentElements = array(); 00433 $pos = 0; 00434 00435 while ( $pos < strlen( $argumentText ) ) 00436 { 00437 if ( $argumentText[$pos] == '"' || $argumentText[$pos] == "'" ) 00438 { 00439 $quoteStartPos = $pos + 1; 00440 $quoteEndPos = $pos + 1; 00441 00442 while ( $quoteEndPos < strlen( $argumentText ) ) 00443 { 00444 $tmpPos = strpos( $argumentText, $argumentText[$pos], $quoteEndPos ); 00445 00446 if ( $tmpPos !== false && $argumentText[$tmpPos - 1] != "\\" ) 00447 { 00448 $quoteEndPos = $tmpPos; 00449 break; 00450 } 00451 00452 if ( $tmpPos === false ) 00453 { 00454 $quoteEndPos = strlen( $argumentText ); 00455 break; 00456 } 00457 $quoteEndPos = $tmpPos + 1; 00458 } 00459 00460 $argumentElements[] = substr( $argumentText, $quoteStartPos, $quoteEndPos - $quoteStartPos ); 00461 $pos = $quoteEndPos + 1; 00462 } 00463 else if ( $argumentText[$pos] == ' ' ) 00464 { 00465 $spacePos = $pos; 00466 $spaceEndPos = $pos; 00467 while ( $spaceEndPos < strlen( $argumentText ) ) 00468 { 00469 if ( $argumentText[$spaceEndPos] != ' ' ) 00470 { 00471 break; 00472 } 00473 ++$spaceEndPos; 00474 } 00475 $spaceText = substr( $argumentText, $spacePos, $spaceEndPos - $spacePos ); 00476 $spaceCount = strlen( $spaceText ); 00477 if ( $spaceCount > 0 ) 00478 { 00479 $argumentElements[] = $spaceCount; 00480 } 00481 00482 $pos = $spaceEndPos; 00483 } 00484 else 00485 { 00486 $spacePos = strpos( $argumentText, ' ', $pos ); 00487 00488 if ( $spacePos !== false ) 00489 { 00490 $argumentElements[] = substr( $argumentText, $pos, $spacePos - $pos ); 00491 $spaceEndPos = $spacePos + 1; 00492 00493 while ( $spaceEndPos < strlen( $argumentText ) ) 00494 { 00495 if ( $argumentText[$spaceEndPos] != ' ' ) 00496 { 00497 break; 00498 } 00499 ++$spaceEndPos; 00500 } 00501 00502 $spaceText = substr( $argumentText, $spacePos, $spaceEndPos - $spacePos ); 00503 $spaceCount = strlen( $spaceText ); 00504 00505 if ( $spaceCount > 0 ) 00506 { 00507 $argumentElements[] = $spaceCount; 00508 } 00509 $pos = $spaceEndPos; 00510 } 00511 else 00512 { 00513 $argumentElements[] = substr( $argumentText, $pos ); 00514 $pos = strlen( $argumentText ); 00515 } 00516 } 00517 } 00518 00519 return $argumentElements; 00520 } 00521 00522 /** 00523 * Merges an argument list created by eZSys::splitArgumentIntoElements() 00524 * back into a text string 00525 * 00526 * @param array $argumentElements 00527 * @return string 00528 */ 00529 public static function mergeArgumentElements( array $argumentElements ) 00530 { 00531 $instance = self::instance(); 00532 $argumentText = ''; 00533 foreach ( $argumentElements as $element ) 00534 { 00535 if ( is_int( $element ) ) 00536 { 00537 $argumentText .= str_repeat( ' ', $element ); 00538 } 00539 else if ( is_string( $element ) ) 00540 { 00541 $argumentText .= $instance->escapeShellArgument( $element ); 00542 } 00543 } 00544 return $argumentText; 00545 } 00546 00547 /** 00548 * Returns the backup filename for this platform 00549 * 00550 * Possible values: .bak (win32), ~ (unix, mac) 00551 * 00552 * @return string 00553 */ 00554 public static function backupFilename() 00555 { 00556 return self::instance()->BackupFilename; 00557 } 00558 00559 /** 00560 * Returns the string used as line separator on the current system 00561 * 00562 * @return string 00563 */ 00564 public static function lineSeparator() 00565 { 00566 return self::instance()->LineSeparator; 00567 } 00568 00569 /** 00570 * Returns the string used as environment separator on the current system 00571 * 00572 * @return string 00573 */ 00574 public static function envSeparator() 00575 { 00576 return self::instance()->EnvSeparator; 00577 } 00578 00579 /** 00580 * Returns the path of the current var directory 00581 * 00582 * @return string 00583 */ 00584 public static function varDirectory() 00585 { 00586 $ini = eZINI::instance(); 00587 return eZDir::path( array( $ini->variable( 'FileSettings', 'VarDir' ) ) ); 00588 } 00589 00590 /** 00591 * Returns the current storage directory 00592 * 00593 * @return string 00594 */ 00595 public static function storageDirectory() 00596 { 00597 $ini = eZINI::instance(); 00598 $varDir = self::varDirectory(); 00599 $storageDir = $ini->variable( 'FileSettings', 'StorageDir' ); 00600 return eZDir::path( array( $varDir, $storageDir ) ); 00601 } 00602 00603 /** 00604 * Returns the current cache directory. 00605 * 00606 * @return string 00607 */ 00608 public static function cacheDirectory() 00609 { 00610 $ini = eZINI::instance(); 00611 $cacheDir = $ini->variable( 'FileSettings', 'CacheDir' ); 00612 00613 if ( $cacheDir[0] == "/" ) 00614 { 00615 return eZDir::path( array( $cacheDir ) ); 00616 } 00617 else 00618 { 00619 return eZDir::path( array( self::varDirectory(), $cacheDir ) ); 00620 } 00621 } 00622 00623 /** 00624 * Returns the absolute path to the eZ Publish root directory 00625 * 00626 * @return string|null 00627 */ 00628 public static function rootDir() 00629 { 00630 $instance = self::instance(); 00631 if ( !$instance->RootDir ) 00632 { 00633 $cwd = getcwd(); 00634 $self = $instance->serverVariable( 'PHP_SELF' ); 00635 if ( file_exists( $cwd . $instance->FileSeparator . $self ) or 00636 file_exists( $cwd . $instance->FileSeparator . $instance->IndexFile ) ) 00637 { 00638 $instance->RootDir = $cwd; 00639 } 00640 else 00641 { 00642 $instance->RootDir = null; 00643 } 00644 } 00645 return $instance->RootDir; 00646 } 00647 00648 /** 00649 * Returns the path to where all the code resides. 00650 * 00651 * @return string 00652 */ 00653 public static function siteDir() 00654 { 00655 return self::instance()->SiteDir; 00656 } 00657 00658 /** 00659 * Returns the relative directory path of the vhless setup. 00660 * 00661 * @return string 00662 */ 00663 public static function wwwDir() 00664 { 00665 return self::instance()->WWWDir; 00666 } 00667 00668 /** 00669 * Returns the filepath for the index file. 00670 * 00671 * @param bool $withAccessList 00672 * @return string 00673 */ 00674 public static function indexDir( $withAccessList = true ) 00675 { 00676 return self::wwwDir() . self::indexFile( $withAccessList ); 00677 } 00678 00679 /** 00680 * Returns the query string for the current request. 00681 * 00682 * <code> 00683 * ?param1=value1¶m2=value2 00684 * </code> 00685 * 00686 * @return string 00687 */ 00688 public static function queryString() 00689 { 00690 return self::instance()->QueryString; 00691 } 00692 00693 /** 00694 * Returns the filepath for the index file with the access path appended 00695 * 00696 * @param bool $withAccessPath 00697 * @return string 00698 */ 00699 public static function indexFile( $withAccessPath = true ) 00700 { 00701 $sys = self::instance(); 00702 $text = $sys->IndexFile; 00703 00704 if ( $withAccessPath && ( isset( $sys->AccessPath['siteaccess']['url'][0] ) || isset( $sys->AccessPath['path']['url'][0] ) ) ) 00705 { 00706 $ini = eZINI::instance(); 00707 if ( isset( $sys->AccessPath['siteaccess']['url'][0] ) && 00708 $ini->variable( 'SiteAccessSettings', 'RemoveSiteAccessIfDefaultAccess' ) === 'enabled' ) 00709 { 00710 $defaultAccess = $ini->variable( 'SiteSettings', 'DefaultAccess' ); 00711 // 1st is proper match where code has used updated api as of 4.4, do not use siteaccess 00712 if ( $sys->AccessPath['siteaccess']['name'] === $defaultAccess ) 00713 $accessPath = implode( '/', $sys->AccessPath['path']['url'] ); 00714 // 2nd is for compatability with older code that used eZSys api withouth defining scopes, shift default siteaccess path 00715 elseif ( $sys->AccessPath['siteaccess']['name'] === 'undefined' && $sys->AccessPath['siteaccess']['url'][0] === $defaultAccess ) 00716 { 00717 $accessPathArray = $sys->AccessPath; 00718 array_shift( $accessPathArray['siteaccess']['url'] ); //remove default siteaccess 00719 $accessPath = implode( '/', array_merge( $accessPathArray['siteaccess']['url'], $accessPathArray['path']['url'] ) ); 00720 } 00721 // In case there is no default siteaccess match use full url 00722 else 00723 $accessPath = implode( '/', array_merge( $sys->AccessPath['siteaccess']['url'], $sys->AccessPath['path']['url'] ) ); 00724 } 00725 else 00726 { 00727 $accessPath = implode( '/', array_merge( $sys->AccessPath['siteaccess']['url'], $sys->AccessPath['path']['url'] ) ); 00728 } 00729 00730 $text .= '/' . $accessPath; 00731 00732 // Make sure we never return just a single '/' in case where siteaccess was shifted 00733 if ( $text === '/' ) 00734 $text = ''; 00735 } 00736 return $text; 00737 } 00738 00739 /** 00740 * Returns the filepath for the index file 00741 * 00742 * @return string 00743 */ 00744 public static function indexFileName() 00745 { 00746 return self::instance()->IndexFile; 00747 } 00748 00749 /** 00750 * Returns the current hostname. 00751 * 00752 * First tries to use X-Forward-Host before it goes on to use host in header, if none of them 00753 * exists fallback to use host part of site.ini\[SiteSettings]|SiteURL setting. 00754 * 00755 * @return string 00756 */ 00757 public static function hostname() 00758 { 00759 $hostName = null; 00760 $forwardedHostsString = self::serverVariable( 'HTTP_X_FORWARDED_HOST', true ); 00761 if ( $forwardedHostsString ) 00762 { 00763 $forwardedHosts = explode( ',', $forwardedHostsString ); 00764 $hostName = trim( $forwardedHosts[0] ); 00765 } 00766 00767 if ( !$hostName && self::serverVariable( 'HTTP_HOST', true ) ) 00768 { 00769 $hostName = self::serverVariable( 'HTTP_HOST' ); 00770 } 00771 00772 if ( !$hostName ) 00773 { 00774 $siteUrl = eZINI::instance()->variable( 'SiteSettings', 'SiteURL' ); 00775 $hostName = parse_url( "http://{$siteUrl}", PHP_URL_HOST ); 00776 } 00777 00778 return $hostName; 00779 } 00780 00781 /** 00782 * Returns the client IP whether he's behind a proxy or not 00783 * 00784 * Use [HTTPHeaderSettings].ClientIpByCustomHTTPHeader in site.ini if you want 00785 * to use a custom http header such as X-Forwarded-For 00786 * 00787 * Note: X-Forwarded-For is transformed by PHP 00788 * into $_SERVER['HTTP_X_FORWARDED_FOR] 00789 * 00790 * @return string 00791 */ 00792 public static function clientIP() 00793 { 00794 $customHTTPHeader = eZINI::instance()->variable( 'HTTPHeaderSettings', 'ClientIpByCustomHTTPHeader' ); 00795 if( $customHTTPHeader && $customHTTPHeader != 'false' ) 00796 { 00797 // Transforms for instance, X-Forwarded-For into X_FORWARDED_FOR 00798 $phpHeader = 'HTTP_' . str_replace( '-', '_', strtoupper( $customHTTPHeader ) ); 00799 $forwardedClientsString = eZSys::serverVariable( $phpHeader, true ); 00800 00801 if ( $forwardedClientsString ) 00802 { 00803 // $forwardedClientsString (usually) contains a comma+space separated list of IPs 00804 // where the left-most being the farthest downstream client. All the others are proxy servers. 00805 // As X-Forwarded-For is not a standard header yet, we prefer to use a simple comma as the explode delimiter 00806 $forwardedClients = explode( ',', $forwardedClientsString ); 00807 if( !empty( $forwardedClients ) ) 00808 { 00809 return trim( $forwardedClients[0] ); 00810 } 00811 } 00812 00813 // Fallback on $_SERVER['REMOTE_ADDR'] 00814 eZDebug::writeWarning( "Could not get ip with ClientIpByCustomHTTPHeader={$customHTTPHeader}, fallback to using REMOTE_ADDR", 00815 __METHOD__ ); 00816 } 00817 00818 return self::serverVariable( 'REMOTE_ADDR', true ); 00819 } 00820 00821 /** 00822 * Determines if SSL is enabled and protocol HTTPS is used. 00823 * 00824 * @return bool 00825 */ 00826 public static function isSSLNow() 00827 { 00828 $ini = eZINI::instance(); 00829 $sslPort = $ini->variable( 'SiteSettings', 'SSLPort' ); 00830 if ( !$sslPort ) 00831 $sslPort = eZSSLZone::DEFAULT_SSL_PORT; 00832 // $nowSSl is true if current access mode is HTTPS. 00833 $nowSSL = ( self::serverPort() == $sslPort ); 00834 00835 if ( !$nowSSL ) 00836 { 00837 // Check if this request might be driven through a ssl proxy 00838 if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) 00839 { 00840 $nowSSL = ( $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ); 00841 } 00842 else if ( isset( $_SERVER['HTTP_X_FORWARDED_PORT'] ) ) 00843 { 00844 $sslPort = $ini->variable( 'SiteSettings', 'SSLPort' ); 00845 $nowSSL = ( $_SERVER['HTTP_X_FORWARDED_PORT'] == $sslPort ); 00846 } 00847 else if ( isset( $_SERVER['HTTP_X_FORWARDED_SERVER'] ) ) 00848 { 00849 $sslProxyServerName = $ini->variable( 'SiteSettings', 'SSLProxyServerName' ); 00850 $nowSSL = ( $sslProxyServerName == $_SERVER['HTTP_X_FORWARDED_SERVER'] ); 00851 } 00852 } 00853 return $nowSSL; 00854 } 00855 00856 /** 00857 * Returns the current server protocol depending on if SSL is enabled or not. 00858 * 00859 * @return string 00860 */ 00861 public static function serverProtocol() 00862 { 00863 if ( self::isSSLNow() ) 00864 return 'https'; 00865 else 00866 return 'http'; 00867 } 00868 00869 /** 00870 * Returns the server URL (protocol and hostname and port) 00871 * 00872 * @return string 00873 */ 00874 public static function serverURL() 00875 { 00876 $host = self::hostname(); 00877 $url = ''; 00878 if ( $host ) 00879 { 00880 if ( self::isSSLNow() ) 00881 { 00882 // https case 00883 $host = preg_replace( '/:\d+$/', '', $host ); 00884 00885 $ini = eZINI::instance(); 00886 $sslPort = $ini->variable( 'SiteSettings', 'SSLPort' ); 00887 00888 $sslPortString = ( $sslPort == eZSSLZone::DEFAULT_SSL_PORT ) ? '' : ":$sslPort"; 00889 $url = "https://" . $host . $sslPortString; 00890 } 00891 else 00892 { 00893 $url = "http://" . $host; 00894 } 00895 } 00896 return $url; 00897 } 00898 00899 /** 00900 * Returns the server port or 80 as default if the server port can not 00901 * be retrieved from the hostname or the server variable 'SERVER_PORT' 00902 * 00903 * @return int 00904 */ 00905 public static function serverPort() 00906 { 00907 if ( empty( $GLOBALS['eZSysServerPort'] ) ) 00908 { 00909 $hostname = self::hostname(); 00910 if ( preg_match( "/.*:([0-9]+)/", $hostname, $regs ) ) 00911 { 00912 $port = (int) $regs[1]; 00913 } 00914 else 00915 { 00916 $port = (int) self::serverVariable( 'SERVER_PORT', true ); 00917 } 00918 00919 if ( !$port ) 00920 { 00921 $port = 80; 00922 } 00923 00924 $GLOBALS['eZSysServerPort'] = $port; 00925 } 00926 return $GLOBALS['eZSysServerPort']; 00927 } 00928 00929 /** 00930 * Should return true when magick quotes are enabled, but instead return null. 00931 * 00932 * @deprecated since 4.5 00933 * 00934 * @return null 00935 */ 00936 public static function magickQuotes() 00937 { 00938 return null; 00939 } 00940 00941 /** 00942 * Returns the value of $_SERVER[$variableName] if it is set. 00943 * 00944 * If it isn't set, trigger an error message if $quiet is false 00945 * 00946 * @param string $variableName 00947 * @param bool $quiet 00948 * @return mixed|null 00949 */ 00950 public static function serverVariable( $variableName, $quiet = false ) 00951 { 00952 if ( !isset( $_SERVER[$variableName] ) ) 00953 { 00954 if ( !$quiet ) 00955 { 00956 eZDebug::writeError( "Server variable '$variableName' does not exist", __METHOD__ ); 00957 } 00958 00959 return null; 00960 } 00961 return $_SERVER[$variableName]; 00962 } 00963 00964 /** 00965 * Sets a server variable in the global array $_SERVER 00966 * 00967 * Note: Variables are only set for the current process/page view 00968 * @param string $variableName 00969 * @param mixed $variableValue 00970 * @return void 00971 */ 00972 public static function setServerVariable( $variableName, $variableValue ) 00973 { 00974 $_SERVER[$variableName] = $variableValue; 00975 } 00976 00977 /** 00978 * Returns the server's path string 00979 * 00980 * @param bool $quiet 00981 * @return mixed|null 00982 */ 00983 public static function path( $quiet = false ) 00984 { 00985 return self::serverVariable( 'PATH', $quiet ); 00986 } 00987 00988 /** 00989 * Returns an environment variable or null if it is not available 00990 * 00991 * If the variable is not available, trigger an error message 00992 * 00993 * @param string $variableName 00994 * @param bool $quiet 00995 * @return null|string 00996 */ 00997 public static function environmentVariable( $variableName, $quiet = false ) 00998 { 00999 if ( getenv($variableName) === false ) 01000 { 01001 if ( !$quiet ) 01002 { 01003 eZDebug::writeError( "Environment variable '$variableName' does not exist", __METHOD__ ); 01004 } 01005 return null; 01006 } 01007 return getenv($variableName); 01008 } 01009 01010 /** 01011 * Checks if an environment variable is available 01012 * 01013 * @param string $variableName 01014 * @return bool 01015 */ 01016 public static function hasEnvironmentVariable( $variableName ) 01017 { 01018 return getenv($variableName) !== false; 01019 } 01020 01021 /** 01022 * Sets an environment variable for the current process/page view 01023 * 01024 * @param string $variableName 01025 * @param mixed $variableValue 01026 * @return void 01027 */ 01028 public static function setEnvironmentVariable( $variableName, $variableValue ) 01029 { 01030 putenv( "$variableName=$variableValue" ); 01031 } 01032 01033 /** 01034 * Make sure that certain attribute keys are available in $this->Attributes 01035 * 01036 * @return array 01037 */ 01038 function attributes() 01039 { 01040 return array_merge( array( 'wwwdir', 01041 'sitedir', 01042 'indexfile', 01043 'indexdir', 01044 'querystring' ), 01045 array_keys( $this->Attributes ) ); 01046 01047 } 01048 01049 /** 01050 * Checks if the attribute $attr is set. 01051 * 01052 * @param string $attr 01053 * @return bool 01054 */ 01055 function hasAttribute( $attr ) 01056 { 01057 return in_array( $attr, $this->attributes() ); 01058 } 01059 01060 /** 01061 * Returns the attribute value for $attr or null if the attribute does not exist 01062 * 01063 * @param string $attr 01064 * @return null|string 01065 */ 01066 function attribute( $attr ) 01067 { 01068 if ( isset( $this->Attributes[$attr] ) ) 01069 { 01070 return $this->$attr(); 01071 } 01072 else if ( $attr == 'wwwdir' ) 01073 { 01074 return $this->wwwDir(); 01075 } 01076 else if ( $attr == 'sitedir' ) 01077 { 01078 return $this->siteDir(); 01079 } 01080 else if ( $attr == 'indexfile' ) 01081 { 01082 return $this->indexFile(); 01083 } 01084 else if ( $attr == 'indexdir' ) 01085 { 01086 return $this->indexDir(); 01087 } 01088 else if ( $attr = 'querystring' ) 01089 { 01090 return $this->queryString(); 01091 } 01092 01093 eZDebug::writeError( "Attribute '$attr' does not exist", __METHOD__ ); 01094 return null; 01095 } 01096 01097 /** 01098 * Appends the access path (parts of url that identifies siteaccess), used by {@link eZSys::indexFile()} 01099 * NOTE: Does not make sense to use for siteaccess, as you would want to clear current path and set new one 01100 * normally, so preferably use {@link eZSys::setAccessPath()} in this case. 01101 * 01102 * @param array|string $path 01103 * @param string $name An identifer of the name of the path provided {@link $AccessPath} 01104 * @param bool $siteaccess Hints if path is siteaccess related or not, needed in case subsequesnt code suddenly 01105 * changes siteaccess and needs to clear siteaccess scope 01106 */ 01107 static function addAccessPath( $path, $name = 'undefined', $siteaccess = true ) 01108 { 01109 $instance = self::instance(); 01110 if ( !is_array( $path ) ) 01111 $path = array( $path ); 01112 01113 if ( $siteaccess ) 01114 { 01115 $instance->AccessPath['siteaccess']['name'] = $name; 01116 if ( isset($instance->AccessPath['siteaccess']['url'][0]) ) 01117 $instance->AccessPath['siteaccess']['url'] = array_merge( $instance->AccessPath['siteaccess']['url'], $path ); 01118 else 01119 $instance->AccessPath['siteaccess']['url'] = $path; 01120 } 01121 else 01122 { 01123 $instance->AccessPath['path']['name'] = $name; 01124 if ( isset($instance->AccessPath['path']['url'][0]) ) 01125 $instance->AccessPath['path']['url'] = array_merge( $instance->AccessPath['path']['url'], $path ); 01126 else 01127 $instance->AccessPath['path']['url'] = $path; 01128 } 01129 } 01130 01131 /** 01132 * Set access path (parts of url that identifies siteaccess), used by {@link eZSys::indexFile()} 01133 * 01134 * @param array $path 01135 * @param string $name An identifer of the name of the path provided {@link $AccessPath} 01136 * @param bool $siteaccess Hints if path is siteaccess related or not, needed in case subsequesnt code suddenly 01137 * changes siteaccess and needs to clear siteaccess scope 01138 */ 01139 static function setAccessPath( array $path = array(), $name = 'undefined', $siteaccess = true ) 01140 { 01141 if ( $siteaccess ) 01142 self::instance()->AccessPath['siteaccess'] = array( 'name' => $name, 'url' => $path ); 01143 else 01144 self::instance()->AccessPath['path'] = array( 'name' => $name, 'url' => $path ); 01145 } 01146 01147 /** 01148 * Clears the access path, used by {@link eZSys::indexFile()} 01149 * 01150 * @param bool $siteaccess 01151 * @return void 01152 */ 01153 static function clearAccessPath( $siteaccess = true ) 01154 { 01155 if ( $siteaccess ) 01156 self::instance()->AccessPath['siteaccess'] = array( 'name' => '', 'url' => array() ); 01157 else 01158 self::instance()->AccessPath['path'] = array( 'name' => '', 'url' => array() ); 01159 } 01160 01161 /** 01162 * Magic function to get access readonly properties (protected) 01163 * 01164 * @param string $propertyName 01165 * @return mixed 01166 * @throws ezcBasePropertyNotFoundException 01167 */ 01168 public function __get( $propertyName ) 01169 { 01170 if ( $propertyName === 'AccessPath' ) 01171 return $this->AccessPath; 01172 01173 throw new ezcBasePropertyNotFoundException( $propertyName ); 01174 } 01175 01176 /** 01177 * Magic function to see if readonly properties (protected) exists 01178 * 01179 * @param string $propertyName Option name to check for. 01180 * @return bool Whether the option exists. 01181 * @ignore 01182 */ 01183 public function __isset( $propertyName ) 01184 { 01185 return $propertyName === 'AccessPath'; 01186 } 01187 01188 /** 01189 * Returns true if debugging of internals is enabled, this will display 01190 * which server variables are read. 01191 * Set the option with setIsDebugEnabled(). 01192 * 01193 * @deprecated Since 4.5, not used 01194 * @return bool 01195 */ 01196 public static function isDebugEnabled() 01197 { 01198 } 01199 01200 /** 01201 * Sets whether internal debugging is enabled or not. 01202 * 01203 * @deprecated Since 4.5, has not effect anymore 01204 * @param bool $debug 01205 */ 01206 public static function setIsDebugEnabled( $debug ) 01207 { 01208 } 01209 01210 /** 01211 * Initializes some variables according to some global PHP values. 01212 * This function should be called once in the index file with the parameters 01213 * stated in the parameter list. 01214 * 01215 * @param string $index The current index file, needed for virtual host mode detection. 01216 * @param bool $forceVirtualHost Virtual host mode is normally autodetected, but if not this can be forced 01217 * by setting this to true. 01218 */ 01219 public static function init( $index = 'index.php', $forceVirtualHost = null ) 01220 { 01221 $instance = self::instance(); 01222 $server = $instance->Params['_SERVER']; 01223 $phpSelf = $server['PHP_SELF']; 01224 $requestUri = $server['REQUEST_URI']; 01225 $scriptFileName = $server['SCRIPT_FILENAME']; 01226 $siteDir = rtrim( str_replace( $index, '', $scriptFileName ), '\/' ) . '/'; 01227 $wwwDir = ''; 01228 $IndexFile = ''; 01229 $queryString = ''; 01230 01231 // see if we can use phpSelf to determin wwwdir 01232 $tempwwwDir = self::getValidwwwDir( $phpSelf, $scriptFileName, $index ); 01233 if ( $tempwwwDir !== null && $tempwwwDir !== false ) 01234 { 01235 // Force virual host or Auto detect IIS vh mode & Apache .htaccess mode 01236 if ( $forceVirtualHost 01237 || ( isset( $server['IIS_WasUrlRewritten'] ) && $server['IIS_WasUrlRewritten'] ) 01238 || ( isset( $server['REDIRECT_URL'] ) && isset( $server['REDIRECT_STATUS'] ) && $server['REDIRECT_STATUS'] == '200' ) ) 01239 { 01240 if ( $tempwwwDir ) 01241 { 01242 $wwwDir = '/' . $tempwwwDir; 01243 $wwwDirPos = strpos( $requestUri, $wwwDir ); 01244 if ( $wwwDirPos !== false ) 01245 { 01246 $requestUri = substr( $requestUri, $wwwDirPos + strlen($wwwDir) ); 01247 } 01248 } 01249 } 01250 else // Non virtual host mode, use $tempwwwDir to figgure out paths 01251 { 01252 $indexDir = $index; 01253 if ( $tempwwwDir ) 01254 { 01255 $wwwDir = '/' . $tempwwwDir; 01256 $indexDir = $wwwDir . '/' . $indexDir; 01257 } 01258 $IndexFile = '/' . $index; 01259 01260 // remove sub path from requestUri 01261 $indexDirPos = strpos( $requestUri, $indexDir ); 01262 if ( $indexDirPos !== false ) 01263 { 01264 $requestUri = substr( $requestUri, $indexDirPos + strlen($indexDir) ); 01265 } 01266 elseif ( $wwwDir ) 01267 { 01268 $wwwDirPos = strpos( $requestUri, $wwwDir ); 01269 if ( $wwwDirPos !== false ) 01270 { 01271 $requestUri = substr( $requestUri, $wwwDirPos + strlen($wwwDir) ); 01272 } 01273 } 01274 } 01275 } 01276 01277 // remove url and hash parameters 01278 if ( isset( $requestUri[1] ) && $requestUri !== '/' ) 01279 { 01280 $uriGetPos = strpos( $requestUri, '?' ); 01281 if ( $uriGetPos !== false ) 01282 { 01283 $queryString = substr( $requestUri, $uriGetPos ); 01284 if ( $uriGetPos === 0 ) 01285 $requestUri = ''; 01286 else 01287 $requestUri = substr( $requestUri, 0, $uriGetPos ); 01288 } 01289 01290 $uriHashPos = strpos( $requestUri, '#' ); 01291 if ( $uriHashPos === 0 ) 01292 $requestUri = ''; 01293 elseif ( $uriHashPos !== false ) 01294 $requestUri = substr( $requestUri, 0, $uriHashPos ); 01295 } 01296 01297 // normalize slash use and url decode url if needed 01298 if ( $requestUri === '/' || $requestUri === '' ) 01299 { 01300 $requestUri = ''; 01301 } 01302 else 01303 { 01304 $requestUri = '/' . urldecode( trim( $requestUri, '/ ' ) ); 01305 } 01306 01307 $instance->AccessPath = array( 'siteaccess' => array( 'name' => '', 'url' => array() ), 01308 'path' => array( 'name' => '', 'url' => array() ) ); 01309 01310 $instance->SiteDir = $siteDir; 01311 $instance->WWWDir = $wwwDir; 01312 $instance->IndexFile = $IndexFile; 01313 $instance->RequestURI = $requestUri; 01314 $instance->QueryString = $queryString; 01315 } 01316 01317 /** 01318 * Generate wwwdir from phpSelf if valid accoring to scriptFileName 01319 * and return null if invalid and false if there is no index in phpSelf 01320 * 01321 * @param string $phpSelf 01322 * @param string $scriptFileName 01323 * @param string $index 01324 * @return string|null|false String in form 'path/path2' if valid, null if not 01325 * and false if $index is not part of phpself 01326 */ 01327 protected static function getValidwwwDir( $phpSelf, $scriptFileName, $index ) 01328 { 01329 if ( !isset( $phpSelf[1] ) || strpos( $phpSelf, $index ) === false ) 01330 return false; 01331 01332 // validate $index straight away 01333 if ( strpos( $scriptFileName, $index ) === false ) 01334 return null; 01335 01336 // optimize '/index.php' pattern 01337 if ( $phpSelf === "/{$index}" ) 01338 return ''; 01339 01340 $phpSelfParts = explode( $index, $phpSelf ); 01341 $validateDir = $phpSelfParts[0]; 01342 // remove first path if home dir 01343 if ( $phpSelf[1] === '~' ) 01344 { 01345 $uri = explode( '/', ltrim( $validateDir, '/' ) ); 01346 array_shift( $uri ); 01347 $validateDir = '/' . implode( '/', $uri ); 01348 } 01349 01350 // validate direclty with phpself part 01351 if ( strpos( $scriptFileName, $validateDir ) !== false ) 01352 return trim( $phpSelfParts[0], '/' ); 01353 01354 // validate with windows path 01355 if ( strpos( $scriptFileName, str_replace( '/', '\\', $validateDir ) ) !== false ) 01356 return trim( $phpSelfParts[0], '/' ); 01357 01358 return null; 01359 } 01360 01361 /** 01362 * Returns the URI used for parsing modules, views and parameters 01363 * 01364 * May differ from $_SERVER['REQUEST_URI']. 01365 * 01366 * @return string 01367 */ 01368 public static function requestURI() 01369 { 01370 return self::instance()->RequestURI; 01371 } 01372 01373 /** 01374 * Returns a shared instance of the eZSys class 01375 * 01376 * @return eZSys 01377 */ 01378 public static function instance() 01379 { 01380 if ( !self::$instance instanceof eZSys ) 01381 { 01382 self::$instance = new eZSys(); 01383 } 01384 return self::$instance; 01385 } 01386 01387 /** 01388 * Sets eZSys instance or clears it if left undefined. 01389 * 01390 * @param eZSys $instance 01391 */ 01392 public static function setInstance( eZSys $instance = null ) 01393 { 01394 self::$instance = $instance; 01395 } 01396 01397 /** 01398 * A wrapper for PHP's crc32 function. Returns the crc32 polynomial as unsigned int 01399 * 01400 * @param $string 01401 * @return int|string 01402 */ 01403 public static function ezcrc32( $string ) 01404 { 01405 $ini = eZINI::instance(); 01406 01407 if ( $ini->variable( 'SiteSettings', '64bitCompatibilityMode' ) === 'enabled' ) 01408 $checksum = sprintf( '%u', crc32( $string ) ); 01409 else 01410 $checksum = crc32( $string ); 01411 01412 return $checksum; 01413 } 01414 01415 /** 01416 * Returns the schema of the request. 01417 * 01418 * @return string 01419 */ 01420 public static function protocolSchema() 01421 { 01422 $schema = ''; 01423 if( preg_match( "#^([a-zA-Z]+)/.*$#", self::serverVariable( 'SERVER_PROTOCOL' ), $schemaMatches ) ) 01424 { 01425 $schema = strtolower( $schemaMatches[1] ) . '://'; 01426 } 01427 01428 return $schema; 01429 } 01430 01431 /** 01432 * Wraps around the built-in glob() function to provide same functionality 01433 * for systems (e.g Solaris) that does not support GLOB_BRACE. 01434 * 01435 * @param string $pattern 01436 * @param int $flags 01437 * @return array 01438 */ 01439 public static function globBrace( $pattern, $flags = 0 ) 01440 { 01441 if ( defined( 'GLOB_BRACE' ) ) 01442 { 01443 $flags = $flags | GLOB_BRACE; 01444 return glob( $pattern, $flags ); 01445 } 01446 else 01447 { 01448 $result = array(); 01449 $files = self::simulateGlobBrace( array( $pattern ) ); 01450 foreach( $files as $file ) 01451 { 01452 $globList = glob( $file, $flags ); 01453 if ( is_array( $globList ) ) 01454 { 01455 $result = array_merge( $result, $globList ); 01456 } 01457 } 01458 return $result; 01459 } 01460 } 01461 01462 /** 01463 * Expands a list of filenames like GLOB_BRACE does. 01464 * 01465 * GLOB_BRACE is non POSIX and only available in GNU glibc. This is needed to 01466 * support operating systems like Solars. 01467 * 01468 * @param $filenames 01469 * @return array 01470 */ 01471 protected static function simulateGlobBrace( $filenames ) 01472 { 01473 $result = array(); 01474 01475 foreach ( $filenames as $filename ) 01476 { 01477 if ( strpos( $filename, '{' ) === false ) 01478 { 01479 $result[] = $filename; 01480 continue; 01481 } 01482 01483 if ( preg_match( '/^(.*)\{(.*?)(?<!\\\\)\}(.*)$/', $filename, $match ) ) 01484 { 01485 $variants = preg_split( '/(?<!\\\\),/', $match[2] ); 01486 01487 $newFilenames = array(); 01488 foreach ( $variants as $variant ) 01489 { 01490 $newFilenames[] = $match[1] . $variant . $match[3]; 01491 } 01492 01493 $newFilenames = self::simulateGlobBrace( $newFilenames ); 01494 $result = array_merge( $result, $newFilenames ); 01495 } 01496 else 01497 { 01498 $result[] = $filename; 01499 } 01500 } 01501 01502 return $result; 01503 } 01504 } 01505 01506 ?>