GlobalFunctions.php

Go to the documentation of this file.
00001 <?php
00023 if ( !defined( 'MEDIAWIKI' ) ) {
00024         die( "This file is part of MediaWiki, it is not a valid entry point" );
00025 }
00026 
00027 // Hide compatibility functions from Doxygen
00029 
00038 if( !function_exists( 'iconv' ) ) {
00043         function iconv( $from, $to, $string ) {
00044                 return Fallback::iconv( $from, $to, $string );
00045         }
00046 }
00047 
00048 if ( !function_exists( 'mb_substr' ) ) {
00053         function mb_substr( $str, $start, $count='end' ) {
00054                 return Fallback::mb_substr( $str, $start, $count );
00055         }
00056 
00061         function mb_substr_split_unicode( $str, $splitPos ) {
00062                 return Fallback::mb_substr_split_unicode( $str, $splitPos );
00063         }
00064 }
00065 
00066 if ( !function_exists( 'mb_strlen' ) ) {
00071         function mb_strlen( $str, $enc = '' ) {
00072                 return Fallback::mb_strlen( $str, $enc );
00073         }
00074 }
00075 
00076 if( !function_exists( 'mb_strpos' ) ) {
00081         function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
00082                 return Fallback::mb_strpos( $haystack, $needle, $offset, $encoding );
00083         }
00084 
00085 }
00086 
00087 if( !function_exists( 'mb_strrpos' ) ) {
00092         function mb_strrpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
00093                 return Fallback::mb_strrpos( $haystack, $needle, $offset, $encoding );
00094         }
00095 }
00096 
00097 
00098 // Support for Wietse Venema's taint feature
00099 if ( !function_exists( 'istainted' ) ) {
00104         function istainted( $var ) {
00105                 return 0;
00106         }
00108         function taint( $var, $level = 0 ) {}
00110         function untaint( $var, $level = 0 ) {}
00111         define( 'TC_HTML', 1 );
00112         define( 'TC_SHELL', 1 );
00113         define( 'TC_MYSQL', 1 );
00114         define( 'TC_PCRE', 1 );
00115         define( 'TC_SELF', 1 );
00116 }
00118 
00125 function wfArrayDiff2( $a, $b ) {
00126         return array_udiff( $a, $b, 'wfArrayDiff2_cmp' );
00127 }
00128 
00134 function wfArrayDiff2_cmp( $a, $b ) {
00135         if ( !is_array( $a ) ) {
00136                 return strcmp( $a, $b );
00137         } elseif ( count( $a ) !== count( $b ) ) {
00138                 return count( $a ) < count( $b ) ? -1 : 1;
00139         } else {
00140                 reset( $a );
00141                 reset( $b );
00142                 while( ( list( , $valueA ) = each( $a ) ) && ( list( , $valueB ) = each( $b ) ) ) {
00143                         $cmp = strcmp( $valueA, $valueB );
00144                         if ( $cmp !== 0 ) {
00145                                 return $cmp;
00146                         }
00147                 }
00148                 return 0;
00149         }
00150 }
00151 
00161 function wfArrayLookup( $a, $b ) {
00162         return array_flip( array_intersect( array_flip( $a ), array_keys( $b ) ) );
00163 }
00164 
00174 function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) {
00175         if ( is_null( $changed ) ) {
00176                 throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' );
00177         }
00178         if ( $default[$key] !== $value ) {
00179                 $changed[$key] = $value;
00180         }
00181 }
00182 
00191 function wfArrayMerge( $array1/* ... */ ) {
00192         $args = func_get_args();
00193         $args = array_reverse( $args, true );
00194         $out = array();
00195         foreach ( $args as $arg ) {
00196                 $out += $arg;
00197         }
00198         return $out;
00199 }
00200 
00219 function wfMergeErrorArrays( /*...*/ ) {
00220         $args = func_get_args();
00221         $out = array();
00222         foreach ( $args as $errors ) {
00223                 foreach ( $errors as $params ) {
00224                         # @todo FIXME: Sometimes get nested arrays for $params,
00225                         # which leads to E_NOTICEs
00226                         $spec = implode( "\t", $params );
00227                         $out[$spec] = $params;
00228                 }
00229         }
00230         return array_values( $out );
00231 }
00232 
00241 function wfArrayInsertAfter( array $array, array $insert, $after ) {
00242         // Find the offset of the element to insert after.
00243         $keys = array_keys( $array );
00244         $offsetByKey = array_flip( $keys );
00245 
00246         $offset = $offsetByKey[$after];
00247 
00248         // Insert at the specified offset
00249         $before = array_slice( $array, 0, $offset + 1, true );
00250         $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true );
00251 
00252         $output = $before + $insert + $after;
00253 
00254         return $output;
00255 }
00256 
00264 function wfObjectToArray( $objOrArray, $recursive = true ) {
00265         $array = array();
00266         if( is_object( $objOrArray ) ) {
00267                 $objOrArray = get_object_vars( $objOrArray );
00268         }
00269         foreach ( $objOrArray as $key => $value ) {
00270                 if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
00271                         $value = wfObjectToArray( $value );
00272                 }
00273 
00274                 $array[$key] = $value;
00275         }
00276 
00277         return $array;
00278 }
00279 
00287 function wfArrayMap( $function, $input ) {
00288         $ret = array_map( $function, $input );
00289         foreach ( $ret as $key => $value ) {
00290                 $taint = istainted( $input[$key] );
00291                 if ( $taint ) {
00292                         taint( $ret[$key], $taint );
00293                 }
00294         }
00295         return $ret;
00296 }
00297 
00305 function wfRandom() {
00306         # The maximum random value is "only" 2^31-1, so get two random
00307         # values to reduce the chance of dupes
00308         $max = mt_getrandmax() + 1;
00309         $rand = number_format( ( mt_rand() * $max + mt_rand() )
00310                 / $max / $max, 12, '.', '' );
00311         return $rand;
00312 }
00313 
00324 function wfRandomString( $length = 32 ) {
00325         $str = '';
00326         while ( strlen( $str ) < $length ) {
00327                 $str .= dechex( mt_rand() );
00328         }
00329         return substr( $str, 0, $length );
00330 }
00331 
00354 function wfUrlencode( $s ) {
00355         static $needle;
00356         if ( is_null( $s ) ) {
00357                 $needle = null;
00358                 return '';
00359         }
00360 
00361         if ( is_null( $needle ) ) {
00362                 $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' );
00363                 if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) || ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false ) ) {
00364                         $needle[] = '%3A';
00365                 }
00366         }
00367 
00368         $s = urlencode( $s );
00369         $s = str_ireplace(
00370                 $needle,
00371                 array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ),
00372                 $s
00373         );
00374 
00375         return $s;
00376 }
00377 
00388 function wfArrayToCgi( $array1, $array2 = null, $prefix = '' ) {
00389         if ( !is_null( $array2 ) ) {
00390                 $array1 = $array1 + $array2;
00391         }
00392 
00393         $cgi = '';
00394         foreach ( $array1 as $key => $value ) {
00395                 if ( !is_null($value) && $value !== false ) {
00396                         if ( $cgi != '' ) {
00397                                 $cgi .= '&';
00398                         }
00399                         if ( $prefix !== '' ) {
00400                                 $key = $prefix . "[$key]";
00401                         }
00402                         if ( is_array( $value ) ) {
00403                                 $firstTime = true;
00404                                 foreach ( $value as $k => $v ) {
00405                                         $cgi .= $firstTime ? '' : '&';
00406                                         if ( is_array( $v ) ) {
00407                                                 $cgi .= wfArrayToCgi( $v, null, $key . "[$k]" );
00408                                         } else {
00409                                                 $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v );
00410                                         }
00411                                         $firstTime = false;
00412                                 }
00413                         } else {
00414                                 if ( is_object( $value ) ) {
00415                                         $value = $value->__toString();
00416                                 }
00417                                 $cgi .= urlencode( $key ) . '=' . urlencode( $value );
00418                         }
00419                 }
00420         }
00421         return $cgi;
00422 }
00423 
00433 function wfCgiToArray( $query ) {
00434         if ( isset( $query[0] ) && $query[0] == '?' ) {
00435                 $query = substr( $query, 1 );
00436         }
00437         $bits = explode( '&', $query );
00438         $ret = array();
00439         foreach ( $bits as $bit ) {
00440                 if ( $bit === '' ) {
00441                         continue;
00442                 }
00443                 if ( strpos( $bit, '=' ) === false ) {
00444                         // Pieces like &qwerty become 'qwerty' => '' (at least this is what php does)
00445                         $key = $bit;
00446                         $value = '';
00447                 } else {
00448                         list( $key, $value ) = explode( '=', $bit );
00449                 }
00450                 $key = urldecode( $key );
00451                 $value = urldecode( $value );
00452                 if ( strpos( $key, '[' ) !== false ) {
00453                         $keys = array_reverse( explode( '[', $key ) );
00454                         $key = array_pop( $keys );
00455                         $temp = $value;
00456                         foreach ( $keys as $k ) {
00457                                 $k = substr( $k, 0, -1 );
00458                                 $temp = array( $k => $temp );
00459                         }
00460                         if ( isset( $ret[$key] ) ) {
00461                                 $ret[$key] = array_merge( $ret[$key], $temp );
00462                         } else {
00463                                 $ret[$key] = $temp;
00464                         }
00465                 } else {
00466                         $ret[$key] = $value;
00467                 }
00468         }
00469         return $ret;
00470 }
00471 
00480 function wfAppendQuery( $url, $query ) {
00481         if ( is_array( $query ) ) {
00482                 $query = wfArrayToCgi( $query );
00483         }
00484         if( $query != '' ) {
00485                 if( false === strpos( $url, '?' ) ) {
00486                         $url .= '?';
00487                 } else {
00488                         $url .= '&';
00489                 }
00490                 $url .= $query;
00491         }
00492         return $url;
00493 }
00494 
00517 function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
00518         global $wgServer, $wgCanonicalServer, $wgInternalServer;
00519         $serverUrl = $wgServer;
00520         if ( $defaultProto === PROTO_CANONICAL ) {
00521                 $serverUrl = $wgCanonicalServer;
00522         }
00523         // Make $wgInternalServer fall back to $wgServer if not set
00524         if ( $defaultProto === PROTO_INTERNAL && $wgInternalServer !== false ) {
00525                 $serverUrl = $wgInternalServer;
00526         }
00527         if ( $defaultProto === PROTO_CURRENT ) {
00528                 $defaultProto = WebRequest::detectProtocol() . '://';
00529         }
00530 
00531         // Analyze $serverUrl to obtain its protocol
00532         $bits = wfParseUrl( $serverUrl );
00533         $serverHasProto = $bits && $bits['scheme'] != '';
00534 
00535         if ( $defaultProto === PROTO_CANONICAL || $defaultProto === PROTO_INTERNAL ) {
00536                 if ( $serverHasProto ) {
00537                         $defaultProto = $bits['scheme'] . '://';
00538                 } else {
00539                         // $wgCanonicalServer or $wgInternalServer doesn't have a protocol. This really isn't supposed to happen
00540                         // Fall back to HTTP in this ridiculous case
00541                         $defaultProto = PROTO_HTTP;
00542                 }
00543         }
00544 
00545         $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 );
00546 
00547         if ( substr( $url, 0, 2 ) == '//' ) {
00548                 $url = $defaultProtoWithoutSlashes . $url;
00549         } elseif ( substr( $url, 0, 1 ) == '/' ) {
00550                 // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone
00551                 $url = ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $serverUrl . $url;
00552         }
00553 
00554         $bits = wfParseUrl( $url );
00555         if ( $bits && isset( $bits['path'] ) ) {
00556                 $bits['path'] = wfRemoveDotSegments( $bits['path'] );
00557                 return wfAssembleUrl( $bits );
00558         } elseif ( $bits ) {
00559                 # No path to expand
00560                 return $url;
00561         } elseif ( substr( $url, 0, 1 ) != '/' ) {
00562                 # URL is a relative path
00563                 return wfRemoveDotSegments( $url );
00564         }
00565 
00566         # Expanded URL is not valid.
00567         return false;
00568 }
00569 
00583 function wfAssembleUrl( $urlParts ) {
00584         $result = '';
00585 
00586         if ( isset( $urlParts['delimiter'] ) ) {
00587                 if ( isset( $urlParts['scheme'] ) ) {
00588                         $result .= $urlParts['scheme'];
00589                 }
00590 
00591                 $result .= $urlParts['delimiter'];
00592         }
00593 
00594         if ( isset( $urlParts['host'] ) ) {
00595                 if ( isset( $urlParts['user'] ) ) {
00596                         $result .= $urlParts['user'];
00597                         if ( isset( $urlParts['pass'] ) ) {
00598                                 $result .= ':' . $urlParts['pass'];
00599                         }
00600                         $result .= '@';
00601                 }
00602 
00603                 $result .= $urlParts['host'];
00604 
00605                 if ( isset( $urlParts['port'] ) ) {
00606                         $result .= ':' . $urlParts['port'];
00607                 }
00608         }
00609 
00610         if ( isset( $urlParts['path'] ) ) {
00611                 $result .= $urlParts['path'];
00612         }
00613 
00614         if ( isset( $urlParts['query'] ) ) {
00615                 $result .= '?' . $urlParts['query'];
00616         }
00617 
00618         if ( isset( $urlParts['fragment'] ) ) {
00619                 $result .= '#' . $urlParts['fragment'];
00620         }
00621 
00622         return $result;
00623 }
00624 
00635 function wfRemoveDotSegments( $urlPath ) {
00636         $output = '';
00637         $inputOffset = 0;
00638         $inputLength = strlen( $urlPath );
00639 
00640         while ( $inputOffset < $inputLength ) {
00641                 $prefixLengthOne = substr( $urlPath, $inputOffset, 1 );
00642                 $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 );
00643                 $prefixLengthThree = substr( $urlPath, $inputOffset, 3 );
00644                 $prefixLengthFour = substr( $urlPath, $inputOffset, 4 );
00645                 $trimOutput = false;
00646 
00647                 if ( $prefixLengthTwo == './' ) {
00648                         # Step A, remove leading "./"
00649                         $inputOffset += 2;
00650                 } elseif ( $prefixLengthThree == '../' ) {
00651                         # Step A, remove leading "../"
00652                         $inputOffset += 3;
00653                 } elseif ( ( $prefixLengthTwo == '/.' ) && ( $inputOffset + 2 == $inputLength ) ) {
00654                         # Step B, replace leading "/.$" with "/"
00655                         $inputOffset += 1;
00656                         $urlPath[$inputOffset] = '/';
00657                 } elseif ( $prefixLengthThree == '/./' ) {
00658                         # Step B, replace leading "/./" with "/"
00659                         $inputOffset += 2;
00660                 } elseif ( $prefixLengthThree == '/..' && ( $inputOffset + 3 == $inputLength ) ) {
00661                         # Step C, replace leading "/..$" with "/" and
00662                         # remove last path component in output
00663                         $inputOffset += 2;
00664                         $urlPath[$inputOffset] = '/';
00665                         $trimOutput = true;
00666                 } elseif ( $prefixLengthFour == '/../' ) {
00667                         # Step C, replace leading "/../" with "/" and
00668                         # remove last path component in output
00669                         $inputOffset += 3;
00670                         $trimOutput = true;
00671                 } elseif ( ( $prefixLengthOne == '.' ) && ( $inputOffset + 1 == $inputLength ) ) {
00672                         # Step D, remove "^.$"
00673                         $inputOffset += 1;
00674                 } elseif ( ( $prefixLengthTwo == '..' ) && ( $inputOffset + 2 == $inputLength ) ) {
00675                         # Step D, remove "^..$"
00676                         $inputOffset += 2;
00677                 } else {
00678                         # Step E, move leading path segment to output
00679                         if ( $prefixLengthOne == '/' ) {
00680                                 $slashPos = strpos( $urlPath, '/', $inputOffset + 1 );
00681                         } else {
00682                                 $slashPos = strpos( $urlPath, '/', $inputOffset );
00683                         }
00684                         if ( $slashPos === false ) {
00685                                 $output .= substr( $urlPath, $inputOffset );
00686                                 $inputOffset = $inputLength;
00687                         } else {
00688                                 $output .= substr( $urlPath, $inputOffset, $slashPos - $inputOffset );
00689                                 $inputOffset += $slashPos - $inputOffset;
00690                         }
00691                 }
00692 
00693                 if ( $trimOutput ) {
00694                         $slashPos = strrpos( $output, '/' );
00695                         if ( $slashPos === false ) {
00696                                 $output = '';
00697                         } else {
00698                                 $output = substr( $output, 0, $slashPos );
00699                         }
00700                 }
00701         }
00702 
00703         return $output;
00704 }
00705 
00713 function wfUrlProtocols( $includeProtocolRelative = true ) {
00714         global $wgUrlProtocols;
00715 
00716         // Cache return values separately based on $includeProtocolRelative
00717         static $withProtRel = null, $withoutProtRel = null;
00718         $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel;
00719         if ( !is_null( $cachedValue ) ) {
00720                 return $cachedValue;
00721         }
00722 
00723         // Support old-style $wgUrlProtocols strings, for backwards compatibility
00724         // with LocalSettings files from 1.5
00725         if ( is_array( $wgUrlProtocols ) ) {
00726                 $protocols = array();
00727                 foreach ( $wgUrlProtocols as $protocol ) {
00728                         // Filter out '//' if !$includeProtocolRelative
00729                         if ( $includeProtocolRelative || $protocol !== '//' ) {
00730                                 $protocols[] = preg_quote( $protocol, '/' );
00731                         }
00732                 }
00733 
00734                 $retval = implode( '|', $protocols );
00735         } else {
00736                 // Ignore $includeProtocolRelative in this case
00737                 // This case exists for pre-1.6 compatibility, and we can safely assume
00738                 // that '//' won't appear in a pre-1.6 config because protocol-relative
00739                 // URLs weren't supported until 1.18
00740                 $retval = $wgUrlProtocols;
00741         }
00742 
00743         // Cache return value
00744         if ( $includeProtocolRelative ) {
00745                 $withProtRel = $retval;
00746         } else {
00747                 $withoutProtRel = $retval;
00748         }
00749         return $retval;
00750 }
00751 
00758 function wfUrlProtocolsWithoutProtRel() {
00759         return wfUrlProtocols( false );
00760 }
00761 
00772 function wfParseUrl( $url ) {
00773         global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
00774 
00775         // Protocol-relative URLs are handled really badly by parse_url(). It's so bad that the easiest
00776         // way to handle them is to just prepend 'http:' and strip the protocol out later
00777         $wasRelative = substr( $url, 0, 2 ) == '//';
00778         if ( $wasRelative ) {
00779                 $url = "http:$url";
00780         }
00781         wfSuppressWarnings();
00782         $bits = parse_url( $url );
00783         wfRestoreWarnings();
00784         // parse_url() returns an array without scheme for some invalid URLs, e.g.
00785         // parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
00786         if ( !$bits || !isset( $bits['scheme'] ) ) {
00787                 return false;
00788         }
00789 
00790         // parse_url() incorrectly handles schemes case-sensitively. Convert it to lowercase.
00791         $bits['scheme'] = strtolower( $bits['scheme'] );
00792 
00793         // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it
00794         if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) {
00795                 $bits['delimiter'] = '://';
00796         } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) {
00797                 $bits['delimiter'] = ':';
00798                 // parse_url detects for news: and mailto: the host part of an url as path
00799                 // We have to correct this wrong detection
00800                 if ( isset( $bits['path'] ) ) {
00801                         $bits['host'] = $bits['path'];
00802                         $bits['path'] = '';
00803                 }
00804         } else {
00805                 return false;
00806         }
00807 
00808         /* Provide an empty host for eg. file:/// urls (see bug 28627) */
00809         if ( !isset( $bits['host'] ) ) {
00810                 $bits['host'] = '';
00811 
00812                 /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
00813                 if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
00814                         $bits['path'] = '/' . $bits['path'];
00815                 }
00816         }
00817 
00818         // If the URL was protocol-relative, fix scheme and delimiter
00819         if ( $wasRelative ) {
00820                 $bits['scheme'] = '';
00821                 $bits['delimiter'] = '//';
00822         }
00823         return $bits;
00824 }
00825 
00836 function wfExpandIRI( $url ) {
00837         return preg_replace_callback( '/((?:%[89A-F][0-9A-F])+)/i', 'wfExpandIRI_callback', wfExpandUrl( $url ) );
00838 }
00839 
00845 function wfExpandIRI_callback( $matches ) {
00846         return urldecode( $matches[1] );
00847 }
00848 
00849 
00850 
00857 function wfMakeUrlIndexes( $url ) {
00858         $bits = wfParseUrl( $url );
00859 
00860         // Reverse the labels in the hostname, convert to lower case
00861         // For emails reverse domainpart only
00862         if ( $bits['scheme'] == 'mailto' ) {
00863                 $mailparts = explode( '@', $bits['host'], 2 );
00864                 if ( count( $mailparts ) === 2 ) {
00865                         $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
00866                 } else {
00867                         // No domain specified, don't mangle it
00868                         $domainpart = '';
00869                 }
00870                 $reversedHost = $domainpart . '@' . $mailparts[0];
00871         } else {
00872                 $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) );
00873         }
00874         // Add an extra dot to the end
00875         // Why? Is it in wrong place in mailto links?
00876         if ( substr( $reversedHost, -1, 1 ) !== '.' ) {
00877                 $reversedHost .= '.';
00878         }
00879         // Reconstruct the pseudo-URL
00880         $prot = $bits['scheme'];
00881         $index = $prot . $bits['delimiter'] . $reversedHost;
00882         // Leave out user and password. Add the port, path, query and fragment
00883         if ( isset( $bits['port'] ) ) {
00884                 $index .= ':' . $bits['port'];
00885         }
00886         if ( isset( $bits['path'] ) ) {
00887                 $index .= $bits['path'];
00888         } else {
00889                 $index .= '/';
00890         }
00891         if ( isset( $bits['query'] ) ) {
00892                 $index .= '?' . $bits['query'];
00893         }
00894         if ( isset( $bits['fragment'] ) ) {
00895                 $index .= '#' . $bits['fragment'];
00896         }
00897 
00898         if ( $prot == '' ) {
00899                 return array( "http:$index", "https:$index" );
00900         } else {
00901                 return array( $index );
00902         }
00903 }
00904 
00911 function wfMatchesDomainList( $url, $domains ) {
00912         $bits = wfParseUrl( $url );
00913         if ( is_array( $bits ) && isset( $bits['host'] ) ) {
00914                 foreach ( (array)$domains as $domain ) {
00915                         // FIXME: This gives false positives. http://nds-nl.wikipedia.org will match nl.wikipedia.org
00916                         // We should use something that interprets dots instead
00917                         if ( substr( $bits['host'], -strlen( $domain ) ) === $domain ) {
00918                                 return true;
00919                         }
00920                 }
00921         }
00922         return false;
00923 }
00924 
00938 function wfDebug( $text, $logonly = false ) {
00939         global $wgDebugLogFile, $wgProfileOnly, $wgDebugRawPage, $wgDebugLogPrefix;
00940 
00941         if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
00942                 return;
00943         }
00944 
00945         $timer = wfDebugTimer();
00946         if ( $timer !== '' ) {
00947                 $text = preg_replace( '/[^\n]/', $timer . '\0', $text, 1 );
00948         }
00949 
00950         if ( !$logonly ) {
00951                 MWDebug::debugMsg( $text );
00952         }
00953 
00954         if ( wfRunHooks( 'Debug', array( $text, null /* no log group */ ) ) ) {
00955                 if ( $wgDebugLogFile != '' && !$wgProfileOnly ) {
00956                         # Strip unprintables; they can switch terminal modes when binary data
00957                         # gets dumped, which is pretty annoying.
00958                         $text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $text );
00959                         $text = $wgDebugLogPrefix . $text;
00960                         wfErrorLog( $text, $wgDebugLogFile );
00961                 }
00962         }
00963 }
00964 
00969 function wfIsDebugRawPage() {
00970         static $cache;
00971         if ( $cache !== null ) {
00972                 return $cache;
00973         }
00974         # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
00975         if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' )
00976                 || (
00977                         isset( $_SERVER['SCRIPT_NAME'] )
00978                         && substr( $_SERVER['SCRIPT_NAME'], -8 ) == 'load.php'
00979                 ) )
00980         {
00981                 $cache = true;
00982         } else {
00983                 $cache = false;
00984         }
00985         return $cache;
00986 }
00987 
00993 function wfDebugTimer() {
00994         global $wgDebugTimestamps, $wgRequestTime;
00995 
00996         if ( !$wgDebugTimestamps ) {
00997                 return '';
00998         }
00999 
01000         $prefix = sprintf( "%6.4f", microtime( true ) - $wgRequestTime );
01001         $mem = sprintf( "%5.1fM", ( memory_get_usage( true ) / ( 1024 * 1024 ) ) );
01002         return "$prefix $mem  ";
01003 }
01004 
01010 function wfDebugMem( $exact = false ) {
01011         $mem = memory_get_usage();
01012         if( !$exact ) {
01013                 $mem = floor( $mem / 1024 ) . ' kilobytes';
01014         } else {
01015                 $mem .= ' bytes';
01016         }
01017         wfDebug( "Memory usage: $mem\n" );
01018 }
01019 
01029 function wfDebugLog( $logGroup, $text, $public = true ) {
01030         global $wgDebugLogGroups;
01031         $text = trim( $text ) . "\n";
01032         if( isset( $wgDebugLogGroups[$logGroup] ) ) {
01033                 $time = wfTimestamp( TS_DB );
01034                 $wiki = wfWikiID();
01035                 $host = wfHostname();
01036                 if ( wfRunHooks( 'Debug', array( $text, $logGroup ) ) ) {
01037                         wfErrorLog( "$time $host $wiki: $text", $wgDebugLogGroups[$logGroup] );
01038                 }
01039         } elseif ( $public === true ) {
01040                 wfDebug( $text, true );
01041         }
01042 }
01043 
01049 function wfLogDBError( $text ) {
01050         global $wgDBerrorLog, $wgDBerrorLogTZ;
01051         static $logDBErrorTimeZoneObject = null;
01052 
01053         if ( $wgDBerrorLog ) {
01054                 $host = wfHostname();
01055                 $wiki = wfWikiID();
01056 
01057                 if ( $wgDBerrorLogTZ && !$logDBErrorTimeZoneObject ) {
01058                         $logDBErrorTimeZoneObject = new DateTimeZone( $wgDBerrorLogTZ );
01059                 }
01060 
01061                 // Workaround for https://bugs.php.net/bug.php?id=52063
01062                 // Can be removed when min PHP > 5.3.2
01063                 if ( $logDBErrorTimeZoneObject === null ) {
01064                         $d = date_create( "now" );
01065                 } else {
01066                         $d = date_create( "now", $logDBErrorTimeZoneObject );
01067                 }
01068 
01069                 $date = $d->format( 'D M j G:i:s T Y' );
01070 
01071                 $text = "$date\t$host\t$wiki\t$text";
01072                 wfErrorLog( $text, $wgDBerrorLog );
01073         }
01074 }
01075 
01088 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
01089         MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 );
01090 }
01091 
01102 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
01103         MWDebug::warning( $msg, $callerOffset + 1, $level );
01104 }
01105 
01116 function wfErrorLog( $text, $file ) {
01117         if ( substr( $file, 0, 4 ) == 'udp:' ) {
01118                 # Needs the sockets extension
01119                 if ( preg_match( '!^(tcp|udp):(?://)?\[([0-9a-fA-F:]+)\]:(\d+)(?:/(.*))?$!', $file, $m ) ) {
01120                         // IPv6 bracketed host
01121                         $host = $m[2];
01122                         $port = intval( $m[3] );
01123                         $prefix = isset( $m[4] ) ? $m[4] : false;
01124                         $domain = AF_INET6;
01125                 } elseif ( preg_match( '!^(tcp|udp):(?://)?([a-zA-Z0-9.-]+):(\d+)(?:/(.*))?$!', $file, $m ) ) {
01126                         $host = $m[2];
01127                         if ( !IP::isIPv4( $host ) ) {
01128                                 $host = gethostbyname( $host );
01129                         }
01130                         $port = intval( $m[3] );
01131                         $prefix = isset( $m[4] ) ? $m[4] : false;
01132                         $domain = AF_INET;
01133                 } else {
01134                         throw new MWException( __METHOD__ . ': Invalid UDP specification' );
01135                 }
01136 
01137                 // Clean it up for the multiplexer
01138                 if ( strval( $prefix ) !== '' ) {
01139                         $text = preg_replace( '/^/m', $prefix . ' ', $text );
01140 
01141                         // Limit to 64KB
01142                         if ( strlen( $text ) > 65506 ) {
01143                                 $text = substr( $text, 0, 65506 );
01144                         }
01145 
01146                         if ( substr( $text, -1 ) != "\n" ) {
01147                                 $text .= "\n";
01148                         }
01149                 } elseif ( strlen( $text ) > 65507 ) {
01150                         $text = substr( $text, 0, 65507 );
01151                 }
01152 
01153                 $sock = socket_create( $domain, SOCK_DGRAM, SOL_UDP );
01154                 if ( !$sock ) {
01155                         return;
01156                 }
01157 
01158                 socket_sendto( $sock, $text, strlen( $text ), 0, $host, $port );
01159                 socket_close( $sock );
01160         } else {
01161                 wfSuppressWarnings();
01162                 $exists = file_exists( $file );
01163                 $size = $exists ? filesize( $file ) : false;
01164                 if ( !$exists || ( $size !== false && $size + strlen( $text ) < 0x7fffffff ) ) {
01165                         file_put_contents( $file, $text, FILE_APPEND );
01166                 }
01167                 wfRestoreWarnings();
01168         }
01169 }
01170 
01174 function wfLogProfilingData() {
01175         global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest;
01176         global $wgProfileLimit, $wgUser;
01177 
01178         $profiler = Profiler::instance();
01179 
01180         # Profiling must actually be enabled...
01181         if ( $profiler->isStub() ) {
01182                 return;
01183         }
01184 
01185         // Get total page request time and only show pages that longer than
01186         // $wgProfileLimit time (default is 0)
01187         $elapsed = microtime( true ) - $wgRequestTime;
01188         if ( $elapsed <= $wgProfileLimit ) {
01189                 return;
01190         }
01191 
01192         $profiler->logData();
01193 
01194         // Check whether this should be logged in the debug file.
01195         if ( $wgDebugLogFile == '' || ( !$wgDebugRawPage && wfIsDebugRawPage() ) ) {
01196                 return;
01197         }
01198 
01199         $forward = '';
01200         if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
01201                 $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
01202         }
01203         if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
01204                 $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP'];
01205         }
01206         if ( !empty( $_SERVER['HTTP_FROM'] ) ) {
01207                 $forward .= ' from ' . $_SERVER['HTTP_FROM'];
01208         }
01209         if ( $forward ) {
01210                 $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})";
01211         }
01212         // Don't load $wgUser at this late stage just for statistics purposes
01213         // @todo FIXME: We can detect some anons even if it is not loaded. See User::getId()
01214         if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) {
01215                 $forward .= ' anon';
01216         }
01217         $log = sprintf( "%s\t%04.3f\t%s\n",
01218                 gmdate( 'YmdHis' ), $elapsed,
01219                 urldecode( $wgRequest->getRequestURL() . $forward ) );
01220 
01221         wfErrorLog( $log . $profiler->getOutput(), $wgDebugLogFile );
01222 }
01223 
01230 function wfIncrStats( $key, $count = 1 ) {
01231         global $wgStatsMethod;
01232 
01233         $count = intval( $count );
01234 
01235         if( $wgStatsMethod == 'udp' ) {
01236                 global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgDBname, $wgAggregateStatsID;
01237                 static $socket;
01238 
01239                 $id = $wgAggregateStatsID !== false ? $wgAggregateStatsID : $wgDBname;
01240 
01241                 if ( !$socket ) {
01242                         $socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
01243                         $statline = "stats/{$id} - 1 1 1 1 1 -total\n";
01244                         socket_sendto(
01245                                 $socket,
01246                                 $statline,
01247                                 strlen( $statline ),
01248                                 0,
01249                                 $wgUDPProfilerHost,
01250                                 $wgUDPProfilerPort
01251                         );
01252                 }
01253                 $statline = "stats/{$id} - {$count} 1 1 1 1 {$key}\n";
01254                 wfSuppressWarnings();
01255                 socket_sendto(
01256                         $socket,
01257                         $statline,
01258                         strlen( $statline ),
01259                         0,
01260                         $wgUDPProfilerHost,
01261                         $wgUDPProfilerPort
01262                 );
01263                 wfRestoreWarnings();
01264         } elseif( $wgStatsMethod == 'cache' ) {
01265                 global $wgMemc;
01266                 $key = wfMemcKey( 'stats', $key );
01267                 if ( is_null( $wgMemc->incr( $key, $count ) ) ) {
01268                         $wgMemc->add( $key, $count );
01269                 }
01270         } else {
01271                 // Disabled
01272         }
01273 }
01274 
01282 function wfReadOnly() {
01283         global $wgReadOnlyFile, $wgReadOnly;
01284 
01285         if ( !is_null( $wgReadOnly ) ) {
01286                 return (bool)$wgReadOnly;
01287         }
01288         if ( $wgReadOnlyFile == '' ) {
01289                 return false;
01290         }
01291         // Set $wgReadOnly for faster access next time
01292         if ( is_file( $wgReadOnlyFile ) ) {
01293                 $wgReadOnly = file_get_contents( $wgReadOnlyFile );
01294         } else {
01295                 $wgReadOnly = false;
01296         }
01297         return (bool)$wgReadOnly;
01298 }
01299 
01303 function wfReadOnlyReason() {
01304         global $wgReadOnly;
01305         wfReadOnly();
01306         return $wgReadOnly;
01307 }
01308 
01324 function wfGetLangObj( $langcode = false ) {
01325         # Identify which language to get or create a language object for.
01326         # Using is_object here due to Stub objects.
01327         if( is_object( $langcode ) ) {
01328                 # Great, we already have the object (hopefully)!
01329                 return $langcode;
01330         }
01331 
01332         global $wgContLang, $wgLanguageCode;
01333         if( $langcode === true || $langcode === $wgLanguageCode ) {
01334                 # $langcode is the language code of the wikis content language object.
01335                 # or it is a boolean and value is true
01336                 return $wgContLang;
01337         }
01338 
01339         global $wgLang;
01340         if( $langcode === false || $langcode === $wgLang->getCode() ) {
01341                 # $langcode is the language code of user language object.
01342                 # or it was a boolean and value is false
01343                 return $wgLang;
01344         }
01345 
01346         $validCodes = array_keys( Language::fetchLanguageNames() );
01347         if( in_array( $langcode, $validCodes ) ) {
01348                 # $langcode corresponds to a valid language.
01349                 return Language::factory( $langcode );
01350         }
01351 
01352         # $langcode is a string, but not a valid language code; use content language.
01353         wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
01354         return $wgContLang;
01355 }
01356 
01364 function wfUILang() {
01365         wfDeprecated( __METHOD__, '1.18' );
01366         global $wgLang;
01367         return $wgLang;
01368 }
01369 
01379 function wfMessage( $key /*...*/) {
01380         $params = func_get_args();
01381         array_shift( $params );
01382         if ( isset( $params[0] ) && is_array( $params[0] ) ) {
01383                 $params = $params[0];
01384         }
01385         return new Message( $key, $params );
01386 }
01387 
01396 function wfMessageFallback( /*...*/ ) {
01397         $args = func_get_args();
01398         return MWFunction::callArray( 'Message::newFallbackSequence', $args );
01399 }
01400 
01420 function wfMsg( $key ) {
01421         $args = func_get_args();
01422         array_shift( $args );
01423         return wfMsgReal( $key, $args );
01424 }
01425 
01434 function wfMsgNoTrans( $key ) {
01435         $args = func_get_args();
01436         array_shift( $args );
01437         return wfMsgReal( $key, $args, true, false, false );
01438 }
01439 
01465 function wfMsgForContent( $key ) {
01466         global $wgForceUIMsgAsContentMsg;
01467         $args = func_get_args();
01468         array_shift( $args );
01469         $forcontent = true;
01470         if( is_array( $wgForceUIMsgAsContentMsg ) &&
01471                 in_array( $key, $wgForceUIMsgAsContentMsg ) )
01472         {
01473                 $forcontent = false;
01474         }
01475         return wfMsgReal( $key, $args, true, $forcontent );
01476 }
01477 
01486 function wfMsgForContentNoTrans( $key ) {
01487         global $wgForceUIMsgAsContentMsg;
01488         $args = func_get_args();
01489         array_shift( $args );
01490         $forcontent = true;
01491         if( is_array( $wgForceUIMsgAsContentMsg ) &&
01492                 in_array( $key, $wgForceUIMsgAsContentMsg ) )
01493         {
01494                 $forcontent = false;
01495         }
01496         return wfMsgReal( $key, $args, true, $forcontent, false );
01497 }
01498 
01511 function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform = true ) {
01512         wfProfileIn( __METHOD__ );
01513         $message = wfMsgGetKey( $key, $useDB, $forContent, $transform );
01514         $message = wfMsgReplaceArgs( $message, $args );
01515         wfProfileOut( __METHOD__ );
01516         return $message;
01517 }
01518 
01531 function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true ) {
01532         wfRunHooks( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) );
01533 
01534         $cache = MessageCache::singleton();
01535         $message = $cache->get( $key, $useDB, $langCode );
01536         if( $message === false ) {
01537                 $message = '&lt;' . htmlspecialchars( $key ) . '&gt;';
01538         } elseif ( $transform ) {
01539                 $message = $cache->transform( $message );
01540         }
01541         return $message;
01542 }
01543 
01552 function wfMsgReplaceArgs( $message, $args ) {
01553         # Fix windows line-endings
01554         # Some messages are split with explode("\n", $msg)
01555         $message = str_replace( "\r", '', $message );
01556 
01557         // Replace arguments
01558         if ( count( $args ) ) {
01559                 if ( is_array( $args[0] ) ) {
01560                         $args = array_values( $args[0] );
01561                 }
01562                 $replacementKeys = array();
01563                 foreach( $args as $n => $param ) {
01564                         $replacementKeys['$' . ( $n + 1 )] = $param;
01565                 }
01566                 $message = strtr( $message, $replacementKeys );
01567         }
01568 
01569         return $message;
01570 }
01571 
01585 function wfMsgHtml( $key ) {
01586         $args = func_get_args();
01587         array_shift( $args );
01588         return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key ) ), $args );
01589 }
01590 
01604 function wfMsgWikiHtml( $key ) {
01605         $args = func_get_args();
01606         array_shift( $args );
01607         return wfMsgReplaceArgs(
01608                 MessageCache::singleton()->parse( wfMsgGetKey( $key ), null,
01609                 /* can't be set to false */ true, /* interface */ true )->getText(),
01610                 $args );
01611 }
01612 
01635 function wfMsgExt( $key, $options ) {
01636         $args = func_get_args();
01637         array_shift( $args );
01638         array_shift( $args );
01639         $options = (array)$options;
01640 
01641         foreach( $options as $arrayKey => $option ) {
01642                 if( !preg_match( '/^[0-9]+|language$/', $arrayKey ) ) {
01643                         # An unknown index, neither numeric nor "language"
01644                         wfWarn( "wfMsgExt called with incorrect parameter key $arrayKey", 1, E_USER_WARNING );
01645                 } elseif( preg_match( '/^[0-9]+$/', $arrayKey ) && !in_array( $option,
01646                 array( 'parse', 'parseinline', 'escape', 'escapenoentities',
01647                 'replaceafter', 'parsemag', 'content' ) ) ) {
01648                         # A numeric index with unknown value
01649                         wfWarn( "wfMsgExt called with incorrect parameter $option", 1, E_USER_WARNING );
01650                 }
01651         }
01652 
01653         if( in_array( 'content', $options, true ) ) {
01654                 $forContent = true;
01655                 $langCode = true;
01656                 $langCodeObj = null;
01657         } elseif( array_key_exists( 'language', $options ) ) {
01658                 $forContent = false;
01659                 $langCode = wfGetLangObj( $options['language'] );
01660                 $langCodeObj = $langCode;
01661         } else {
01662                 $forContent = false;
01663                 $langCode = false;
01664                 $langCodeObj = null;
01665         }
01666 
01667         $string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false );
01668 
01669         if( !in_array( 'replaceafter', $options, true ) ) {
01670                 $string = wfMsgReplaceArgs( $string, $args );
01671         }
01672 
01673         $messageCache = MessageCache::singleton();
01674         $parseInline = in_array( 'parseinline', $options, true );
01675         if( in_array( 'parse', $options, true ) || $parseInline ) {
01676                 $string = $messageCache->parse( $string, null, true, !$forContent, $langCodeObj );
01677                 if ( $string instanceof ParserOutput ) {
01678                         $string = $string->getText();
01679                 }
01680 
01681                 if ( $parseInline ) {
01682                         $m = array();
01683                         if( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $string, $m ) ) {
01684                                 $string = $m[1];
01685                         }
01686                 }
01687         } elseif ( in_array( 'parsemag', $options, true ) ) {
01688                 $string = $messageCache->transform( $string,
01689                                 !$forContent, $langCodeObj );
01690         }
01691 
01692         if ( in_array( 'escape', $options, true ) ) {
01693                 $string = htmlspecialchars ( $string );
01694         } elseif ( in_array( 'escapenoentities', $options, true ) ) {
01695                 $string = Sanitizer::escapeHtmlAllowEntities( $string );
01696         }
01697 
01698         if( in_array( 'replaceafter', $options, true ) ) {
01699                 $string = wfMsgReplaceArgs( $string, $args );
01700         }
01701 
01702         return $string;
01703 }
01704 
01715 function wfEmptyMsg( $key ) {
01716         return MessageCache::singleton()->get( $key, /*useDB*/true, /*content*/false ) === false;
01717 }
01718 
01726 function wfDebugDieBacktrace( $msg = '' ) {
01727         throw new MWException( $msg );
01728 }
01729 
01737 function wfHostname() {
01738         static $host;
01739         if ( is_null( $host ) ) {
01740 
01741                 # Hostname overriding
01742                 global $wgOverrideHostname;
01743                 if( $wgOverrideHostname !== false ) {
01744                         # Set static and skip any detection
01745                         $host = $wgOverrideHostname;
01746                         return $host;
01747                 }
01748 
01749                 if ( function_exists( 'posix_uname' ) ) {
01750                         // This function not present on Windows
01751                         $uname = posix_uname();
01752                 } else {
01753                         $uname = false;
01754                 }
01755                 if( is_array( $uname ) && isset( $uname['nodename'] ) ) {
01756                         $host = $uname['nodename'];
01757                 } elseif ( getenv( 'COMPUTERNAME' ) ) {
01758                         # Windows computer name
01759                         $host = getenv( 'COMPUTERNAME' );
01760                 } else {
01761                         # This may be a virtual server.
01762                         $host = $_SERVER['SERVER_NAME'];
01763                 }
01764         }
01765         return $host;
01766 }
01767 
01774 function wfReportTime() {
01775         global $wgRequestTime, $wgShowHostnames;
01776 
01777         $elapsed = microtime( true ) - $wgRequestTime;
01778 
01779         return $wgShowHostnames
01780                 ? sprintf( '<!-- Served by %s in %01.3f secs. -->', wfHostname(), $elapsed )
01781                 : sprintf( '<!-- Served in %01.3f secs. -->', $elapsed );
01782 }
01783 
01799 function wfDebugBacktrace( $limit = 0 ) {
01800         static $disabled = null;
01801 
01802         if( extension_loaded( 'Zend Optimizer' ) ) {
01803                 wfDebug( "Zend Optimizer detected; skipping debug_backtrace for safety.\n" );
01804                 return array();
01805         }
01806 
01807         if ( is_null( $disabled ) ) {
01808                 $disabled = false;
01809                 $functions = explode( ',', ini_get( 'disable_functions' ) );
01810                 $functions = array_map( 'trim', $functions );
01811                 $functions = array_map( 'strtolower', $functions );
01812                 if ( in_array( 'debug_backtrace', $functions ) ) {
01813                         wfDebug( "debug_backtrace is in disabled_functions\n" );
01814                         $disabled = true;
01815                 }
01816         }
01817         if ( $disabled ) {
01818                 return array();
01819         }
01820 
01821         if ( $limit && version_compare( PHP_VERSION, '5.4.0', '>=' ) ) {
01822                 return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
01823         } else {
01824                 return array_slice( debug_backtrace(), 1 );
01825         }
01826 }
01827 
01833 function wfBacktrace() {
01834         global $wgCommandLineMode;
01835 
01836         if ( $wgCommandLineMode ) {
01837                 $msg = '';
01838         } else {
01839                 $msg = "<ul>\n";
01840         }
01841         $backtrace = wfDebugBacktrace();
01842         foreach( $backtrace as $call ) {
01843                 if( isset( $call['file'] ) ) {
01844                         $f = explode( DIRECTORY_SEPARATOR, $call['file'] );
01845                         $file = $f[count( $f ) - 1];
01846                 } else {
01847                         $file = '-';
01848                 }
01849                 if( isset( $call['line'] ) ) {
01850                         $line = $call['line'];
01851                 } else {
01852                         $line = '-';
01853                 }
01854                 if ( $wgCommandLineMode ) {
01855                         $msg .= "$file line $line calls ";
01856                 } else {
01857                         $msg .= '<li>' . $file . ' line ' . $line . ' calls ';
01858                 }
01859                 if( !empty( $call['class'] ) ) {
01860                         $msg .= $call['class'] . $call['type'];
01861                 }
01862                 $msg .= $call['function'] . '()';
01863 
01864                 if ( $wgCommandLineMode ) {
01865                         $msg .= "\n";
01866                 } else {
01867                         $msg .= "</li>\n";
01868                 }
01869         }
01870         if ( $wgCommandLineMode ) {
01871                 $msg .= "\n";
01872         } else {
01873                 $msg .= "</ul>\n";
01874         }
01875 
01876         return $msg;
01877 }
01878 
01888 function wfGetCaller( $level = 2 ) {
01889         $backtrace = wfDebugBacktrace( $level + 1 );
01890         if ( isset( $backtrace[$level] ) ) {
01891                 return wfFormatStackFrame( $backtrace[$level] );
01892         } else {
01893                 return 'unknown';
01894         }
01895 }
01896 
01905 function wfGetAllCallers( $limit = 3 ) {
01906         $trace = array_reverse( wfDebugBacktrace() );
01907         if ( !$limit || $limit > count( $trace ) - 1 ) {
01908                 $limit = count( $trace ) - 1;
01909         }
01910         $trace = array_slice( $trace, -$limit - 1, $limit );
01911         return implode( '/', array_map( 'wfFormatStackFrame', $trace ) );
01912 }
01913 
01920 function wfFormatStackFrame( $frame ) {
01921         return isset( $frame['class'] ) ?
01922                 $frame['class'] . '::' . $frame['function'] :
01923                 $frame['function'];
01924 }
01925 
01926 
01927 /* Some generic result counters, pulled out of SearchEngine */
01928 
01929 
01937 function wfShowingResults( $offset, $limit ) {
01938         return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse();
01939 }
01940 
01952 function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) {
01953         wfDeprecated( __METHOD__, '1.19' );
01954 
01955         global $wgLang;
01956 
01957         $query = wfCgiToArray( $query );
01958 
01959         if( is_object( $link ) ) {
01960                 $title = $link;
01961         } else {
01962                 $title = Title::newFromText( $link );
01963                 if( is_null( $title ) ) {
01964                         return false;
01965                 }
01966         }
01967 
01968         return $wgLang->viewPrevNext( $title, $offset, $limit, $query, $atend );
01969 }
01970 
01981 function wfSpecialList( $page, $details, $oppositedm = true ) {
01982         wfDeprecated( __METHOD__, '1.19' );
01983 
01984         global $wgLang;
01985         return $wgLang->specialList( $page, $details, $oppositedm );
01986 }
01987 
01995 function wfClientAcceptsGzip( $force = false ) {
01996         static $result = null;
01997         if ( $result === null || $force ) {
01998                 $result = false;
01999                 if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
02000                         # @todo FIXME: We may want to blacklist some broken browsers
02001                         $m = array();
02002                         if( preg_match(
02003                                 '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
02004                                 $_SERVER['HTTP_ACCEPT_ENCODING'],
02005                                 $m )
02006                         )
02007                         {
02008                                 if( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) {
02009                                         $result = false;
02010                                         return $result;
02011                                 }
02012                                 wfDebug( "wfClientAcceptsGzip: client accepts gzip.\n" );
02013                                 $result = true;
02014                         }
02015                 }
02016         }
02017         return $result;
02018 }
02019 
02029 function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) {
02030         global $wgRequest;
02031         return $wgRequest->getLimitOffset( $deflimit, $optionname );
02032 }
02033 
02043 function wfEscapeWikiText( $text ) {
02044         $text = strtr( "\n$text", array(
02045                 '"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
02046                 '=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
02047                 '{' => '&#123;', '|' => '&#124;', '}' => '&#125;',
02048                 "\n#" => "\n&#35;", "\n*" => "\n&#42;",
02049                 "\n:" => "\n&#58;", "\n;" => "\n&#59;",
02050                 '://' => '&#58;//', 'ISBN ' => 'ISBN&#32;', 'RFC ' => 'RFC&#32;',
02051         ) );
02052         return substr( $text, 1 );
02053 }
02054 
02059 function wfTime() {
02060         return microtime( true );
02061 }
02062 
02073 function wfSetVar( &$dest, $source, $force = false ) {
02074         $temp = $dest;
02075         if ( !is_null( $source ) || $force ) {
02076                 $dest = $source;
02077         }
02078         return $temp;
02079 }
02080 
02090 function wfSetBit( &$dest, $bit, $state = true ) {
02091         $temp = (bool)( $dest & $bit );
02092         if ( !is_null( $state ) ) {
02093                 if ( $state ) {
02094                         $dest |= $bit;
02095                 } else {
02096                         $dest &= ~$bit;
02097                 }
02098         }
02099         return $temp;
02100 }
02101 
02108 function wfVarDump( $var ) {
02109         global $wgOut;
02110         $s = str_replace( "\n", "<br />\n", var_export( $var, true ) . "\n" );
02111         if ( headers_sent() || !isset( $wgOut ) || !is_object( $wgOut ) ) {
02112                 print $s;
02113         } else {
02114                 $wgOut->addHTML( $s );
02115         }
02116 }
02117 
02125 function wfHttpError( $code, $label, $desc ) {
02126         global $wgOut;
02127         $wgOut->disable();
02128         header( "HTTP/1.0 $code $label" );
02129         header( "Status: $code $label" );
02130         $wgOut->sendCacheControl();
02131 
02132         header( 'Content-type: text/html; charset=utf-8' );
02133         print "<!doctype html>" .
02134                 '<html><head><title>' .
02135                 htmlspecialchars( $label ) .
02136                 '</title></head><body><h1>' .
02137                 htmlspecialchars( $label ) .
02138                 '</h1><p>' .
02139                 nl2br( htmlspecialchars( $desc ) ) .
02140                 "</p></body></html>\n";
02141 }
02142 
02160 function wfResetOutputBuffers( $resetGzipEncoding = true ) {
02161         if( $resetGzipEncoding ) {
02162                 // Suppress Content-Encoding and Content-Length
02163                 // headers from 1.10+s wfOutputHandler
02164                 global $wgDisableOutputCompression;
02165                 $wgDisableOutputCompression = true;
02166         }
02167         while( $status = ob_get_status() ) {
02168                 if( $status['type'] == 0 /* PHP_OUTPUT_HANDLER_INTERNAL */ ) {
02169                         // Probably from zlib.output_compression or other
02170                         // PHP-internal setting which can't be removed.
02171                         //
02172                         // Give up, and hope the result doesn't break
02173                         // output behavior.
02174                         break;
02175                 }
02176                 if( !ob_end_clean() ) {
02177                         // Could not remove output buffer handler; abort now
02178                         // to avoid getting in some kind of infinite loop.
02179                         break;
02180                 }
02181                 if( $resetGzipEncoding ) {
02182                         if( $status['name'] == 'ob_gzhandler' ) {
02183                                 // Reset the 'Content-Encoding' field set by this handler
02184                                 // so we can start fresh.
02185                                 header_remove( 'Content-Encoding' );
02186                                 break;
02187                         }
02188                 }
02189         }
02190 }
02191 
02204 function wfClearOutputBuffers() {
02205         wfResetOutputBuffers( false );
02206 }
02207 
02216 function wfAcceptToPrefs( $accept, $def = '*/*' ) {
02217         # No arg means accept anything (per HTTP spec)
02218         if( !$accept ) {
02219                 return array( $def => 1.0 );
02220         }
02221 
02222         $prefs = array();
02223 
02224         $parts = explode( ',', $accept );
02225 
02226         foreach( $parts as $part ) {
02227                 # @todo FIXME: Doesn't deal with params like 'text/html; level=1'
02228                 $values = explode( ';', trim( $part ) );
02229                 $match = array();
02230                 if ( count( $values ) == 1 ) {
02231                         $prefs[$values[0]] = 1.0;
02232                 } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) {
02233                         $prefs[$values[0]] = floatval( $match[1] );
02234                 }
02235         }
02236 
02237         return $prefs;
02238 }
02239 
02252 function mimeTypeMatch( $type, $avail ) {
02253         if( array_key_exists( $type, $avail ) ) {
02254                 return $type;
02255         } else {
02256                 $parts = explode( '/', $type );
02257                 if( array_key_exists( $parts[0] . '/*', $avail ) ) {
02258                         return $parts[0] . '/*';
02259                 } elseif( array_key_exists( '*/*', $avail ) ) {
02260                         return '*/*';
02261                 } else {
02262                         return null;
02263                 }
02264         }
02265 }
02266 
02280 function wfNegotiateType( $cprefs, $sprefs ) {
02281         $combine = array();
02282 
02283         foreach( array_keys( $sprefs ) as $type ) {
02284                 $parts = explode( '/', $type );
02285                 if( $parts[1] != '*' ) {
02286                         $ckey = mimeTypeMatch( $type, $cprefs );
02287                         if( $ckey ) {
02288                                 $combine[$type] = $sprefs[$type] * $cprefs[$ckey];
02289                         }
02290                 }
02291         }
02292 
02293         foreach( array_keys( $cprefs ) as $type ) {
02294                 $parts = explode( '/', $type );
02295                 if( $parts[1] != '*' && !array_key_exists( $type, $sprefs ) ) {
02296                         $skey = mimeTypeMatch( $type, $sprefs );
02297                         if( $skey ) {
02298                                 $combine[$type] = $sprefs[$skey] * $cprefs[$type];
02299                         }
02300                 }
02301         }
02302 
02303         $bestq = 0;
02304         $besttype = null;
02305 
02306         foreach( array_keys( $combine ) as $type ) {
02307                 if( $combine[$type] > $bestq ) {
02308                         $besttype = $type;
02309                         $bestq = $combine[$type];
02310                 }
02311         }
02312 
02313         return $besttype;
02314 }
02315 
02321 function wfSuppressWarnings( $end = false ) {
02322         static $suppressCount = 0;
02323         static $originalLevel = false;
02324 
02325         if ( $end ) {
02326                 if ( $suppressCount ) {
02327                         --$suppressCount;
02328                         if ( !$suppressCount ) {
02329                                 error_reporting( $originalLevel );
02330                         }
02331                 }
02332         } else {
02333                 if ( !$suppressCount ) {
02334                         $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED ) );
02335                 }
02336                 ++$suppressCount;
02337         }
02338 }
02339 
02343 function wfRestoreWarnings() {
02344         wfSuppressWarnings( true );
02345 }
02346 
02347 # Autodetect, convert and provide timestamps of various types
02348 
02352 define( 'TS_UNIX', 0 );
02353 
02357 define( 'TS_MW', 1 );
02358 
02362 define( 'TS_DB', 2 );
02363 
02367 define( 'TS_RFC2822', 3 );
02368 
02374 define( 'TS_ISO_8601', 4 );
02375 
02383 define( 'TS_EXIF', 5 );
02384 
02388 define( 'TS_ORACLE', 6 );
02389 
02393 define( 'TS_POSTGRES', 7 );
02394 
02398 define( 'TS_DB2', 8 );
02399 
02403 define( 'TS_ISO_8601_BASIC', 9 );
02404 
02414 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
02415         try {
02416                 $timestamp = new MWTimestamp( $ts );
02417                 return $timestamp->getTimestamp( $outputtype );
02418         } catch( TimestampException $e ) {
02419                 wfDebug("wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n");
02420                 return false;
02421         }
02422 }
02423 
02432 function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) {
02433         if( is_null( $ts ) ) {
02434                 return null;
02435         } else {
02436                 return wfTimestamp( $outputtype, $ts );
02437         }
02438 }
02439 
02445 function wfTimestampNow() {
02446         # return NOW
02447         return wfTimestamp( TS_MW, time() );
02448 }
02449 
02455 function wfIsWindows() {
02456         static $isWindows = null;
02457         if ( $isWindows === null ) {
02458                 $isWindows = substr( php_uname(), 0, 7 ) == 'Windows';
02459         }
02460         return $isWindows;
02461 }
02462 
02468 function wfIsHipHop() {
02469         return function_exists( 'hphp_thread_set_warmup_enabled' );
02470 }
02471 
02478 function swap( &$x, &$y ) {
02479         $z = $x;
02480         $x = $y;
02481         $y = $z;
02482 }
02483 
02495 function wfTempDir() {
02496         global $wgTmpDirectory;
02497 
02498         if ( $wgTmpDirectory !== false ) {
02499                 return $wgTmpDirectory;
02500         }
02501 
02502         $tmpDir = array_map( "getenv", array( 'TMPDIR', 'TMP', 'TEMP' ) );
02503 
02504         foreach( $tmpDir as $tmp ) {
02505                 if( $tmp && file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
02506                         return $tmp;
02507                 }
02508         }
02509         return sys_get_temp_dir();
02510 }
02511 
02521 function wfMkdirParents( $dir, $mode = null, $caller = null ) {
02522         global $wgDirectoryMode;
02523 
02524         if ( FileBackend::isStoragePath( $dir ) ) { // sanity
02525                 throw new MWException( __FUNCTION__ . " given storage path '$dir'." );
02526         }
02527 
02528         if ( !is_null( $caller ) ) {
02529                 wfDebug( "$caller: called wfMkdirParents($dir)\n" );
02530         }
02531 
02532         if( strval( $dir ) === '' || file_exists( $dir ) ) {
02533                 return true;
02534         }
02535 
02536         $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir );
02537 
02538         if ( is_null( $mode ) ) {
02539                 $mode = $wgDirectoryMode;
02540         }
02541 
02542         // Turn off the normal warning, we're doing our own below
02543         wfSuppressWarnings();
02544         $ok = mkdir( $dir, $mode, true ); // PHP5 <3
02545         wfRestoreWarnings();
02546 
02547         if( !$ok ) {
02548                 // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
02549                 trigger_error( sprintf( "%s: failed to mkdir \"%s\" mode 0%o", __FUNCTION__, $dir, $mode ),
02550                         E_USER_WARNING );
02551         }
02552         return $ok;
02553 }
02554 
02559 function wfRecursiveRemoveDir( $dir ) {
02560         wfDebug( __FUNCTION__ . "( $dir )\n" );
02561         // taken from http://de3.php.net/manual/en/function.rmdir.php#98622
02562         if ( is_dir( $dir ) ) {
02563                 $objects = scandir( $dir );
02564                 foreach ( $objects as $object ) {
02565                         if ( $object != "." && $object != ".." ) {
02566                                 if ( filetype( $dir . '/' . $object ) == "dir" ) {
02567                                         wfRecursiveRemoveDir( $dir . '/' . $object );
02568                                 } else {
02569                                         unlink( $dir . '/' . $object );
02570                                 }
02571                         }
02572                 }
02573                 reset( $objects );
02574                 rmdir( $dir );
02575         }
02576 }
02577 
02584 function wfPercent( $nr, $acc = 2, $round = true ) {
02585         $ret = sprintf( "%.${acc}f", $nr );
02586         return $round ? round( $ret, $acc ) . '%' : "$ret%";
02587 }
02588 
02597 function in_string( $needle, $str, $insensitive = false ) {
02598         $func = 'strpos';
02599         if( $insensitive ) $func = 'stripos';
02600 
02601         return $func( $str, $needle ) !== false;
02602 }
02603 
02627 function wfIniGetBool( $setting ) {
02628         $val = ini_get( $setting );
02629         // 'on' and 'true' can't have whitespace around them, but '1' can.
02630         return strtolower( $val ) == 'on'
02631                 || strtolower( $val ) == 'true'
02632                 || strtolower( $val ) == 'yes'
02633                 || preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function
02634 }
02635 
02645 function wfDl( $extension, $fileName = null ) {
02646         if( extension_loaded( $extension ) ) {
02647                 return true;
02648         }
02649 
02650         $canDl = false;
02651         $sapi = php_sapi_name();
02652         if( $sapi == 'cli' || $sapi == 'cgi' || $sapi == 'embed' ) {
02653                 $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' )
02654                 && wfIniGetBool( 'enable_dl' ) && !wfIniGetBool( 'safe_mode' ) );
02655         }
02656 
02657         if( $canDl ) {
02658                 $fileName = $fileName ? $fileName : $extension;
02659                 if( wfIsWindows() ) {
02660                         $fileName = 'php_' . $fileName;
02661                 }
02662                 wfSuppressWarnings();
02663                 dl( $fileName . '.' . PHP_SHLIB_SUFFIX );
02664                 wfRestoreWarnings();
02665         }
02666         return extension_loaded( $extension );
02667 }
02668 
02680 function wfEscapeShellArg( ) {
02681         wfInitShellLocale();
02682 
02683         $args = func_get_args();
02684         $first = true;
02685         $retVal = '';
02686         foreach ( $args as $arg ) {
02687                 if ( !$first ) {
02688                         $retVal .= ' ';
02689                 } else {
02690                         $first = false;
02691                 }
02692 
02693                 if ( wfIsWindows() ) {
02694                         // Escaping for an MSVC-style command line parser and CMD.EXE
02695                         // Refs:
02696                         //  * https://waybackassets.bk21.net/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
02697                         //  * http://technet.microsoft.com/en-us/library/cc723564.aspx
02698                         //  * Bug #13518
02699                         //  * CR r63214
02700                         // Double the backslashes before any double quotes. Escape the double quotes.
02701                         $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
02702                         $arg = '';
02703                         $iteration = 0;
02704                         foreach ( $tokens as $token ) {
02705                                 if ( $iteration % 2 == 1 ) {
02706                                         // Delimiter, a double quote preceded by zero or more slashes
02707                                         $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"';
02708                                 } elseif ( $iteration % 4 == 2 ) {
02709                                         // ^ in $token will be outside quotes, need to be escaped
02710                                         $arg .= str_replace( '^', '^^', $token );
02711                                 } else { // $iteration % 4 == 0
02712                                         // ^ in $token will appear inside double quotes, so leave as is
02713                                         $arg .= $token;
02714                                 }
02715                                 $iteration++;
02716                         }
02717                         // Double the backslashes before the end of the string, because
02718                         // we will soon add a quote
02719                         $m = array();
02720                         if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
02721                                 $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
02722                         }
02723 
02724                         // Add surrounding quotes
02725                         $retVal .= '"' . $arg . '"';
02726                 } else {
02727                         $retVal .= escapeshellarg( $arg );
02728                 }
02729         }
02730         return $retVal;
02731 }
02732 
02745 function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
02746         global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime;
02747 
02748         static $disabled;
02749         if ( is_null( $disabled ) ) {
02750                 $disabled = false;
02751                 if( wfIniGetBool( 'safe_mode' ) ) {
02752                         wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
02753                         $disabled = 'safemode';
02754                 } else {
02755                         $functions = explode( ',', ini_get( 'disable_functions' ) );
02756                         $functions = array_map( 'trim', $functions );
02757                         $functions = array_map( 'strtolower', $functions );
02758                         if ( in_array( 'passthru', $functions ) ) {
02759                                 wfDebug( "passthru is in disabled_functions\n" );
02760                                 $disabled = 'passthru';
02761                         }
02762                 }
02763         }
02764         if ( $disabled ) {
02765                 $retval = 1;
02766                 return $disabled == 'safemode' ?
02767                         'Unable to run external programs in safe mode.' :
02768                         'Unable to run external programs, passthru() is disabled.';
02769         }
02770 
02771         wfInitShellLocale();
02772 
02773         $envcmd = '';
02774         foreach( $environ as $k => $v ) {
02775                 if ( wfIsWindows() ) {
02776                         /* Surrounding a set in quotes (method used by wfEscapeShellArg) makes the quotes themselves
02777                          * appear in the environment variable, so we must use carat escaping as documented in
02778                          * http://technet.microsoft.com/en-us/library/cc723564.aspx
02779                          * Note however that the quote isn't listed there, but is needed, and the parentheses
02780                          * are listed there but doesn't appear to need it.
02781                          */
02782                         $envcmd .= "set $k=" . preg_replace( '/([&|()<>^"])/', '^\\1', $v ) . '&& ';
02783                 } else {
02784                         /* Assume this is a POSIX shell, thus required to accept variable assignments before the command
02785                          * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_01
02786                          */
02787                         $envcmd .= "$k=" . escapeshellarg( $v ) . ' ';
02788                 }
02789         }
02790         $cmd = $envcmd . $cmd;
02791 
02792         if ( php_uname( 's' ) == 'Linux' ) {
02793                 $time = intval ( isset($limits['time']) ? $limits['time'] : $wgMaxShellTime );
02794                 $mem = intval ( isset($limits['memory']) ? $limits['memory'] : $wgMaxShellMemory );
02795                 $filesize = intval ( isset($limits['filesize']) ? $limits['filesize'] : $wgMaxShellFileSize );
02796 
02797                 if ( $time > 0 && $mem > 0 ) {
02798                         $script = "$IP/bin/ulimit4.sh";
02799                         if ( is_executable( $script ) ) {
02800                                 $cmd = '/bin/bash ' . escapeshellarg( $script ) . " $time $mem $filesize " . escapeshellarg( $cmd );
02801                         }
02802                 }
02803         }
02804         wfDebug( "wfShellExec: $cmd\n" );
02805 
02806         $retval = 1; // error by default?
02807         ob_start();
02808         passthru( $cmd, $retval );
02809         $output = ob_get_contents();
02810         ob_end_clean();
02811 
02812         if ( $retval == 127 ) {
02813                 wfDebugLog( 'exec', "Possibly missing executable file: $cmd\n" );
02814         }
02815         return $output;
02816 }
02817 
02822 function wfInitShellLocale() {
02823         static $done = false;
02824         if ( $done ) {
02825                 return;
02826         }
02827         $done = true;
02828         global $wgShellLocale;
02829         if ( !wfIniGetBool( 'safe_mode' ) ) {
02830                 putenv( "LC_CTYPE=$wgShellLocale" );
02831                 setlocale( LC_CTYPE, $wgShellLocale );
02832         }
02833 }
02834 
02839 function wfShellMaintenanceCmd( $script, array $parameters = array(), array $options = array() ) {
02840         return wfShellWikiCmd( $script, $parameters, $options );
02841 }
02842 
02854 function wfShellWikiCmd( $script, array $parameters = array(), array $options = array() ) {
02855         global $wgPhpCli;
02856         // Give site config file a chance to run the script in a wrapper.
02857         // The caller may likely want to call wfBasename() on $script.
02858         wfRunHooks( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) );
02859         $cmd = isset( $options['php'] ) ? array( $options['php'] ) : array( $wgPhpCli );
02860         if ( isset( $options['wrapper'] ) ) {
02861                 $cmd[] = $options['wrapper'];
02862         }
02863         $cmd[] = $script;
02864         // Escape each parameter for shell
02865         return implode( " ", array_map( 'wfEscapeShellArg', array_merge( $cmd, $parameters ) ) );
02866 }
02867 
02878 function wfMerge( $old, $mine, $yours, &$result ) {
02879         global $wgDiff3;
02880 
02881         # This check may also protect against code injection in
02882         # case of broken installations.
02883         wfSuppressWarnings();
02884         $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
02885         wfRestoreWarnings();
02886 
02887         if( !$haveDiff3 ) {
02888                 wfDebug( "diff3 not found\n" );
02889                 return false;
02890         }
02891 
02892         # Make temporary files
02893         $td = wfTempDir();
02894         $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
02895         $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
02896         $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
02897 
02898         fwrite( $oldtextFile, $old );
02899         fclose( $oldtextFile );
02900         fwrite( $mytextFile, $mine );
02901         fclose( $mytextFile );
02902         fwrite( $yourtextFile, $yours );
02903         fclose( $yourtextFile );
02904 
02905         # Check for a conflict
02906         $cmd = $wgDiff3 . ' -a --overlap-only ' .
02907                 wfEscapeShellArg( $mytextName ) . ' ' .
02908                 wfEscapeShellArg( $oldtextName ) . ' ' .
02909                 wfEscapeShellArg( $yourtextName );
02910         $handle = popen( $cmd, 'r' );
02911 
02912         if( fgets( $handle, 1024 ) ) {
02913                 $conflict = true;
02914         } else {
02915                 $conflict = false;
02916         }
02917         pclose( $handle );
02918 
02919         # Merge differences
02920         $cmd = $wgDiff3 . ' -a -e --merge ' .
02921                 wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName );
02922         $handle = popen( $cmd, 'r' );
02923         $result = '';
02924         do {
02925                 $data = fread( $handle, 8192 );
02926                 if ( strlen( $data ) == 0 ) {
02927                         break;
02928                 }
02929                 $result .= $data;
02930         } while ( true );
02931         pclose( $handle );
02932         unlink( $mytextName );
02933         unlink( $oldtextName );
02934         unlink( $yourtextName );
02935 
02936         if ( $result === '' && $old !== '' && !$conflict ) {
02937                 wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
02938                 $conflict = true;
02939         }
02940         return !$conflict;
02941 }
02942 
02952 function wfDiff( $before, $after, $params = '-u' ) {
02953         if ( $before == $after ) {
02954                 return '';
02955         }
02956 
02957         global $wgDiff;
02958         wfSuppressWarnings();
02959         $haveDiff = $wgDiff && file_exists( $wgDiff );
02960         wfRestoreWarnings();
02961 
02962         # This check may also protect against code injection in
02963         # case of broken installations.
02964         if( !$haveDiff ) {
02965                 wfDebug( "diff executable not found\n" );
02966                 $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) );
02967                 $format = new UnifiedDiffFormatter();
02968                 return $format->format( $diffs );
02969         }
02970 
02971         # Make temporary files
02972         $td = wfTempDir();
02973         $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
02974         $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' );
02975 
02976         fwrite( $oldtextFile, $before );
02977         fclose( $oldtextFile );
02978         fwrite( $newtextFile, $after );
02979         fclose( $newtextFile );
02980 
02981         // Get the diff of the two files
02982         $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName );
02983 
02984         $h = popen( $cmd, 'r' );
02985 
02986         $diff = '';
02987 
02988         do {
02989                 $data = fread( $h, 8192 );
02990                 if ( strlen( $data ) == 0 ) {
02991                         break;
02992                 }
02993                 $diff .= $data;
02994         } while ( true );
02995 
02996         // Clean up
02997         pclose( $h );
02998         unlink( $oldtextName );
02999         unlink( $newtextName );
03000 
03001         // Kill the --- and +++ lines. They're not useful.
03002         $diff_lines = explode( "\n", $diff );
03003         if ( strpos( $diff_lines[0], '---' ) === 0 ) {
03004                 unset( $diff_lines[0] );
03005         }
03006         if ( strpos( $diff_lines[1], '+++' ) === 0 ) {
03007                 unset( $diff_lines[1] );
03008         }
03009 
03010         $diff = implode( "\n", $diff_lines );
03011 
03012         return $diff;
03013 }
03014 
03031 function wfUsePHP( $req_ver ) {
03032         $php_ver = PHP_VERSION;
03033 
03034         if ( version_compare( $php_ver, (string)$req_ver, '<' ) ) {
03035                 throw new MWException( "PHP $req_ver required--this is only $php_ver" );
03036         }
03037 }
03038 
03053 function wfUseMW( $req_ver ) {
03054         global $wgVersion;
03055 
03056         if ( version_compare( $wgVersion, (string)$req_ver, '<' ) ) {
03057                 throw new MWException( "MediaWiki $req_ver required--this is only $wgVersion" );
03058         }
03059 }
03060 
03073 function wfBaseName( $path, $suffix = '' ) {
03074         $encSuffix = ( $suffix == '' )
03075                 ? ''
03076                 : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' );
03077         $matches = array();
03078         if( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
03079                 return $matches[1];
03080         } else {
03081                 return '';
03082         }
03083 }
03084 
03094 function wfRelativePath( $path, $from ) {
03095         // Normalize mixed input on Windows...
03096         $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
03097         $from = str_replace( '/', DIRECTORY_SEPARATOR, $from );
03098 
03099         // Trim trailing slashes -- fix for drive root
03100         $path = rtrim( $path, DIRECTORY_SEPARATOR );
03101         $from = rtrim( $from, DIRECTORY_SEPARATOR );
03102 
03103         $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) );
03104         $against = explode( DIRECTORY_SEPARATOR, $from );
03105 
03106         if( $pieces[0] !== $against[0] ) {
03107                 // Non-matching Windows drive letters?
03108                 // Return a full path.
03109                 return $path;
03110         }
03111 
03112         // Trim off common prefix
03113         while( count( $pieces ) && count( $against )
03114                 && $pieces[0] == $against[0] ) {
03115                 array_shift( $pieces );
03116                 array_shift( $against );
03117         }
03118 
03119         // relative dots to bump us to the parent
03120         while( count( $against ) ) {
03121                 array_unshift( $pieces, '..' );
03122                 array_shift( $against );
03123         }
03124 
03125         array_push( $pieces, wfBaseName( $path ) );
03126 
03127         return implode( DIRECTORY_SEPARATOR, $pieces );
03128 }
03129 
03137 function wfDoUpdates( $commit = '' ) {
03138         wfDeprecated( __METHOD__, '1.19' );
03139         DeferredUpdates::doUpdates( $commit );
03140 }
03141 
03156 function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true ) {
03157         $input = strval( $input );
03158         if( $sourceBase < 2 ||
03159                 $sourceBase > 36 ||
03160                 $destBase < 2 ||
03161                 $destBase > 36 ||
03162                 $pad < 1 ||
03163                 $sourceBase != intval( $sourceBase ) ||
03164                 $destBase != intval( $destBase ) ||
03165                 $pad != intval( $pad ) ||
03166                 !is_string( $input ) ||
03167                 $input == '' ) {
03168                 return false;
03169         }
03170         $digitChars = ( $lowercase ) ? '0123456789abcdefghijklmnopqrstuvwxyz' : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
03171         $inDigits = array();
03172         $outChars = '';
03173 
03174         // Decode and validate input string
03175         $input = strtolower( $input );
03176         for( $i = 0; $i < strlen( $input ); $i++ ) {
03177                 $n = strpos( $digitChars, $input[$i] );
03178                 if( $n === false || $n > $sourceBase ) {
03179                         return false;
03180                 }
03181                 $inDigits[] = $n;
03182         }
03183 
03184         // Iterate over the input, modulo-ing out an output digit
03185         // at a time until input is gone.
03186         while( count( $inDigits ) ) {
03187                 $work = 0;
03188                 $workDigits = array();
03189 
03190                 // Long division...
03191                 foreach( $inDigits as $digit ) {
03192                         $work *= $sourceBase;
03193                         $work += $digit;
03194 
03195                         if( $work < $destBase ) {
03196                                 // Gonna need to pull another digit.
03197                                 if( count( $workDigits ) ) {
03198                                         // Avoid zero-padding; this lets us find
03199                                         // the end of the input very easily when
03200                                         // length drops to zero.
03201                                         $workDigits[] = 0;
03202                                 }
03203                         } else {
03204                                 // Finally! Actual division!
03205                                 $workDigits[] = intval( $work / $destBase );
03206 
03207                                 // Isn't it annoying that most programming languages
03208                                 // don't have a single divide-and-remainder operator,
03209                                 // even though the CPU implements it that way?
03210                                 $work = $work % $destBase;
03211                         }
03212                 }
03213 
03214                 // All that division leaves us with a remainder,
03215                 // which is conveniently our next output digit.
03216                 $outChars .= $digitChars[$work];
03217 
03218                 // And we continue!
03219                 $inDigits = $workDigits;
03220         }
03221 
03222         while( strlen( $outChars ) < $pad ) {
03223                 $outChars .= '0';
03224         }
03225 
03226         return strrev( $outChars );
03227 }
03228 
03237 function wfCreateObject( $name, $p ) {
03238         wfDeprecated( __FUNCTION__, '1.18' );
03239         return MWFunction::newObj( $name, $p );
03240 }
03241 
03245 function wfHttpOnlySafe() {
03246         global $wgHttpOnlyBlacklist;
03247 
03248         if( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
03249                 foreach( $wgHttpOnlyBlacklist as $regex ) {
03250                         if( preg_match( $regex, $_SERVER['HTTP_USER_AGENT'] ) ) {
03251                                 return false;
03252                         }
03253                 }
03254         }
03255 
03256         return true;
03257 }
03258 
03263 function wfFixSessionID() {
03264         // If the cookie or session id is already set we already have a session and should abort
03265         if ( isset( $_COOKIE[ session_name() ] ) || session_id() ) {
03266                 return;
03267         }
03268 
03269         // PHP's built-in session entropy is enabled if:
03270         // - entropy_file is set or you're on Windows with php 5.3.3+
03271         // - AND entropy_length is > 0
03272         // We treat it as disabled if it doesn't have an entropy length of at least 32
03273         $entropyEnabled = (
03274                         ( wfIsWindows() && version_compare( PHP_VERSION, '5.3.3', '>=' ) )
03275                         || ini_get( 'session.entropy_file' )
03276                 )
03277                 && intval( ini_get( 'session.entropy_length' ) ) >= 32;
03278 
03279         // If built-in entropy is not enabled or not sufficient override php's built in session id generation code
03280         if ( !$entropyEnabled ) {
03281                 wfDebug( __METHOD__ . ": PHP's built in entropy is disabled or not sufficient, overriding session id generation using our cryptrand source.\n" );
03282                 session_id( MWCryptRand::generateHex( 32 ) );
03283         }
03284 }
03285 
03291 function wfSetupSession( $sessionId = false ) {
03292         global $wgSessionsInMemcached, $wgSessionsInObjectCache, $wgCookiePath, $wgCookieDomain,
03293                         $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler;
03294         if( $wgSessionsInObjectCache || $wgSessionsInMemcached ) {
03295                 ObjectCacheSessionHandler::install();
03296         } elseif( $wgSessionHandler && $wgSessionHandler != ini_get( 'session.save_handler' ) ) {
03297                 # Only set this if $wgSessionHandler isn't null and session.save_handler
03298                 # hasn't already been set to the desired value (that causes errors)
03299                 ini_set( 'session.save_handler', $wgSessionHandler );
03300         }
03301         $httpOnlySafe = wfHttpOnlySafe() && $wgCookieHttpOnly;
03302         wfDebugLog( 'cookie',
03303                 'session_set_cookie_params: "' . implode( '", "',
03304                         array(
03305                                 0,
03306                                 $wgCookiePath,
03307                                 $wgCookieDomain,
03308                                 $wgCookieSecure,
03309                                 $httpOnlySafe ) ) . '"' );
03310         session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe );
03311         session_cache_limiter( 'private, must-revalidate' );
03312         if ( $sessionId ) {
03313                 session_id( $sessionId );
03314         } else {
03315                 wfFixSessionID();
03316         }
03317         wfSuppressWarnings();
03318         session_start();
03319         wfRestoreWarnings();
03320 }
03321 
03328 function wfGetPrecompiledData( $name ) {
03329         global $IP;
03330 
03331         $file = "$IP/serialized/$name";
03332         if ( file_exists( $file ) ) {
03333                 $blob = file_get_contents( $file );
03334                 if ( $blob ) {
03335                         return unserialize( $blob );
03336                 }
03337         }
03338         return false;
03339 }
03340 
03347 function wfMemcKey( /*... */ ) {
03348         global $wgCachePrefix;
03349         $prefix = $wgCachePrefix === false ? wfWikiID() : $wgCachePrefix;
03350         $args = func_get_args();
03351         $key = $prefix . ':' . implode( ':', $args );
03352         $key = str_replace( ' ', '_', $key );
03353         return $key;
03354 }
03355 
03364 function wfForeignMemcKey( $db, $prefix /*, ... */ ) {
03365         $args = array_slice( func_get_args(), 2 );
03366         if ( $prefix ) {
03367                 $key = "$db-$prefix:" . implode( ':', $args );
03368         } else {
03369                 $key = $db . ':' . implode( ':', $args );
03370         }
03371         return $key;
03372 }
03373 
03380 function wfWikiID() {
03381         global $wgDBprefix, $wgDBname;
03382         if ( $wgDBprefix ) {
03383                 return "$wgDBname-$wgDBprefix";
03384         } else {
03385                 return $wgDBname;
03386         }
03387 }
03388 
03396 function wfSplitWikiID( $wiki ) {
03397         $bits = explode( '-', $wiki, 2 );
03398         if ( count( $bits ) < 2 ) {
03399                 $bits[] = '';
03400         }
03401         return $bits;
03402 }
03403 
03426 function &wfGetDB( $db, $groups = array(), $wiki = false ) {
03427         return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
03428 }
03429 
03436 function wfGetLB( $wiki = false ) {
03437         return wfGetLBFactory()->getMainLB( $wiki );
03438 }
03439 
03445 function &wfGetLBFactory() {
03446         return LBFactory::singleton();
03447 }
03448 
03469 function wfFindFile( $title, $options = array() ) {
03470         return RepoGroup::singleton()->findFile( $title, $options );
03471 }
03472 
03480 function wfLocalFile( $title ) {
03481         return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
03482 }
03483 
03488 function wfStreamFile( $fname, $headers = array() ) {
03489         wfDeprecated( __FUNCTION__, '1.19' );
03490         StreamFile::stream( $fname, $headers );
03491 }
03492 
03499 function wfQueriesMustScale() {
03500         global $wgMiserMode;
03501         return $wgMiserMode
03502                 || ( SiteStats::pages() > 100000
03503                 && SiteStats::edits() > 1000000
03504                 && SiteStats::users() > 10000 );
03505 }
03506 
03515 function wfScript( $script = 'index' ) {
03516         global $wgScriptPath, $wgScriptExtension, $wgScript, $wgLoadScript;
03517         if ( $script === 'index' ) {
03518                 return $wgScript;
03519         } else if ( $script === 'load' ) {
03520                 return $wgLoadScript;
03521         } else {
03522                 return "{$wgScriptPath}/{$script}{$wgScriptExtension}";
03523         }
03524 }
03525 
03531 function wfGetScriptUrl() {
03532         if( isset( $_SERVER['SCRIPT_NAME'] ) ) {
03533                 #
03534                 # as it was called, minus the query string.
03535                 #
03536                 # Some sites use Apache rewrite rules to handle subdomains,
03537                 # and have PHP set up in a weird way that causes PHP_SELF
03538                 # to contain the rewritten URL instead of the one that the
03539                 # outside world sees.
03540                 #
03541                 # If in this mode, use SCRIPT_URL instead, which mod_rewrite
03542                 # provides containing the "before" URL.
03543                 return $_SERVER['SCRIPT_NAME'];
03544         } else {
03545                 return $_SERVER['URL'];
03546         }
03547 }
03548 
03556 function wfBoolToStr( $value ) {
03557         return $value ? 'true' : 'false';
03558 }
03559 
03565 function wfGetNull() {
03566         return wfIsWindows()
03567                 ? 'NUL'
03568                 : '/dev/null';
03569 }
03570 
03581 function wfWaitForSlaves( $maxLag = false, $wiki = false ) {
03582         $lb = wfGetLB( $wiki );
03583         // bug 27975 - Don't try to wait for slaves if there are none
03584         // Prevents permission error when getting master position
03585         if ( $lb->getServerCount() > 1 ) {
03586                 $dbw = $lb->getConnection( DB_MASTER );
03587                 $pos = $dbw->getMasterPos();
03588                 $lb->waitForAll( $pos );
03589         }
03590 }
03591 
03596 function wfOut( $s ) {
03597         wfDeprecated( __FUNCTION__, '1.18' );
03598         global $wgCommandLineMode;
03599         if ( $wgCommandLineMode ) {
03600                 echo $s;
03601         } else {
03602                 echo htmlspecialchars( $s );
03603         }
03604         flush();
03605 }
03606 
03613 function wfCountDown( $n ) {
03614         for ( $i = $n; $i >= 0; $i-- ) {
03615                 if ( $i != $n ) {
03616                         echo str_repeat( "\x08", strlen( $i + 1 ) );
03617                 }
03618                 echo $i;
03619                 flush();
03620                 if ( $i ) {
03621                         sleep( 1 );
03622                 }
03623         }
03624         echo "\n";
03625 }
03626 
03636 function wfGenerateToken( $salt = '' ) {
03637         wfDeprecated( __METHOD__, '1.20' );
03638         $salt = serialize( $salt );
03639         return md5( mt_rand( 0, 0x7fffffff ) . $salt );
03640 }
03641 
03650 function wfStripIllegalFilenameChars( $name ) {
03651         global $wgIllegalFileChars;
03652         $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '';
03653         $name = wfBaseName( $name );
03654         $name = preg_replace(
03655                 "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/",
03656                 '-',
03657                 $name
03658         );
03659         return $name;
03660 }
03661 
03667 function wfMemoryLimit() {
03668         global $wgMemoryLimit;
03669         $memlimit = wfShorthandToInteger( ini_get( 'memory_limit' ) );
03670         if( $memlimit != -1 ) {
03671                 $conflimit = wfShorthandToInteger( $wgMemoryLimit );
03672                 if( $conflimit == -1 ) {
03673                         wfDebug( "Removing PHP's memory limit\n" );
03674                         wfSuppressWarnings();
03675                         ini_set( 'memory_limit', $conflimit );
03676                         wfRestoreWarnings();
03677                         return $conflimit;
03678                 } elseif ( $conflimit > $memlimit ) {
03679                         wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
03680                         wfSuppressWarnings();
03681                         ini_set( 'memory_limit', $conflimit );
03682                         wfRestoreWarnings();
03683                         return $conflimit;
03684                 }
03685         }
03686         return $memlimit;
03687 }
03688 
03695 function wfShorthandToInteger( $string = '' ) {
03696         $string = trim( $string );
03697         if( $string === '' ) {
03698                 return -1;
03699         }
03700         $last = $string[strlen( $string ) - 1];
03701         $val = intval( $string );
03702         switch( $last ) {
03703                 case 'g':
03704                 case 'G':
03705                         $val *= 1024;
03706                         // break intentionally missing
03707                 case 'm':
03708                 case 'M':
03709                         $val *= 1024;
03710                         // break intentionally missing
03711                 case 'k':
03712                 case 'K':
03713                         $val *= 1024;
03714         }
03715 
03716         return $val;
03717 }
03718 
03726 function wfBCP47( $code ) {
03727         $codeSegment = explode( '-', $code );
03728         $codeBCP = array();
03729         foreach ( $codeSegment as $segNo => $seg ) {
03730                 if ( count( $codeSegment ) > 0 ) {
03731                         // when previous segment is x, it is a private segment and should be lc
03732                         if( $segNo > 0 && strtolower( $codeSegment[( $segNo - 1 )] ) == 'x' ) {
03733                                 $codeBCP[$segNo] = strtolower( $seg );
03734                         // ISO 3166 country code
03735                         } elseif ( ( strlen( $seg ) == 2 ) && ( $segNo > 0 ) ) {
03736                                 $codeBCP[$segNo] = strtoupper( $seg );
03737                         // ISO 15924 script code
03738                         } elseif ( ( strlen( $seg ) == 4 ) && ( $segNo > 0 ) ) {
03739                                 $codeBCP[$segNo] = ucfirst( strtolower( $seg ) );
03740                         // Use lowercase for other cases
03741                         } else {
03742                                 $codeBCP[$segNo] = strtolower( $seg );
03743                         }
03744                 } else {
03745                 // Use lowercase for single segment
03746                         $codeBCP[$segNo] = strtolower( $seg );
03747                 }
03748         }
03749         $langCode = implode( '-', $codeBCP );
03750         return $langCode;
03751 }
03752 
03759 function wfGetCache( $inputType ) {
03760         return ObjectCache::getInstance( $inputType );
03761 }
03762 
03768 function wfGetMainCache() {
03769         global $wgMainCacheType;
03770         return ObjectCache::getInstance( $wgMainCacheType );
03771 }
03772 
03778 function wfGetMessageCacheStorage() {
03779         global $wgMessageCacheType;
03780         return ObjectCache::getInstance( $wgMessageCacheType );
03781 }
03782 
03788 function wfGetParserCacheStorage() {
03789         global $wgParserCacheType;
03790         return ObjectCache::getInstance( $wgParserCacheType );
03791 }
03792 
03798 function wfGetLangConverterCacheStorage() {
03799         global $wgLanguageConverterCacheType;
03800         return ObjectCache::getInstance( $wgLanguageConverterCacheType );
03801 }
03802 
03810 function wfRunHooks( $event, $args = array() ) {
03811         return Hooks::run( $event, $args );
03812 }
03813 
03828 function wfUnpack( $format, $data, $length=false ) {
03829         if ( $length !== false ) {
03830                 $realLen = strlen( $data );
03831                 if ( $realLen < $length ) {
03832                         throw new MWException( "Tried to use wfUnpack on a "
03833                                 . "string of length $realLen, but needed one "
03834                                 . "of at least length $length."
03835                         );
03836                 }
03837         }
03838 
03839         wfSuppressWarnings();
03840         $result = unpack( $format, $data );
03841         wfRestoreWarnings();
03842 
03843         if ( $result === false ) {
03844                 // If it cannot extract the packed data.
03845                 throw new MWException( "unpack could not unpack binary data" );
03846         }
03847         return $result;
03848 }
03849 
03864 function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
03865         static $badImageCache = null; // based on bad_image_list msg
03866         wfProfileIn( __METHOD__ );
03867 
03868         # Handle redirects
03869         $redirectTitle = RepoGroup::singleton()->checkRedirect( Title::makeTitle( NS_FILE, $name ) );
03870         if( $redirectTitle ) {
03871                 $name = $redirectTitle->getDbKey();
03872         }
03873 
03874         # Run the extension hook
03875         $bad = false;
03876         if( !wfRunHooks( 'BadImage', array( $name, &$bad ) ) ) {
03877                 wfProfileOut( __METHOD__ );
03878                 return $bad;
03879         }
03880 
03881         $cacheable = ( $blacklist === null );
03882         if( $cacheable && $badImageCache !== null ) {
03883                 $badImages = $badImageCache;
03884         } else { // cache miss
03885                 if ( $blacklist === null ) {
03886                         $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list
03887                 }
03888                 # Build the list now
03889                 $badImages = array();
03890                 $lines = explode( "\n", $blacklist );
03891                 foreach( $lines as $line ) {
03892                         # List items only
03893                         if ( substr( $line, 0, 1 ) !== '*' ) {
03894                                 continue;
03895                         }
03896 
03897                         # Find all links
03898                         $m = array();
03899                         if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
03900                                 continue;
03901                         }
03902 
03903                         $exceptions = array();
03904                         $imageDBkey = false;
03905                         foreach ( $m[1] as $i => $titleText ) {
03906                                 $title = Title::newFromText( $titleText );
03907                                 if ( !is_null( $title ) ) {
03908                                         if ( $i == 0 ) {
03909                                                 $imageDBkey = $title->getDBkey();
03910                                         } else {
03911                                                 $exceptions[$title->getPrefixedDBkey()] = true;
03912                                         }
03913                                 }
03914                         }
03915 
03916                         if ( $imageDBkey !== false ) {
03917                                 $badImages[$imageDBkey] = $exceptions;
03918                         }
03919                 }
03920                 if ( $cacheable ) {
03921                         $badImageCache = $badImages;
03922                 }
03923         }
03924 
03925         $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
03926         $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
03927         wfProfileOut( __METHOD__ );
03928         return $bad;
03929 }
Generated on Wed Oct 10 00:01:00 2012 for MediaWiki by  doxygen 1.6.3