Followup r95753 per CR: prevent extensions from making isMovable() return true for...
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index 98a1ea7..017b842 100644 (file)
@@ -298,7 +298,7 @@ function wfUrlencode( $s ) {
                $needle = null;
                return;
        }
-       
+
        if ( is_null( $needle ) ) {
                $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' );
                if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) || ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false ) ) {
@@ -431,12 +431,13 @@ function wfAppendQuery( $url, $query ) {
 /**
  * Expand a potentially local URL to a fully-qualified URL.  Assumes $wgServer
  * is correct.
- * 
+ *
  * The meaning of the PROTO_* constants is as follows:
  * PROTO_HTTP: Output a URL starting with http://
  * PROTO_HTTPS: Output a URL starting with https://
  * PROTO_RELATIVE: Output a URL starting with // (protocol-relative URL)
  * PROTO_CURRENT: Output a URL starting with either http:// or https:// , depending on which protocol was used for the current incoming request
+ * PROTO_CANONICAL: For URLs without a domain, like /w/index.php , use $wgCanonicalServer. For protocol-relative URLs, use the protocol of $wgCanonicalServer
  *
  * @todo this won't work with current-path-relative URLs
  * like "subdir/foo.html", etc.
@@ -446,21 +447,34 @@ function wfAppendQuery( $url, $query ) {
  * @return string Fully-qualified URL
  */
 function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
-       global $wgServer;
+       global $wgServer, $wgCanonicalServer;
+       $serverUrl = $defaultProto === PROTO_CANONICAL ? $wgCanonicalServer : $wgServer;
+
        if ( $defaultProto === PROTO_CURRENT ) {
                $defaultProto = WebRequest::detectProtocol() . '://';
        }
-       
-       // Analyze $wgServer to obtain its protocol
-       $bits = wfParseUrl( $wgServer );
+
+       // Analyze $serverUrl to obtain its protocol
+       $bits = wfParseUrl( $serverUrl );
        $serverHasProto = $bits && $bits['scheme'] != '';
+
+       if ( $defaultProto === PROTO_CANONICAL ) {
+               if ( $serverHasProto ) {
+                       $defaultProto = $bits['scheme'] . '://';
+               } else {
+                       // $wgCanonicalServer doesn't have a protocol. This really isn't supposed to happen
+                       // Fall back to HTTP in this ridiculous case
+                       $defaultProto = PROTO_HTTP;
+               }
+       }
+
        $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 );
-       
+
        if( substr( $url, 0, 2 ) == '//' ) {
                return $defaultProtoWithoutSlashes . $url;
        } elseif( substr( $url, 0, 1 ) == '/' ) {
-               // If $wgServer is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone
-               return ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $wgServer . $url;
+               // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone
+               return ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $serverUrl . $url;
        } else {
                return $url;
        }
@@ -469,14 +483,18 @@ function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
 /**
  * Returns a regular expression of url protocols
  *
+ * @param $includeProtocolRelative bool If false, remove '//' from the returned protocol list.
+ *        DO NOT USE this directy, use wfUrlProtocolsWithoutProtRel() instead
  * @return String
  */
-function wfUrlProtocols() {
+function wfUrlProtocols( $includeProtocolRelative = true ) {
        global $wgUrlProtocols;
 
-       static $retval = null;
-       if ( !is_null( $retval ) ) {
-               return $retval;
+       // Cache return values separately based on $includeProtocolRelative
+       static $withProtRel = null, $withoutProtRel = null;
+       $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel;
+       if ( !is_null( $cachedValue ) ) {
+               return $cachedValue;
        }
 
        // Support old-style $wgUrlProtocols strings, for backwards compatibility
@@ -484,16 +502,39 @@ function wfUrlProtocols() {
        if ( is_array( $wgUrlProtocols ) ) {
                $protocols = array();
                foreach ( $wgUrlProtocols as $protocol ) {
-                       $protocols[] = preg_quote( $protocol, '/' );
+                       // Filter out '//' if !$includeProtocolRelative
+                       if ( $includeProtocolRelative || $protocol !== '//' ) {
+                               $protocols[] = preg_quote( $protocol, '/' );
+                       }
                }
 
                $retval = implode( '|', $protocols );
        } else {
+               // Ignore $includeProtocolRelative in this case
+               // This case exists for pre-1.6 compatibility, and we can safely assume
+               // that '//' won't appear in a pre-1.6 config because protocol-relative
+               // URLs weren't supported until 1.18
                $retval = $wgUrlProtocols;
        }
+
+       // Cache return value
+       if ( $includeProtocolRelative ) {
+               $withProtRel = $retval;
+       } else {
+               $withoutProtRel = $retval;
+       }
        return $retval;
 }
 
+/**
+ * Like wfUrlProtocols(), but excludes '//' from the protocol list. Use this if
+ * you need a regex that matches all URL protocols but does not match protocol-
+ * relative URLs
+ */
+function wfUrlProtocolsWithoutProtRel() {
+       return wfUrlProtocols( false );
+}
+
 /**
  * parse_url() work-alike, but non-broken.  Differences:
  *
@@ -516,7 +557,9 @@ function wfParseUrl( $url ) {
        wfSuppressWarnings();
        $bits = parse_url( $url );
        wfRestoreWarnings();
-       if ( !$bits ) {
+       // 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;
        }
 
@@ -602,6 +645,26 @@ function wfMakeUrlIndex( $url ) {
        return $index;
 }
 
+/**
+ * Check whether a given URL has a domain that occurs in a given set of domains
+ * @param $url string URL
+ * @param $domains array Array of domains (strings)
+ * @return bool True if the host part of $url ends in one of the strings in $domains
+ */
+function wfMatchesDomainList( $url, $domains ) {
+       $bits = wfParseUrl( $url );
+       if ( is_array( $bits ) && isset( $bits['host'] ) ) {
+               foreach ( (array)$domains as $domain ) {
+                       // FIXME: This gives false positives. http://nds-nl.wikipedia.org will match nl.wikipedia.org
+                       // We should use something that interprets dots instead
+                       if ( substr( $bits['host'], -strlen( $domain ) ) === $domain ) {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
 /**
  * Sends a line to the debug log if enabled or, optionally, to a comment in output.
  * In normal operation this is a NOP.
@@ -1176,7 +1239,8 @@ function wfMsgWikiHtml( $key ) {
        $args = func_get_args();
        array_shift( $args );
        return wfMsgReplaceArgs(
-               MessageCache::singleton()->parse( wfMsgGetKey( $key ), null, /* can't be set to false */ true )->getText(),
+               MessageCache::singleton()->parse( wfMsgGetKey( $key ), null,
+               /* can't be set to false */ true, /* interface */ true )->getText(),
                $args );
 }
 
@@ -1343,6 +1407,8 @@ function wfReportTime() {
  * debug_backtrace is disabled, otherwise the output from
  * debug_backtrace() (trimmed).
  *
+ * @param $limit int This parameter can be used to limit the number of stack frames returned
+ *
  * @return array of backtrace information
  */
 function wfDebugBacktrace( $limit = 0 ) {
@@ -1368,7 +1434,7 @@ function wfDebugBacktrace( $limit = 0 ) {
        }
 
        if ( $limit && version_compare( PHP_VERSION, '5.4.0', '>=' ) ) {
-               return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ), 1 );
+               return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit ), 1 );
        } else {
                return array_slice( debug_backtrace(), 1 );
        }
@@ -3193,6 +3259,14 @@ function wfLocalFile( $title ) {
        return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
 }
 
+/**
+ * Stream a file to the browser. Back-compat alias for StreamFile::stream()
+ * @deprecated since 1.19
+ */
+function wfStreamFile( $fname, $headers = array() ) {
+       StreamFile::stream( $fname, $headers );
+}
+
 /**
  * Should low-performance queries be disabled?
  *