Merge "Use $wgUser in ResourceLoaderUserGroupsModule when possible."
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index ce9c287..8764783 100644 (file)
@@ -221,7 +221,7 @@ function wfMergeErrorArrays( /*...*/ ) {
  * @param $after Mixed: The key to insert after
  * @return Array
  */
-function wfArrayInsertAfter( $array, $insert, $after ) {
+function wfArrayInsertAfter( array $array, array $insert, $after ) {
        // Find the offset of the element to insert after.
        $keys = array_keys( $array );
        $offsetByKey = array_flip( $keys );
@@ -294,6 +294,24 @@ function wfRandom() {
        return $rand;
 }
 
+/**
+ * Get a random string containing a number of pesudo-random hex
+ * characters.
+ * @note This is not secure, if you are trying to generate some sort
+ *       of token please use MWCryptRand instead.
+ *
+ * @param $length int The length of the string to generate
+ * @return String
+ * @since 1.20
+ */
+function wfRandomString( $length = 32 ) {
+       $str = '';
+       while ( strlen( $str ) < $length ) {
+               $str .= dechex( mt_rand() );
+       }
+       return substr( $str, 0, $length );
+}
+
 /**
  * We want some things to be included as literal characters in our title URLs
  * for prettiness, which urlencode encodes by default.  According to RFC 1738,
@@ -784,6 +802,31 @@ function wfParseUrl( $url ) {
        return $bits;
 }
 
+/**
+ * Take a URL, make sure it's expanded to fully qualified, and replace any
+ * encoded non-ASCII Unicode characters with their UTF-8 original forms
+ * for more compact display and legibility for local audiences.
+ *
+ * @todo handle punycode domains too
+ *
+ * @param $url string
+ * @return string
+ */
+function wfExpandIRI( $url ) {
+       return preg_replace_callback( '/((?:%[89A-F][0-9A-F])+)/i', 'wfExpandIRI_callback', wfExpandUrl( $url ) );
+}
+
+/**
+ * Private callback for wfExpandIRI
+ * @param array $matches
+ * @return string
+ */
+function wfExpandIRI_callback( $matches ) {
+       return urldecode( $matches[1] );
+}
+
+
+
 /**
  * Make URL indexes, appropriate for the el_index field of externallinks.
  *
@@ -876,12 +919,16 @@ function wfDebug( $text, $logonly = false ) {
        global $wgDebugLogPrefix, $wgShowDebug;
 
        static $cache = array(); // Cache of unoutputted messages
-       $text = wfDebugTimer() . $text;
 
        if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
                return;
        }
 
+       $timer = wfDebugTimer();
+       if ( $timer !== '' ) {
+               $text = preg_replace( '/[^\n]/', $timer . '\0', $text, 1 );
+       }
+
        if ( ( $wgDebugComments || $wgShowDebug ) && !$logonly ) {
                $cache[] = $text;
 
@@ -1006,8 +1053,8 @@ function wfLogDBError( $text ) {
  * @param $component String|bool: Added in 1.19.
  * @param $callerOffset integer: How far up the callstack is the original
  *    caller. 2 = function that called the function that called
- *    wfDeprecated (Added in 1.20) 
- * 
+ *    wfDeprecated (Added in 1.20)
+ *
  * @return null
  */
 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
@@ -1017,23 +1064,23 @@ function wfDeprecated( $function, $version = false, $component = false, $callerO
 
        if ( !isset( $functionsWarned[$function] ) ) {
                $functionsWarned[$function] = true;
-               
+
                if ( $version ) {
                        global $wgDeprecationReleaseLimit;
-                       
+
                        if ( $wgDeprecationReleaseLimit && $component === false ) {
                                # Strip -* off the end of $version so that branches can use the
                                # format #.##-branchname to avoid issues if the branch is merged into
                                # a version of MediaWiki later than what it was branched from
                                $comparableVersion = preg_replace( '/-.*$/', '', $version );
-                               
+
                                # If the comparableVersion is larger than our release limit then
                                # skip the warning message for the deprecation
                                if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
                                        return;
                                }
                        }
-                       
+
                        $component = $component === false ? 'MediaWiki' : $component;
                        wfWarn( "Use of $function was deprecated in $component $version.", $callerOffset );
                } else {
@@ -1903,7 +1950,7 @@ function wfShowingResults( $offset, $limit ) {
  */
 function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) {
        wfDeprecated( __METHOD__, '1.19' );
-       
+
        global $wgLang;
 
        $query = wfCgiToArray( $query );
@@ -2905,21 +2952,29 @@ function wfInitShellLocale() {
 }
 
 /**
- * Generate a shell-escaped command line string to run a maintenance script.
+ * Alias to wfShellWikiCmd()
+ * @see wfShellWikiCmd()
+ */
+function wfShellMaintenanceCmd( $script, array $parameters = array(), array $options = array() ) {
+       return wfShellWikiCmd( $script, $parameters, $options );
+}
+
+/**
+ * Generate a shell-escaped command line string to run a MediaWiki cli script.
  * Note that $parameters should be a flat array and an option with an argument
  * should consist of two consecutive items in the array (do not use "--option value").
- * @param $script string MediaWiki maintenance script path
+ * @param $script string MediaWiki cli script path
  * @param $parameters Array Arguments and options to the script
  * @param $options Array Associative array of options:
  *             'php': The path to the php executable
  *             'wrapper': Path to a PHP wrapper to handle the maintenance script
  * @return Array
  */
-function wfShellMaintenanceCmd( $script, array $parameters = array(), array $options = array() ) {
+function wfShellWikiCmd( $script, array $parameters = array(), array $options = array() ) {
        global $wgPhpCli;
        // Give site config file a chance to run the script in a wrapper.
        // The caller may likely want to call wfBasename() on $script.
-       wfRunHooks( 'wfShellMaintenanceCmd', array( &$script, &$parameters, &$options ) );
+       wfRunHooks( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) );
        $cmd = isset( $options['php'] ) ? array( $options['php'] ) : array( $wgPhpCli );
        if ( isset( $options['wrapper'] ) ) {
                $cmd[] = $options['wrapper'];
@@ -3318,6 +3373,33 @@ function wfHttpOnlySafe() {
        return true;
 }
 
+/**
+ * Override session_id before session startup if php's built-in
+ * session generation code is not secure.
+ */
+function wfFixSessionID() {
+       // If the cookie or session id is already set we already have a session and should abort
+       if ( isset( $_COOKIE[ session_name() ] ) || session_id() ) {
+               return;
+       }
+
+       // PHP's built-in session entropy is enabled if:
+       // - entropy_file is set or you're on Windows with php 5.3.3+
+       // - AND entropy_length is > 0
+       // We treat it as disabled if it doesn't have an entropy length of at least 32
+       $entropyEnabled = (
+                       ( wfIsWindows() && version_compare( PHP_VERSION, '5.3.3', '>=' ) )
+                       || ini_get( 'session.entropy_file' )
+               )
+               && intval( ini_get( 'session.entropy_length' ) ) >= 32;
+
+       // If built-in entropy is not enabled or not sufficient override php's built in session id generation code
+       if ( !$entropyEnabled ) {
+               wfDebug( __METHOD__ . ": PHP's built in entropy is disabled or not sufficient, overriding session id generation using our cryptrand source.\n" );
+               session_id( MWCryptRand::generateHex( 32 ) );
+       }
+}
+
 /**
  * Initialise php session
  *
@@ -3357,6 +3439,8 @@ function wfSetupSession( $sessionId = false ) {
        session_cache_limiter( 'private, must-revalidate' );
        if ( $sessionId ) {
                session_id( $sessionId );
+       } else {
+               wfFixSessionID();
        }
        wfSuppressWarnings();
        session_start();
@@ -3519,7 +3603,7 @@ function wfFindFile( $title, $options = array() ) {
  * Returns a valid placeholder object if the file does not exist.
  *
  * @param $title Title|String
- * @return File|null A File, or null if passed an invalid Title
+ * @return LocalFile|null A File, or null if passed an invalid Title
  */
 function wfLocalFile( $title ) {
        return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
@@ -3677,8 +3761,11 @@ function wfCountDown( $n ) {
  *              characters before hashing.
  * @return string
  * @codeCoverageIgnore
+ * @deprecated since 1.20; Please use MWCryptRand for security purposes and wfRandomString for pesudo-random strings
+ * @warning This method is NOT secure. Additionally it has many callers that use it for pesudo-random purposes.
  */
 function wfGenerateToken( $salt = '' ) {
+       wfDeprecated( __METHOD__, '1.20' );
        $salt = serialize( $salt );
        return md5( mt_rand( 0, 0x7fffffff ) . $salt );
 }
@@ -3833,6 +3920,16 @@ function wfGetParserCacheStorage() {
        return ObjectCache::getInstance( $wgParserCacheType );
 }
 
+/**
+ * Get the cache object used by the language converter
+ *
+ * @return BagOStuff
+ */
+function wfGetLangConverterCacheStorage() {
+       global $wgLanguageConverterCacheType;
+       return ObjectCache::getInstance( $wgLanguageConverterCacheType );
+}
+
 /**
  * Call hook functions defined in $wgHooks
  *
@@ -3879,3 +3976,84 @@ function wfUnpack( $format, $data, $length=false ) {
        }
        return $result;
 }
+
+/**
+ * Determine if an image exists on the 'bad image list'.
+ *
+ * The format of MediaWiki:Bad_image_list is as follows:
+ *    * Only list items (lines starting with "*") are considered
+ *    * The first link on a line must be a link to a bad image
+ *    * Any subsequent links on the same line are considered to be exceptions,
+ *      i.e. articles where the image may occur inline.
+ *
+ * @param $name string the image name to check
+ * @param $contextTitle Title|bool the page on which the image occurs, if known
+ * @param $blacklist string wikitext of a file blacklist
+ * @return bool
+ */
+function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
+       static $badImageCache = null; // based on bad_image_list msg
+       wfProfileIn( __METHOD__ );
+
+       # Handle redirects
+       $redirectTitle = RepoGroup::singleton()->checkRedirect( Title::makeTitle( NS_FILE, $name ) );
+       if( $redirectTitle ) {
+               $name = $redirectTitle->getDbKey();
+       }
+
+       # Run the extension hook
+       $bad = false;
+       if( !wfRunHooks( 'BadImage', array( $name, &$bad ) ) ) {
+               wfProfileOut( __METHOD__ );
+               return $bad;
+       }
+
+       $cacheable = ( $blacklist === null );
+       if( $cacheable && $badImageCache !== null ) {
+               $badImages = $badImageCache;
+       } else { // cache miss
+               if ( $blacklist === null ) {
+                       $blacklist = wfMsgForContentNoTrans( 'bad_image_list' ); // site list
+               }
+               # Build the list now
+               $badImages = array();
+               $lines = explode( "\n", $blacklist );
+               foreach( $lines as $line ) {
+                       # List items only
+                       if ( substr( $line, 0, 1 ) !== '*' ) {
+                               continue;
+                       }
+
+                       # Find all links
+                       $m = array();
+                       if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
+                               continue;
+                       }
+
+                       $exceptions = array();
+                       $imageDBkey = false;
+                       foreach ( $m[1] as $i => $titleText ) {
+                               $title = Title::newFromText( $titleText );
+                               if ( !is_null( $title ) ) {
+                                       if ( $i == 0 ) {
+                                               $imageDBkey = $title->getDBkey();
+                                       } else {
+                                               $exceptions[$title->getPrefixedDBkey()] = true;
+                                       }
+                               }
+                       }
+
+                       if ( $imageDBkey !== false ) {
+                               $badImages[$imageDBkey] = $exceptions;
+                       }
+               }
+               if ( $cacheable ) {
+                       $badImageCache = $badImages;
+               }
+       }
+
+       $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
+       $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
+       wfProfileOut( __METHOD__ );
+       return $bad;
+}