(bug 13140) Show parent categories in category namespace
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index 008a6d2..286a9b8 100644 (file)
@@ -87,6 +87,29 @@ if ( !function_exists( 'array_diff_key' ) ) {
        }
 }
 
+/**
+ * Like array_diff( $a, $b ) except that it works with two-dimensional arrays.
+ */
+function wfArrayDiff2( $a, $b ) {
+       return array_udiff( $a, $b, 'wfArrayDiff2_cmp' );
+}
+function wfArrayDiff2_cmp( $a, $b ) {
+       if ( !is_array( $a ) ) {
+               return strcmp( $a, $b );
+       } elseif ( count( $a ) !== count( $b ) ) {
+               return count( $a ) < count( $b ) ? -1 : 1;
+       } else {
+               reset( $a );
+               reset( $b );
+               while( ( list( $keyA, $valueA ) = each( $a ) ) && ( list( $keyB, $valueB ) = each( $b ) ) ) {
+                       $cmp = strcmp( $valueA, $valueB );
+                       if ( $cmp !== 0 ) {
+                               return $cmp;
+                       }
+               }
+               return 0;
+       }
+}
 
 /**
  * Wrapper for clone(), for compatibility with PHP4-friendly extensions.
@@ -282,6 +305,11 @@ function wfReadOnly() {
        return (bool)$wgReadOnly;
 }
 
+function wfReadOnlyReason() {
+       global $wgReadOnly;
+       wfReadOnly();
+       return $wgReadOnly;
+}
 
 /**
  * Get a message from anywhere, for the current user language.
@@ -289,11 +317,6 @@ function wfReadOnly() {
  * Use wfMsgForContent() instead if the message should NOT
  * change depending on the user preferences.
  *
- * Note that the message may contain HTML, and is therefore
- * not safe for insertion anywhere. Some functions such as
- * addWikiText will do the escaping for you. Use wfMsgHtml()
- * if you need an escaped message.
- *
  * @param $key String: lookup key for the message, usually
  *    defined in languages/Language.php
  * 
@@ -427,24 +450,12 @@ function wfMsgWeirdKey ( $key ) {
 function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) {
        global $wgParser, $wgContLang, $wgMessageCache, $wgLang;
 
-       /* <Vyznev> btw, is all that code in wfMsgGetKey() that check
-        * if the message cache exists of not really necessary, or is
-        * it just paranoia?
-        * <TimStarling> Vyznev: it's probably not necessary
-        * <TimStarling> I think I wrote it in an attempt to report DB
-        * connection errors properly
-        * <TimStarling> but eventually we gave up on using the
-        * message cache for that and just hard-coded the strings
-        * <TimStarling> it may have other uses, it's not mere paranoia
-        */
-
-       if ( is_object( $wgMessageCache ) )
-               $transstat = $wgMessageCache->getTransform();
-
+       # If $wgMessageCache isn't initialised yet, try to return something sensible.
        if( is_object( $wgMessageCache ) ) {
-               if ( ! $transform )
-                       $wgMessageCache->disableTransform();
                $message = $wgMessageCache->get( $key, $useDB, $forContent );
+               if ( $transform ) {
+                       $message = $wgMessageCache->transform( $message );
+               }
        } else {
                if( $forContent ) {
                        $lang = &$wgContLang;
@@ -456,22 +467,13 @@ function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) {
                # ISSUE: Should we try to handle "message/lang" here too?
                $key = str_replace( ' ' , '_' , $wgContLang->lcfirst( $key ) );
 
-               wfSuppressWarnings();
                if( is_object( $lang ) ) {
                        $message = $lang->getMessage( $key );
                } else {
                        $message = false;
                }
-               wfRestoreWarnings();
-
-               if ( $transform && strstr( $message, '{{' ) !== false ) {
-                       $message = $wgParser->transformMsg($message, $wgMessageCache->getParserOptions() );
-               }
        }
 
-       if ( is_object( $wgMessageCache ) && ! $transform )
-               $wgMessageCache->setTransform( $transstat );
-
        return $message;
 }
 
