merged master (2012-09-11)
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index 8667b67..e6fda96 100644 (file)
@@ -730,8 +730,57 @@ function wfUrlProtocolsWithoutProtRel() {
  * @return Array: bits of the URL in an associative array, per PHP docs
  */
 function wfParseUrl( $url ) {
-       $obj = new Uri( $url );
-       return $obj->getComponents();
+       global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
+
+       // Protocol-relative URLs are handled really badly by parse_url(). It's so bad that the easiest
+       // way to handle them is to just prepend 'http:' and strip the protocol out later
+       $wasRelative = substr( $url, 0, 2 ) == '//';
+       if ( $wasRelative ) {
+               $url = "http:$url";
+       }
+       wfSuppressWarnings();
+       $bits = parse_url( $url );
+       wfRestoreWarnings();
+       // parse_url() returns an array without scheme for some invalid URLs, e.g.
+       // parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
+       if ( !$bits || !isset( $bits['scheme'] ) ) {
+               return false;
+       }
+
+       // parse_url() incorrectly handles schemes case-sensitively. Convert it to lowercase.
+       $bits['scheme'] = strtolower( $bits['scheme'] );
+
+       // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it
+       if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) {
+               $bits['delimiter'] = '://';
+       } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) {
+               $bits['delimiter'] = ':';
+               // parse_url detects for news: and mailto: the host part of an url as path
+               // We have to correct this wrong detection
+               if ( isset( $bits['path'] ) ) {
+                       $bits['host'] = $bits['path'];
+                       $bits['path'] = '';
+               }
+       } else {
+               return false;
+       }
+
+       /* Provide an empty host for eg. file:/// urls (see bug 28627) */
+       if ( !isset( $bits['host'] ) ) {
+               $bits['host'] = '';
+
+               /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
+               if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
+                       $bits['path'] = '/' . $bits['path'];
+               }
+       }
+
+       // If the URL was protocol-relative, fix scheme and delimiter
+       if ( $wasRelative ) {
+               $bits['scheme'] = '';
+               $bits['delimiter'] = '//';
+       }
+       return $bits;
 }
 
 /**
@@ -1455,8 +1504,6 @@ function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true
 /**
  * Replace message parameter keys on the given formatted output.
  *
- * @deprecated since 1.18
- *
  * @param $message String
  * @param $args Array
  * @return string
@@ -1795,16 +1842,15 @@ function wfBacktrace() {
  * wfGetCaller( 3 ) is the parent of that.
  *
  * @param $level Int
- * @return Bool|string
+ * @return string
  */
 function wfGetCaller( $level = 2 ) {
        $backtrace = wfDebugBacktrace( $level + 1 );
        if ( isset( $backtrace[$level] ) ) {
                return wfFormatStackFrame( $backtrace[$level] );
        } else {
-               $caller = 'unknown';
+               return 'unknown';
        }
-       return $caller;
 }
 
 /**
@@ -1828,7 +1874,7 @@ function wfGetAllCallers( $limit = 3 ) {
  * Return a string representation of frame
  *
  * @param $frame Array
- * @return Bool
+ * @return string
  */
 function wfFormatStackFrame( $frame ) {
        return isset( $frame['class'] ) ?
@@ -2318,6 +2364,7 @@ define( 'TS_ISO_8601_BASIC', 9 );
 /**
  * Get a timestamp string in one of various formats
  *
+ * @deprecated
  * @param $outputtype Mixed: A timestamp in one of the supported formats, the
  *                    function will autodetect which format is supplied and act
  *                    accordingly.
@@ -2325,118 +2372,8 @@ define( 'TS_ISO_8601_BASIC', 9 );
  * @return Mixed: String / false The same date in the format specified in $outputtype or false
  */
 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
-       $uts = 0;
-       $da = array();
-       $strtime = '';
-
-       if ( !$ts ) { // We want to catch 0, '', null... but not date strings starting with a letter.
-               $uts = time();
-               $strtime = "@$uts";
-       } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
-               # TS_DB
-       } elseif ( preg_match( '/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) {
-               # TS_EXIF
-       } elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) {
-               # TS_MW
-       } elseif ( preg_match( '/^-?\d{1,13}$/D', $ts ) ) {
-               # TS_UNIX
-               $uts = $ts;
-               $strtime = "@$ts"; // http://php.net/manual/en/datetime.formats.compound.php
-       } elseif ( preg_match( '/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts ) ) {
-               # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
-               $strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
-                               str_replace( '+00:00', 'UTC', $ts ) );
-       } elseif ( preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
-               # TS_ISO_8601
-       } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
-               #TS_ISO_8601_BASIC
-       } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/', $ts, $da ) ) {
-               # TS_POSTGRES
-       } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/', $ts, $da ) ) {
-               # TS_POSTGRES
-       } elseif (preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.\d\d\d$/', $ts, $da ) ) {
-               # TS_DB2
-       } elseif ( preg_match( '/^[ \t\r\n]*([A-Z][a-z]{2},[ \t\r\n]*)?' . # Day of week
-                                                       '\d\d?[ \t\r\n]*[A-Z][a-z]{2}[ \t\r\n]*\d{2}(?:\d{2})?' .  # dd Mon yyyy
-                                                       '[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d/S', $ts ) ) { # hh:mm:ss
-               # TS_RFC2822, accepting a trailing comment. See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html / r77171
-               # The regex is a superset of rfc2822 for readability
-               $strtime = strtok( $ts, ';' );
-       } elseif ( preg_match( '/^[A-Z][a-z]{5,8}, \d\d-[A-Z][a-z]{2}-\d{2} \d\d:\d\d:\d\d/', $ts ) ) {
-               # TS_RFC850
-               $strtime = $ts;
-       } elseif ( preg_match( '/^[A-Z][a-z]{2} [A-Z][a-z]{2} +\d{1,2} \d\d:\d\d:\d\d \d{4}/', $ts ) ) {
-               # asctime
-               $strtime = $ts;
-       } else {
-               # Bogus value...
-               wfDebug("wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n");
-
-               return false;
-       }
-
-       static $formats = array(
-               TS_UNIX => 'U',
-               TS_MW => 'YmdHis',
-               TS_DB => 'Y-m-d H:i:s',
-               TS_ISO_8601 => 'Y-m-d\TH:i:s\Z',
-               TS_ISO_8601_BASIC => 'Ymd\THis\Z',
-               TS_EXIF => 'Y:m:d H:i:s', // This shouldn't ever be used, but is included for completeness
-               TS_RFC2822 => 'D, d M Y H:i:s',
-               TS_ORACLE => 'd-m-Y H:i:s.000000', // Was 'd-M-y h.i.s A' . ' +00:00' before r51500
-               TS_POSTGRES => 'Y-m-d H:i:s',
-               TS_DB2 => 'Y-m-d H:i:s',
-       );
-
-       if ( !isset( $formats[$outputtype] ) ) {
-               throw new MWException( 'wfTimestamp() called with illegal output type.' );
-       }
-
-       if ( function_exists( "date_create" ) ) {
-               if ( count( $da ) ) {
-                       $ds = sprintf("%04d-%02d-%02dT%02d:%02d:%02d.00+00:00",
-                               (int)$da[1], (int)$da[2], (int)$da[3],
-                               (int)$da[4], (int)$da[5], (int)$da[6]);
-
-                       $d = date_create( $ds, new DateTimeZone( 'GMT' ) );
-               } elseif ( $strtime ) {
-                       $d = date_create( $strtime, new DateTimeZone( 'GMT' ) );
-               } else {
-                       return false;
-               }
-
-               if ( !$d ) {
-                       wfDebug("wfTimestamp() fed bogus time value: $outputtype; $ts\n");
-                       return false;
-               }
-
-               $output = $d->format( $formats[$outputtype] );
-       } else {
-               if ( count( $da ) ) {
-                       // Warning! gmmktime() acts oddly if the month or day is set to 0
-                       // We may want to handle that explicitly at some point
-                       $uts = gmmktime( (int)$da[4], (int)$da[5], (int)$da[6],
-                               (int)$da[2], (int)$da[3], (int)$da[1] );
-               } elseif ( $strtime ) {
-                       $uts = strtotime( $strtime );
-               }
-
-               if ( $uts === false ) {
-                       wfDebug("wfTimestamp() can't parse the timestamp (non 32-bit time? Update php): $outputtype; $ts\n");
-                       return false;
-               }
-
-               if ( TS_UNIX == $outputtype ) {
-                       return $uts;
-               }
-               $output = gmdate( $formats[$outputtype], $uts );
-       }
-
-       if ( ( $outputtype == TS_RFC2822 ) || ( $outputtype == TS_POSTGRES ) ) {
-               $output .= ' GMT';
-       }
-
-       return $output;
+       $timestamp = new MWTimestamp( $ts );
+       return $timestamp->getTimestamp( $outputtype );
 }
 
 /**