@@ -491,15 +493,13 @@ function wfMsgReplaceArgs( $message, $args ) {
        // Replace arguments
        if ( count( $args ) ) {
                if ( is_array( $args[0] ) ) {
-                       foreach ( $args[0] as $key => $val ) {
-                               $message = str_replace( '$' . $key, $val, $message );
-                       }
-               } else {
-                       foreach( $args as $n => $param ) {
-                               $replacementKeys['$' . ($n + 1)] = $param;
-                       }
-                       $message = strtr( $message, $replacementKeys );
+                       $args = array_values( $args[0] );
                }
+               $replacementKeys = array();
+               foreach( $args as $n => $param ) {
+                       $replacementKeys['$' . ($n + 1)] = $param;
+               }
+               $message = strtr( $message, $replacementKeys );
        }
 
        return $message;
@@ -546,10 +546,12 @@ function wfMsgWikiHtml( $key ) {
  * @param array $options Processing rules:
  *  <i>parse</i>: parses wikitext to html
  *  <i>parseinline</i>: parses wikitext to html and removes the surrounding p's added by parser or tidy
- *  <i>escape</i>: filters message trough htmlspecialchars
+ *  <i>escape</i>: filters message through htmlspecialchars
+ *  <i>escapenoentities</i>: same, but allows entity references like &nbsp; through
  *  <i>replaceafter</i>: parameters are substituted after parsing or escaping
  *  <i>parsemag</i>: transform the message using magic phrases
  *  <i>content</i>: fetch message for content language instead of interface
+ * Behavior for conflicting options (e.g., parse+parseinline) is undefined.
  */
 function wfMsgExt( $key, $options ) {
        global $wgOut, $wgParser;
@@ -590,6 +592,10 @@ function wfMsgExt( $key, $options ) {
 
        if ( in_array('escape', $options) ) {
                $string = htmlspecialchars ( $string );
+       } elseif ( in_array( 'escapenoentities', $options ) ) {
+               $string = htmlspecialchars( $string );
+               $string = str_replace( '&amp;', '&', $string );
+               $string = Sanitizer::normalizeCharReferences( $string );
        }
 
        if( in_array('replaceafter', $options) ) {
@@ -995,6 +1001,21 @@ function wfAppendQuery( $url, $query ) {
        return $url;
 }
 
+/**
+ * Expand a potentially local URL to a fully-qualified URL.
+ * Assumes $wgServer is correct. :)
+ * @param string $url, either fully-qualified or a local path + query
+ * @return string Fully-qualified URL
+ */
+function wfExpandUrl( $url ) {
+       if( substr( $url, 0, 1 ) == '/' ) {
+               global $wgServer;
+               return $wgServer . $url;
+       } else {
+               return $url;
+       }
+}
+
 /**
  * This is obsolete, use SquidUpdate::purge()
  * @deprecated
@@ -1659,13 +1680,29 @@ function wfMkdirParents( $fullDir, $mode = 0777 ) {
 /**
  * Increment a statistics counter
  */
- function wfIncrStats( $key ) {
-        global $wgMemc;
-        $key = wfMemcKey( 'stats', $key );
-        if ( is_null( $wgMemc->incr( $key ) ) ) {
-                $wgMemc->add( $key, 1 );
-        }
- }
+function wfIncrStats( $key ) {
+       global $wgStatsMethod;
+       
+       if( $wgStatsMethod == 'udp' ) {
+               global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgDBname;
+               static $socket;
+               if (!$socket) {
+                       $socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+                       $statline="stats/{$wgDBname} - 1 1 1 1 1 -total\n";
+                       socket_sendto($socket,$statline,strlen($statline),0,$wgUDPProfilerHost,$wgUDPProfilerPort);
+               }
+               $statline="stats/{$wgDBname} - 1 1 1 1 1 {$key}\n";
+               @socket_sendto($socket,$statline,strlen($statline),0,$wgUDPProfilerHost,$wgUDPProfilerPort);
+       } elseif( $wgStatsMethod == 'cache' ) {
+               global $wgMemc;
+               $key = wfMemcKey( 'stats', $key );
+               if ( is_null( $wgMemc->incr( $key ) ) ) {
+                       $wgMemc->add( $key, 1 );
+               }
+       } else {
+               // Disabled
+       }
+}
 
 /**
  * @param mixed $nr The number to format
@@ -1825,10 +1862,12 @@ function wfShellExec( $cmd, &$retval=null ) {
        }
        wfDebug( "wfShellExec: $cmd\n" );
        
-       $output = array();
        $retval = 1; // error by default?
-       exec( $cmd, $output, $retval ); // returns the last line of output.
-       return implode( "\n", $output );
+       ob_start();
+       passthru( $cmd, $retval );
+       $output = ob_get_contents();
+       ob_end_clean();
+       return $output;
        
 }
 
@@ -1945,8 +1984,8 @@ function wfRelativePath( $path, $from ) {
  */
 function wfMakeUrlIndex( $url ) {
        global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
-       $bits = parse_url( $url );
        wfSuppressWarnings();
+       $bits = parse_url( $url );
        wfRestoreWarnings();
        if ( !$bits ) {
                return false;
@@ -1970,13 +2009,19 @@ function wfMakeUrlIndex( $url ) {
        // Reverse the labels in the hostname, convert to lower case
        // For emails reverse domainpart only
        if ( $bits['scheme'] == 'mailto' ) {
-               $mailparts = explode( '@', $bits['host'] );
-               $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
+               $mailparts = explode( '@', $bits['host'], 2 );
+               if ( count($mailparts) === 2 ) {
+                       $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
+               } else {
+                       // No domain specified, don't mangle it
+                       $domainpart = '';
+               }
                $reversedHost = $domainpart . '@' . $mailparts[0];
        } else {
                $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) );
        }
        // Add an extra dot to the end
+       // Why? Is it in wrong place in mailto links?
        if ( substr( $reversedHost, -1, 1 ) !== '.' ) {
                $reversedHost .= '.';
        }
@@ -2262,7 +2307,7 @@ function &wfGetDB( $db = DB_LAST, $groups = array() ) {
  * @param mixed $title Title object or string. May be interwiki.
  * @param mixed $time Requested time for an archived image, or false for the 
  *                    current version. An image object will be returned which 
- *                    existed at or before the specified time.
+ *                    existed at the specified time.
  * @return File, or false if the file does not exist
  */
 function wfFindFile( $title, $time = false ) {
@@ -2335,4 +2380,24 @@ function wfGetNull() {
        return wfIsWindows()
                ? 'NUL'
                : '/dev/null';
-}
\ No newline at end of file
+}
+
+/**
+ * Displays a maxlag error
+ * 
+ * @param string $host Server that lags the most
+ * @param int $lag Maxlag (actual)
+ * @param int $maxLag Maxlag (requested)
+ */
+function wfMaxlagError( $host, $lag, $maxLag ) {
+       global $wgShowHostnames;
+       header( 'HTTP/1.1 503 Service Unavailable' );
+       header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
+       header( 'X-Database-Lag: ' . intval( $lag ) );
+       header( 'Content-Type: text/plain' );
+       if( $wgShowHostnames ) {
+               echo "Waiting for $host: $lag seconds lagged\n";
+       } else {
+               echo "Waiting for a database server: $lag seconds lagged\n";
+       }
+}