MediaWiki
REL1_22
|
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 // gzdecode function only exists in PHP >= 5.4.0 00098 // http://php.net/gzdecode 00099 if ( !function_exists( 'gzdecode' ) ) { 00104 function gzdecode( $data ) { 00105 return gzinflate( substr( $data, 10, -8 ) ); 00106 } 00107 } 00109 00116 function wfArrayDiff2( $a, $b ) { 00117 return array_udiff( $a, $b, 'wfArrayDiff2_cmp' ); 00118 } 00119 00125 function wfArrayDiff2_cmp( $a, $b ) { 00126 if ( is_string( $a ) && is_string( $b ) ) { 00127 return strcmp( $a, $b ); 00128 } elseif ( count( $a ) !== count( $b ) ) { 00129 return count( $a ) < count( $b ) ? -1 : 1; 00130 } else { 00131 reset( $a ); 00132 reset( $b ); 00133 while ( ( list( , $valueA ) = each( $a ) ) && ( list( , $valueB ) = each( $b ) ) ) { 00134 $cmp = strcmp( $valueA, $valueB ); 00135 if ( $cmp !== 0 ) { 00136 return $cmp; 00137 } 00138 } 00139 return 0; 00140 } 00141 } 00142 00153 function wfArrayLookup( $a, $b ) { 00154 wfDeprecated( __FUNCTION__, '1.22' ); 00155 return array_flip( array_intersect( array_flip( $a ), array_keys( $b ) ) ); 00156 } 00157 00167 function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) { 00168 if ( is_null( $changed ) ) { 00169 throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' ); 00170 } 00171 if ( $default[$key] !== $value ) { 00172 $changed[$key] = $value; 00173 } 00174 } 00175 00185 function wfArrayMerge( $array1/* ... */ ) { 00186 wfDeprecated( __FUNCTION__, '1.22' ); 00187 $args = func_get_args(); 00188 $args = array_reverse( $args, true ); 00189 $out = array(); 00190 foreach ( $args as $arg ) { 00191 $out += $arg; 00192 } 00193 return $out; 00194 } 00195 00214 function wfMergeErrorArrays( /*...*/ ) { 00215 $args = func_get_args(); 00216 $out = array(); 00217 foreach ( $args as $errors ) { 00218 foreach ( $errors as $params ) { 00219 # @todo FIXME: Sometimes get nested arrays for $params, 00220 # which leads to E_NOTICEs 00221 $spec = implode( "\t", $params ); 00222 $out[$spec] = $params; 00223 } 00224 } 00225 return array_values( $out ); 00226 } 00227 00236 function wfArrayInsertAfter( array $array, array $insert, $after ) { 00237 // Find the offset of the element to insert after. 00238 $keys = array_keys( $array ); 00239 $offsetByKey = array_flip( $keys ); 00240 00241 $offset = $offsetByKey[$after]; 00242 00243 // Insert at the specified offset 00244 $before = array_slice( $array, 0, $offset + 1, true ); 00245 $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true ); 00246 00247 $output = $before + $insert + $after; 00248 00249 return $output; 00250 } 00251 00259 function wfObjectToArray( $objOrArray, $recursive = true ) { 00260 $array = array(); 00261 if ( is_object( $objOrArray ) ) { 00262 $objOrArray = get_object_vars( $objOrArray ); 00263 } 00264 foreach ( $objOrArray as $key => $value ) { 00265 if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) { 00266 $value = wfObjectToArray( $value ); 00267 } 00268 00269 $array[$key] = $value; 00270 } 00271 00272 return $array; 00273 } 00274 00282 function wfRandom() { 00283 # The maximum random value is "only" 2^31-1, so get two random 00284 # values to reduce the chance of dupes 00285 $max = mt_getrandmax() + 1; 00286 $rand = number_format( ( mt_rand() * $max + mt_rand() ) 00287 / $max / $max, 12, '.', '' ); 00288 return $rand; 00289 } 00290 00301 function wfRandomString( $length = 32 ) { 00302 $str = ''; 00303 for ( $n = 0; $n < $length; $n += 7 ) { 00304 $str .= sprintf( '%07x', mt_rand() & 0xfffffff ); 00305 } 00306 return substr( $str, 0, $length ); 00307 } 00308 00331 function wfUrlencode( $s ) { 00332 static $needle; 00333 if ( is_null( $s ) ) { 00334 $needle = null; 00335 return ''; 00336 } 00337 00338 if ( is_null( $needle ) ) { 00339 $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' ); 00340 if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) || ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false ) ) { 00341 $needle[] = '%3A'; 00342 } 00343 } 00344 00345 $s = urlencode( $s ); 00346 $s = str_ireplace( 00347 $needle, 00348 array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ), 00349 $s 00350 ); 00351 00352 return $s; 00353 } 00354 00365 function wfArrayToCgi( $array1, $array2 = null, $prefix = '' ) { 00366 if ( !is_null( $array2 ) ) { 00367 $array1 = $array1 + $array2; 00368 } 00369 00370 $cgi = ''; 00371 foreach ( $array1 as $key => $value ) { 00372 if ( !is_null( $value ) && $value !== false ) { 00373 if ( $cgi != '' ) { 00374 $cgi .= '&'; 00375 } 00376 if ( $prefix !== '' ) { 00377 $key = $prefix . "[$key]"; 00378 } 00379 if ( is_array( $value ) ) { 00380 $firstTime = true; 00381 foreach ( $value as $k => $v ) { 00382 $cgi .= $firstTime ? '' : '&'; 00383 if ( is_array( $v ) ) { 00384 $cgi .= wfArrayToCgi( $v, null, $key . "[$k]" ); 00385 } else { 00386 $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v ); 00387 } 00388 $firstTime = false; 00389 } 00390 } else { 00391 if ( is_object( $value ) ) { 00392 $value = $value->__toString(); 00393 } 00394 $cgi .= urlencode( $key ) . '=' . urlencode( $value ); 00395 } 00396 } 00397 } 00398 return $cgi; 00399 } 00400 00410 function wfCgiToArray( $query ) { 00411 if ( isset( $query[0] ) && $query[0] == '?' ) { 00412 $query = substr( $query, 1 ); 00413 } 00414 $bits = explode( '&', $query ); 00415 $ret = array(); 00416 foreach ( $bits as $bit ) { 00417 if ( $bit === '' ) { 00418 continue; 00419 } 00420 if ( strpos( $bit, '=' ) === false ) { 00421 // Pieces like &qwerty become 'qwerty' => '' (at least this is what php does) 00422 $key = $bit; 00423 $value = ''; 00424 } else { 00425 list( $key, $value ) = explode( '=', $bit ); 00426 } 00427 $key = urldecode( $key ); 00428 $value = urldecode( $value ); 00429 if ( strpos( $key, '[' ) !== false ) { 00430 $keys = array_reverse( explode( '[', $key ) ); 00431 $key = array_pop( $keys ); 00432 $temp = $value; 00433 foreach ( $keys as $k ) { 00434 $k = substr( $k, 0, -1 ); 00435 $temp = array( $k => $temp ); 00436 } 00437 if ( isset( $ret[$key] ) ) { 00438 $ret[$key] = array_merge( $ret[$key], $temp ); 00439 } else { 00440 $ret[$key] = $temp; 00441 } 00442 } else { 00443 $ret[$key] = $value; 00444 } 00445 } 00446 return $ret; 00447 } 00448 00457 function wfAppendQuery( $url, $query ) { 00458 if ( is_array( $query ) ) { 00459 $query = wfArrayToCgi( $query ); 00460 } 00461 if ( $query != '' ) { 00462 if ( false === strpos( $url, '?' ) ) { 00463 $url .= '?'; 00464 } else { 00465 $url .= '&'; 00466 } 00467 $url .= $query; 00468 } 00469 return $url; 00470 } 00471 00494 function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) { 00495 global $wgServer, $wgCanonicalServer, $wgInternalServer; 00496 $serverUrl = $wgServer; 00497 if ( $defaultProto === PROTO_CANONICAL ) { 00498 $serverUrl = $wgCanonicalServer; 00499 } 00500 // Make $wgInternalServer fall back to $wgServer if not set 00501 if ( $defaultProto === PROTO_INTERNAL && $wgInternalServer !== false ) { 00502 $serverUrl = $wgInternalServer; 00503 } 00504 if ( $defaultProto === PROTO_CURRENT ) { 00505 $defaultProto = WebRequest::detectProtocol() . '://'; 00506 } 00507 00508 // Analyze $serverUrl to obtain its protocol 00509 $bits = wfParseUrl( $serverUrl ); 00510 $serverHasProto = $bits && $bits['scheme'] != ''; 00511 00512 if ( $defaultProto === PROTO_CANONICAL || $defaultProto === PROTO_INTERNAL ) { 00513 if ( $serverHasProto ) { 00514 $defaultProto = $bits['scheme'] . '://'; 00515 } else { 00516 // $wgCanonicalServer or $wgInternalServer doesn't have a protocol. This really isn't supposed to happen 00517 // Fall back to HTTP in this ridiculous case 00518 $defaultProto = PROTO_HTTP; 00519 } 00520 } 00521 00522 $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 ); 00523 00524 if ( substr( $url, 0, 2 ) == '//' ) { 00525 $url = $defaultProtoWithoutSlashes . $url; 00526 } elseif ( substr( $url, 0, 1 ) == '/' ) { 00527 // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone 00528 $url = ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $serverUrl . $url; 00529 } 00530 00531 $bits = wfParseUrl( $url ); 00532 if ( $bits && isset( $bits['path'] ) ) { 00533 $bits['path'] = wfRemoveDotSegments( $bits['path'] ); 00534 return wfAssembleUrl( $bits ); 00535 } elseif ( $bits ) { 00536 # No path to expand 00537 return $url; 00538 } elseif ( substr( $url, 0, 1 ) != '/' ) { 00539 # URL is a relative path 00540 return wfRemoveDotSegments( $url ); 00541 } 00542 00543 # Expanded URL is not valid. 00544 return false; 00545 } 00546 00560 function wfAssembleUrl( $urlParts ) { 00561 $result = ''; 00562 00563 if ( isset( $urlParts['delimiter'] ) ) { 00564 if ( isset( $urlParts['scheme'] ) ) { 00565 $result .= $urlParts['scheme']; 00566 } 00567 00568 $result .= $urlParts['delimiter']; 00569 } 00570 00571 if ( isset( $urlParts['host'] ) ) { 00572 if ( isset( $urlParts['user'] ) ) { 00573 $result .= $urlParts['user']; 00574 if ( isset( $urlParts['pass'] ) ) { 00575 $result .= ':' . $urlParts['pass']; 00576 } 00577 $result .= '@'; 00578 } 00579 00580 $result .= $urlParts['host']; 00581 00582 if ( isset( $urlParts['port'] ) ) { 00583 $result .= ':' . $urlParts['port']; 00584 } 00585 } 00586 00587 if ( isset( $urlParts['path'] ) ) { 00588 $result .= $urlParts['path']; 00589 } 00590 00591 if ( isset( $urlParts['query'] ) ) { 00592 $result .= '?' . $urlParts['query']; 00593 } 00594 00595 if ( isset( $urlParts['fragment'] ) ) { 00596 $result .= '#' . $urlParts['fragment']; 00597 } 00598 00599 return $result; 00600 } 00601 00612 function wfRemoveDotSegments( $urlPath ) { 00613 $output = ''; 00614 $inputOffset = 0; 00615 $inputLength = strlen( $urlPath ); 00616 00617 while ( $inputOffset < $inputLength ) { 00618 $prefixLengthOne = substr( $urlPath, $inputOffset, 1 ); 00619 $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 ); 00620 $prefixLengthThree = substr( $urlPath, $inputOffset, 3 ); 00621 $prefixLengthFour = substr( $urlPath, $inputOffset, 4 ); 00622 $trimOutput = false; 00623 00624 if ( $prefixLengthTwo == './' ) { 00625 # Step A, remove leading "./" 00626 $inputOffset += 2; 00627 } elseif ( $prefixLengthThree == '../' ) { 00628 # Step A, remove leading "../" 00629 $inputOffset += 3; 00630 } elseif ( ( $prefixLengthTwo == '/.' ) && ( $inputOffset + 2 == $inputLength ) ) { 00631 # Step B, replace leading "/.$" with "/" 00632 $inputOffset += 1; 00633 $urlPath[$inputOffset] = '/'; 00634 } elseif ( $prefixLengthThree == '/./' ) { 00635 # Step B, replace leading "/./" with "/" 00636 $inputOffset += 2; 00637 } elseif ( $prefixLengthThree == '/..' && ( $inputOffset + 3 == $inputLength ) ) { 00638 # Step C, replace leading "/..$" with "/" and 00639 # remove last path component in output 00640 $inputOffset += 2; 00641 $urlPath[$inputOffset] = '/'; 00642 $trimOutput = true; 00643 } elseif ( $prefixLengthFour == '/../' ) { 00644 # Step C, replace leading "/../" with "/" and 00645 # remove last path component in output 00646 $inputOffset += 3; 00647 $trimOutput = true; 00648 } elseif ( ( $prefixLengthOne == '.' ) && ( $inputOffset + 1 == $inputLength ) ) { 00649 # Step D, remove "^.$" 00650 $inputOffset += 1; 00651 } elseif ( ( $prefixLengthTwo == '..' ) && ( $inputOffset + 2 == $inputLength ) ) { 00652 # Step D, remove "^..$" 00653 $inputOffset += 2; 00654 } else { 00655 # Step E, move leading path segment to output 00656 if ( $prefixLengthOne == '/' ) { 00657 $slashPos = strpos( $urlPath, '/', $inputOffset + 1 ); 00658 } else { 00659 $slashPos = strpos( $urlPath, '/', $inputOffset ); 00660 } 00661 if ( $slashPos === false ) { 00662 $output .= substr( $urlPath, $inputOffset ); 00663 $inputOffset = $inputLength; 00664 } else { 00665 $output .= substr( $urlPath, $inputOffset, $slashPos - $inputOffset ); 00666 $inputOffset += $slashPos - $inputOffset; 00667 } 00668 } 00669 00670 if ( $trimOutput ) { 00671 $slashPos = strrpos( $output, '/' ); 00672 if ( $slashPos === false ) { 00673 $output = ''; 00674 } else { 00675 $output = substr( $output, 0, $slashPos ); 00676 } 00677 } 00678 } 00679 00680 return $output; 00681 } 00682 00690 function wfUrlProtocols( $includeProtocolRelative = true ) { 00691 global $wgUrlProtocols; 00692 00693 // Cache return values separately based on $includeProtocolRelative 00694 static $withProtRel = null, $withoutProtRel = null; 00695 $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel; 00696 if ( !is_null( $cachedValue ) ) { 00697 return $cachedValue; 00698 } 00699 00700 // Support old-style $wgUrlProtocols strings, for backwards compatibility 00701 // with LocalSettings files from 1.5 00702 if ( is_array( $wgUrlProtocols ) ) { 00703 $protocols = array(); 00704 foreach ( $wgUrlProtocols as $protocol ) { 00705 // Filter out '//' if !$includeProtocolRelative 00706 if ( $includeProtocolRelative || $protocol !== '//' ) { 00707 $protocols[] = preg_quote( $protocol, '/' ); 00708 } 00709 } 00710 00711 $retval = implode( '|', $protocols ); 00712 } else { 00713 // Ignore $includeProtocolRelative in this case 00714 // This case exists for pre-1.6 compatibility, and we can safely assume 00715 // that '//' won't appear in a pre-1.6 config because protocol-relative 00716 // URLs weren't supported until 1.18 00717 $retval = $wgUrlProtocols; 00718 } 00719 00720 // Cache return value 00721 if ( $includeProtocolRelative ) { 00722 $withProtRel = $retval; 00723 } else { 00724 $withoutProtRel = $retval; 00725 } 00726 return $retval; 00727 } 00728 00735 function wfUrlProtocolsWithoutProtRel() { 00736 return wfUrlProtocols( false ); 00737 } 00738 00749 function wfParseUrl( $url ) { 00750 global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php 00751 00752 // Protocol-relative URLs are handled really badly by parse_url(). It's so bad that the easiest 00753 // way to handle them is to just prepend 'http:' and strip the protocol out later 00754 $wasRelative = substr( $url, 0, 2 ) == '//'; 00755 if ( $wasRelative ) { 00756 $url = "http:$url"; 00757 } 00758 wfSuppressWarnings(); 00759 $bits = parse_url( $url ); 00760 wfRestoreWarnings(); 00761 // parse_url() returns an array without scheme for some invalid URLs, e.g. 00762 // parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' ) 00763 if ( !$bits || !isset( $bits['scheme'] ) ) { 00764 return false; 00765 } 00766 00767 // parse_url() incorrectly handles schemes case-sensitively. Convert it to lowercase. 00768 $bits['scheme'] = strtolower( $bits['scheme'] ); 00769 00770 // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it 00771 if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) { 00772 $bits['delimiter'] = '://'; 00773 } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) { 00774 $bits['delimiter'] = ':'; 00775 // parse_url detects for news: and mailto: the host part of an url as path 00776 // We have to correct this wrong detection 00777 if ( isset( $bits['path'] ) ) { 00778 $bits['host'] = $bits['path']; 00779 $bits['path'] = ''; 00780 } 00781 } else { 00782 return false; 00783 } 00784 00785 /* Provide an empty host for eg. file:/// urls (see bug 28627) */ 00786 if ( !isset( $bits['host'] ) ) { 00787 $bits['host'] = ''; 00788 00789 // bug 45069 00790 if ( isset( $bits['path'] ) ) { 00791 /* parse_url loses the third / for file:///c:/ urls (but not on variants) */ 00792 if ( substr( $bits['path'], 0, 1 ) !== '/' ) { 00793 $bits['path'] = '/' . $bits['path']; 00794 } 00795 } else { 00796 $bits['path'] = ''; 00797 } 00798 } 00799 00800 // If the URL was protocol-relative, fix scheme and delimiter 00801 if ( $wasRelative ) { 00802 $bits['scheme'] = ''; 00803 $bits['delimiter'] = '//'; 00804 } 00805 return $bits; 00806 } 00807 00818 function wfExpandIRI( $url ) { 00819 return preg_replace_callback( '/((?:%[89A-F][0-9A-F])+)/i', 'wfExpandIRI_callback', wfExpandUrl( $url ) ); 00820 } 00821 00827 function wfExpandIRI_callback( $matches ) { 00828 return urldecode( $matches[1] ); 00829 } 00830 00837 function wfMakeUrlIndexes( $url ) { 00838 $bits = wfParseUrl( $url ); 00839 00840 // Reverse the labels in the hostname, convert to lower case 00841 // For emails reverse domainpart only 00842 if ( $bits['scheme'] == 'mailto' ) { 00843 $mailparts = explode( '@', $bits['host'], 2 ); 00844 if ( count( $mailparts ) === 2 ) { 00845 $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) ); 00846 } else { 00847 // No domain specified, don't mangle it 00848 $domainpart = ''; 00849 } 00850 $reversedHost = $domainpart . '@' . $mailparts[0]; 00851 } else { 00852 $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) ); 00853 } 00854 // Add an extra dot to the end 00855 // Why? Is it in wrong place in mailto links? 00856 if ( substr( $reversedHost, -1, 1 ) !== '.' ) { 00857 $reversedHost .= '.'; 00858 } 00859 // Reconstruct the pseudo-URL 00860 $prot = $bits['scheme']; 00861 $index = $prot . $bits['delimiter'] . $reversedHost; 00862 // Leave out user and password. Add the port, path, query and fragment 00863 if ( isset( $bits['port'] ) ) { 00864 $index .= ':' . $bits['port']; 00865 } 00866 if ( isset( $bits['path'] ) ) { 00867 $index .= $bits['path']; 00868 } else { 00869 $index .= '/'; 00870 } 00871 if ( isset( $bits['query'] ) ) { 00872 $index .= '?' . $bits['query']; 00873 } 00874 if ( isset( $bits['fragment'] ) ) { 00875 $index .= '#' . $bits['fragment']; 00876 } 00877 00878 if ( $prot == '' ) { 00879 return array( "http:$index", "https:$index" ); 00880 } else { 00881 return array( $index ); 00882 } 00883 } 00884 00891 function wfMatchesDomainList( $url, $domains ) { 00892 $bits = wfParseUrl( $url ); 00893 if ( is_array( $bits ) && isset( $bits['host'] ) ) { 00894 $host = '.' . $bits['host']; 00895 foreach ( (array)$domains as $domain ) { 00896 $domain = '.' . $domain; 00897 if ( substr( $host, -strlen( $domain ) ) === $domain ) { 00898 return true; 00899 } 00900 } 00901 } 00902 return false; 00903 } 00904 00918 function wfDebug( $text, $logonly = false ) { 00919 global $wgDebugLogFile, $wgProfileOnly, $wgDebugRawPage, $wgDebugLogPrefix; 00920 00921 if ( !$wgDebugRawPage && wfIsDebugRawPage() ) { 00922 return; 00923 } 00924 00925 $timer = wfDebugTimer(); 00926 if ( $timer !== '' ) { 00927 $text = preg_replace( '/[^\n]/', $timer . '\0', $text, 1 ); 00928 } 00929 00930 if ( !$logonly ) { 00931 MWDebug::debugMsg( $text ); 00932 } 00933 00934 if ( $wgDebugLogFile != '' && !$wgProfileOnly ) { 00935 # Strip unprintables; they can switch terminal modes when binary data 00936 # gets dumped, which is pretty annoying. 00937 $text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $text ); 00938 $text = $wgDebugLogPrefix . $text; 00939 wfErrorLog( $text, $wgDebugLogFile ); 00940 } 00941 } 00942 00947 function wfIsDebugRawPage() { 00948 static $cache; 00949 if ( $cache !== null ) { 00950 return $cache; 00951 } 00952 # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet 00953 if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' ) 00954 || ( 00955 isset( $_SERVER['SCRIPT_NAME'] ) 00956 && substr( $_SERVER['SCRIPT_NAME'], -8 ) == 'load.php' 00957 ) ) 00958 { 00959 $cache = true; 00960 } else { 00961 $cache = false; 00962 } 00963 return $cache; 00964 } 00965 00971 function wfDebugTimer() { 00972 global $wgDebugTimestamps, $wgRequestTime; 00973 00974 if ( !$wgDebugTimestamps ) { 00975 return ''; 00976 } 00977 00978 $prefix = sprintf( "%6.4f", microtime( true ) - $wgRequestTime ); 00979 $mem = sprintf( "%5.1fM", ( memory_get_usage( true ) / ( 1024 * 1024 ) ) ); 00980 return "$prefix $mem "; 00981 } 00982 00988 function wfDebugMem( $exact = false ) { 00989 $mem = memory_get_usage(); 00990 if ( !$exact ) { 00991 $mem = floor( $mem / 1024 ) . ' kilobytes'; 00992 } else { 00993 $mem .= ' bytes'; 00994 } 00995 wfDebug( "Memory usage: $mem\n" ); 00996 } 00997 01007 function wfDebugLog( $logGroup, $text, $public = true ) { 01008 global $wgDebugLogGroups; 01009 $text = trim( $text ) . "\n"; 01010 if ( isset( $wgDebugLogGroups[$logGroup] ) ) { 01011 $time = wfTimestamp( TS_DB ); 01012 $wiki = wfWikiID(); 01013 $host = wfHostname(); 01014 wfErrorLog( "$time $host $wiki: $text", $wgDebugLogGroups[$logGroup] ); 01015 } elseif ( $public === true ) { 01016 wfDebug( "[$logGroup] $text", false ); 01017 } 01018 } 01019 01025 function wfLogDBError( $text ) { 01026 global $wgDBerrorLog, $wgDBerrorLogTZ; 01027 static $logDBErrorTimeZoneObject = null; 01028 01029 if ( $wgDBerrorLog ) { 01030 $host = wfHostname(); 01031 $wiki = wfWikiID(); 01032 01033 if ( $wgDBerrorLogTZ && !$logDBErrorTimeZoneObject ) { 01034 $logDBErrorTimeZoneObject = new DateTimeZone( $wgDBerrorLogTZ ); 01035 } 01036 01037 // Workaround for https://bugs.php.net/bug.php?id=52063 01038 // Can be removed when min PHP > 5.3.2 01039 if ( $logDBErrorTimeZoneObject === null ) { 01040 $d = date_create( "now" ); 01041 } else { 01042 $d = date_create( "now", $logDBErrorTimeZoneObject ); 01043 } 01044 01045 $date = $d->format( 'D M j G:i:s T Y' ); 01046 01047 $text = "$date\t$host\t$wiki\t$text"; 01048 wfErrorLog( $text, $wgDBerrorLog ); 01049 } 01050 } 01051 01064 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) { 01065 MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 ); 01066 } 01067 01078 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) { 01079 MWDebug::warning( $msg, $callerOffset + 1, $level, 'auto' ); 01080 } 01081 01091 function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) { 01092 MWDebug::warning( $msg, $callerOffset + 1, $level, 'production' ); 01093 } 01094 01105 function wfErrorLog( $text, $file ) { 01106 if ( substr( $file, 0, 4 ) == 'udp:' ) { 01107 # Needs the sockets extension 01108 if ( preg_match( '!^(tcp|udp):(?://)?\[([0-9a-fA-F:]+)\]:(\d+)(?:/(.*))?$!', $file, $m ) ) { 01109 // IPv6 bracketed host 01110 $host = $m[2]; 01111 $port = intval( $m[3] ); 01112 $prefix = isset( $m[4] ) ? $m[4] : false; 01113 $domain = AF_INET6; 01114 } elseif ( preg_match( '!^(tcp|udp):(?://)?([a-zA-Z0-9.-]+):(\d+)(?:/(.*))?$!', $file, $m ) ) { 01115 $host = $m[2]; 01116 if ( !IP::isIPv4( $host ) ) { 01117 $host = gethostbyname( $host ); 01118 } 01119 $port = intval( $m[3] ); 01120 $prefix = isset( $m[4] ) ? $m[4] : false; 01121 $domain = AF_INET; 01122 } else { 01123 throw new MWException( __METHOD__ . ': Invalid UDP specification' ); 01124 } 01125 01126 // Clean it up for the multiplexer 01127 if ( strval( $prefix ) !== '' ) { 01128 $text = preg_replace( '/^/m', $prefix . ' ', $text ); 01129 01130 // Limit to 64KB 01131 if ( strlen( $text ) > 65506 ) { 01132 $text = substr( $text, 0, 65506 ); 01133 } 01134 01135 if ( substr( $text, -1 ) != "\n" ) { 01136 $text .= "\n"; 01137 } 01138 } elseif ( strlen( $text ) > 65507 ) { 01139 $text = substr( $text, 0, 65507 ); 01140 } 01141 01142 $sock = socket_create( $domain, SOCK_DGRAM, SOL_UDP ); 01143 if ( !$sock ) { 01144 return; 01145 } 01146 01147 socket_sendto( $sock, $text, strlen( $text ), 0, $host, $port ); 01148 socket_close( $sock ); 01149 } else { 01150 wfSuppressWarnings(); 01151 $exists = file_exists( $file ); 01152 $size = $exists ? filesize( $file ) : false; 01153 if ( !$exists || ( $size !== false && $size + strlen( $text ) < 0x7fffffff ) ) { 01154 file_put_contents( $file, $text, FILE_APPEND ); 01155 } 01156 wfRestoreWarnings(); 01157 } 01158 } 01159 01163 function wfLogProfilingData() { 01164 global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; 01165 global $wgProfileLimit, $wgUser; 01166 01167 StatCounter::singleton()->flush(); 01168 01169 $profiler = Profiler::instance(); 01170 01171 # Profiling must actually be enabled... 01172 if ( $profiler->isStub() ) { 01173 return; 01174 } 01175 01176 // Get total page request time and only show pages that longer than 01177 // $wgProfileLimit time (default is 0) 01178 $elapsed = microtime( true ) - $wgRequestTime; 01179 if ( $elapsed <= $wgProfileLimit ) { 01180 return; 01181 } 01182 01183 $profiler->logData(); 01184 01185 // Check whether this should be logged in the debug file. 01186 if ( $wgDebugLogFile == '' || ( !$wgDebugRawPage && wfIsDebugRawPage() ) ) { 01187 return; 01188 } 01189 01190 $forward = ''; 01191 if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { 01192 $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; 01193 } 01194 if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { 01195 $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP']; 01196 } 01197 if ( !empty( $_SERVER['HTTP_FROM'] ) ) { 01198 $forward .= ' from ' . $_SERVER['HTTP_FROM']; 01199 } 01200 if ( $forward ) { 01201 $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; 01202 } 01203 // Don't load $wgUser at this late stage just for statistics purposes 01204 // @todo FIXME: We can detect some anons even if it is not loaded. See User::getId() 01205 if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) { 01206 $forward .= ' anon'; 01207 } 01208 01209 // Command line script uses a FauxRequest object which does not have 01210 // any knowledge about an URL and throw an exception instead. 01211 try { 01212 $requestUrl = $wgRequest->getRequestURL(); 01213 } catch ( MWException $e ) { 01214 $requestUrl = 'n/a'; 01215 } 01216 01217 $log = sprintf( "%s\t%04.3f\t%s\n", 01218 gmdate( 'YmdHis' ), $elapsed, 01219 urldecode( $requestUrl . $forward ) ); 01220 01221 wfErrorLog( $log . $profiler->getOutput(), $wgDebugLogFile ); 01222 } 01223 01231 function wfIncrStats( $key, $count = 1 ) { 01232 StatCounter::singleton()->incr( $key, $count ); 01233 } 01234 01240 function wfReadOnly() { 01241 return wfReadOnlyReason() !== false; 01242 } 01243 01249 function wfReadOnlyReason() { 01250 global $wgReadOnly, $wgReadOnlyFile; 01251 01252 if ( $wgReadOnly === null ) { 01253 // Set $wgReadOnly for faster access next time 01254 if ( is_file( $wgReadOnlyFile ) && filesize( $wgReadOnlyFile ) > 0 ) { 01255 $wgReadOnly = file_get_contents( $wgReadOnlyFile ); 01256 } else { 01257 $wgReadOnly = false; 01258 } 01259 } 01260 01261 return $wgReadOnly; 01262 } 01263 01279 function wfGetLangObj( $langcode = false ) { 01280 # Identify which language to get or create a language object for. 01281 # Using is_object here due to Stub objects. 01282 if ( is_object( $langcode ) ) { 01283 # Great, we already have the object (hopefully)! 01284 return $langcode; 01285 } 01286 01287 global $wgContLang, $wgLanguageCode; 01288 if ( $langcode === true || $langcode === $wgLanguageCode ) { 01289 # $langcode is the language code of the wikis content language object. 01290 # or it is a boolean and value is true 01291 return $wgContLang; 01292 } 01293 01294 global $wgLang; 01295 if ( $langcode === false || $langcode === $wgLang->getCode() ) { 01296 # $langcode is the language code of user language object. 01297 # or it was a boolean and value is false 01298 return $wgLang; 01299 } 01300 01301 $validCodes = array_keys( Language::fetchLanguageNames() ); 01302 if ( in_array( $langcode, $validCodes ) ) { 01303 # $langcode corresponds to a valid language. 01304 return Language::factory( $langcode ); 01305 } 01306 01307 # $langcode is a string, but not a valid language code; use content language. 01308 wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" ); 01309 return $wgContLang; 01310 } 01311 01319 function wfUILang() { 01320 wfDeprecated( __METHOD__, '1.18' ); 01321 global $wgLang; 01322 return $wgLang; 01323 } 01324 01338 function wfMessage( $key /*...*/) { 01339 $params = func_get_args(); 01340 array_shift( $params ); 01341 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 01342 $params = $params[0]; 01343 } 01344 return new Message( $key, $params ); 01345 } 01346 01355 function wfMessageFallback( /*...*/ ) { 01356 $args = func_get_args(); 01357 return call_user_func_array( 'Message::newFallbackSequence', $args ); 01358 } 01359 01379 function wfMsg( $key ) { 01380 wfDeprecated( __METHOD__, '1.21' ); 01381 01382 $args = func_get_args(); 01383 array_shift( $args ); 01384 return wfMsgReal( $key, $args ); 01385 } 01386 01395 function wfMsgNoTrans( $key ) { 01396 wfDeprecated( __METHOD__, '1.21' ); 01397 01398 $args = func_get_args(); 01399 array_shift( $args ); 01400 return wfMsgReal( $key, $args, true, false, false ); 01401 } 01402 01428 function wfMsgForContent( $key ) { 01429 wfDeprecated( __METHOD__, '1.21' ); 01430 01431 global $wgForceUIMsgAsContentMsg; 01432 $args = func_get_args(); 01433 array_shift( $args ); 01434 $forcontent = true; 01435 if ( is_array( $wgForceUIMsgAsContentMsg ) && 01436 in_array( $key, $wgForceUIMsgAsContentMsg ) ) 01437 { 01438 $forcontent = false; 01439 } 01440 return wfMsgReal( $key, $args, true, $forcontent ); 01441 } 01442 01451 function wfMsgForContentNoTrans( $key ) { 01452 wfDeprecated( __METHOD__, '1.21' ); 01453 01454 global $wgForceUIMsgAsContentMsg; 01455 $args = func_get_args(); 01456 array_shift( $args ); 01457 $forcontent = true; 01458 if ( is_array( $wgForceUIMsgAsContentMsg ) && 01459 in_array( $key, $wgForceUIMsgAsContentMsg ) ) 01460 { 01461 $forcontent = false; 01462 } 01463 return wfMsgReal( $key, $args, true, $forcontent, false ); 01464 } 01465 01478 function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform = true ) { 01479 wfDeprecated( __METHOD__, '1.21' ); 01480 01481 wfProfileIn( __METHOD__ ); 01482 $message = wfMsgGetKey( $key, $useDB, $forContent, $transform ); 01483 $message = wfMsgReplaceArgs( $message, $args ); 01484 wfProfileOut( __METHOD__ ); 01485 return $message; 01486 } 01487 01500 function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true ) { 01501 wfDeprecated( __METHOD__, '1.21' ); 01502 01503 wfRunHooks( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) ); 01504 01505 $cache = MessageCache::singleton(); 01506 $message = $cache->get( $key, $useDB, $langCode ); 01507 if ( $message === false ) { 01508 $message = '<' . htmlspecialchars( $key ) . '>'; 01509 } elseif ( $transform ) { 01510 $message = $cache->transform( $message ); 01511 } 01512 return $message; 01513 } 01514 01523 function wfMsgReplaceArgs( $message, $args ) { 01524 # Fix windows line-endings 01525 # Some messages are split with explode("\n", $msg) 01526 $message = str_replace( "\r", '', $message ); 01527 01528 // Replace arguments 01529 if ( count( $args ) ) { 01530 if ( is_array( $args[0] ) ) { 01531 $args = array_values( $args[0] ); 01532 } 01533 $replacementKeys = array(); 01534 foreach ( $args as $n => $param ) { 01535 $replacementKeys['$' . ( $n + 1 )] = $param; 01536 } 01537 $message = strtr( $message, $replacementKeys ); 01538 } 01539 01540 return $message; 01541 } 01542 01556 function wfMsgHtml( $key ) { 01557 wfDeprecated( __METHOD__, '1.21' ); 01558 01559 $args = func_get_args(); 01560 array_shift( $args ); 01561 return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key ) ), $args ); 01562 } 01563 01577 function wfMsgWikiHtml( $key ) { 01578 wfDeprecated( __METHOD__, '1.21' ); 01579 01580 $args = func_get_args(); 01581 array_shift( $args ); 01582 return wfMsgReplaceArgs( 01583 MessageCache::singleton()->parse( wfMsgGetKey( $key ), null, 01584 /* can't be set to false */ true, /* interface */ true )->getText(), 01585 $args ); 01586 } 01587 01610 function wfMsgExt( $key, $options ) { 01611 wfDeprecated( __METHOD__, '1.21' ); 01612 01613 $args = func_get_args(); 01614 array_shift( $args ); 01615 array_shift( $args ); 01616 $options = (array)$options; 01617 01618 foreach ( $options as $arrayKey => $option ) { 01619 if ( !preg_match( '/^[0-9]+|language$/', $arrayKey ) ) { 01620 # An unknown index, neither numeric nor "language" 01621 wfWarn( "wfMsgExt called with incorrect parameter key $arrayKey", 1, E_USER_WARNING ); 01622 } elseif ( preg_match( '/^[0-9]+$/', $arrayKey ) && !in_array( $option, 01623 array( 'parse', 'parseinline', 'escape', 'escapenoentities', 01624 'replaceafter', 'parsemag', 'content' ) ) ) { 01625 # A numeric index with unknown value 01626 wfWarn( "wfMsgExt called with incorrect parameter $option", 1, E_USER_WARNING ); 01627 } 01628 } 01629 01630 if ( in_array( 'content', $options, true ) ) { 01631 $forContent = true; 01632 $langCode = true; 01633 $langCodeObj = null; 01634 } elseif ( array_key_exists( 'language', $options ) ) { 01635 $forContent = false; 01636 $langCode = wfGetLangObj( $options['language'] ); 01637 $langCodeObj = $langCode; 01638 } else { 01639 $forContent = false; 01640 $langCode = false; 01641 $langCodeObj = null; 01642 } 01643 01644 $string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false ); 01645 01646 if ( !in_array( 'replaceafter', $options, true ) ) { 01647 $string = wfMsgReplaceArgs( $string, $args ); 01648 } 01649 01650 $messageCache = MessageCache::singleton(); 01651 $parseInline = in_array( 'parseinline', $options, true ); 01652 if ( in_array( 'parse', $options, true ) || $parseInline ) { 01653 $string = $messageCache->parse( $string, null, true, !$forContent, $langCodeObj ); 01654 if ( $string instanceof ParserOutput ) { 01655 $string = $string->getText(); 01656 } 01657 01658 if ( $parseInline ) { 01659 $m = array(); 01660 if ( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $string, $m ) ) { 01661 $string = $m[1]; 01662 } 01663 } 01664 } elseif ( in_array( 'parsemag', $options, true ) ) { 01665 $string = $messageCache->transform( $string, 01666 !$forContent, $langCodeObj ); 01667 } 01668 01669 if ( in_array( 'escape', $options, true ) ) { 01670 $string = htmlspecialchars ( $string ); 01671 } elseif ( in_array( 'escapenoentities', $options, true ) ) { 01672 $string = Sanitizer::escapeHtmlAllowEntities( $string ); 01673 } 01674 01675 if ( in_array( 'replaceafter', $options, true ) ) { 01676 $string = wfMsgReplaceArgs( $string, $args ); 01677 } 01678 01679 return $string; 01680 } 01681 01692 function wfEmptyMsg( $key ) { 01693 wfDeprecated( __METHOD__, '1.21' ); 01694 01695 return MessageCache::singleton()->get( $key, /*useDB*/true, /*content*/false ) === false; 01696 } 01697 01706 function wfDebugDieBacktrace( $msg = '' ) { 01707 wfDeprecated( __FUNCTION__, '1.22' ); 01708 throw new MWException( $msg ); 01709 } 01710 01718 function wfHostname() { 01719 static $host; 01720 if ( is_null( $host ) ) { 01721 01722 # Hostname overriding 01723 global $wgOverrideHostname; 01724 if ( $wgOverrideHostname !== false ) { 01725 # Set static and skip any detection 01726 $host = $wgOverrideHostname; 01727 return $host; 01728 } 01729 01730 if ( function_exists( 'posix_uname' ) ) { 01731 // This function not present on Windows 01732 $uname = posix_uname(); 01733 } else { 01734 $uname = false; 01735 } 01736 if ( is_array( $uname ) && isset( $uname['nodename'] ) ) { 01737 $host = $uname['nodename']; 01738 } elseif ( getenv( 'COMPUTERNAME' ) ) { 01739 # Windows computer name 01740 $host = getenv( 'COMPUTERNAME' ); 01741 } else { 01742 # This may be a virtual server. 01743 $host = $_SERVER['SERVER_NAME']; 01744 } 01745 } 01746 return $host; 01747 } 01748 01755 function wfReportTime() { 01756 global $wgRequestTime, $wgShowHostnames; 01757 01758 $elapsed = microtime( true ) - $wgRequestTime; 01759 01760 return $wgShowHostnames 01761 ? sprintf( '<!-- Served by %s in %01.3f secs. -->', wfHostname(), $elapsed ) 01762 : sprintf( '<!-- Served in %01.3f secs. -->', $elapsed ); 01763 } 01764 01780 function wfDebugBacktrace( $limit = 0 ) { 01781 static $disabled = null; 01782 01783 if ( extension_loaded( 'Zend Optimizer' ) ) { 01784 wfDebug( "Zend Optimizer detected; skipping debug_backtrace for safety.\n" ); 01785 return array(); 01786 } 01787 01788 if ( is_null( $disabled ) ) { 01789 $disabled = false; 01790 $functions = explode( ',', ini_get( 'disable_functions' ) ); 01791 $functions = array_map( 'trim', $functions ); 01792 $functions = array_map( 'strtolower', $functions ); 01793 if ( in_array( 'debug_backtrace', $functions ) ) { 01794 wfDebug( "debug_backtrace is in disabled_functions\n" ); 01795 $disabled = true; 01796 } 01797 } 01798 if ( $disabled ) { 01799 return array(); 01800 } 01801 01802 if ( $limit && version_compare( PHP_VERSION, '5.4.0', '>=' ) ) { 01803 return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 ); 01804 } else { 01805 return array_slice( debug_backtrace(), 1 ); 01806 } 01807 } 01808 01814 function wfBacktrace() { 01815 global $wgCommandLineMode; 01816 01817 if ( $wgCommandLineMode ) { 01818 $msg = ''; 01819 } else { 01820 $msg = "<ul>\n"; 01821 } 01822 $backtrace = wfDebugBacktrace(); 01823 foreach ( $backtrace as $call ) { 01824 if ( isset( $call['file'] ) ) { 01825 $f = explode( DIRECTORY_SEPARATOR, $call['file'] ); 01826 $file = $f[count( $f ) - 1]; 01827 } else { 01828 $file = '-'; 01829 } 01830 if ( isset( $call['line'] ) ) { 01831 $line = $call['line']; 01832 } else { 01833 $line = '-'; 01834 } 01835 if ( $wgCommandLineMode ) { 01836 $msg .= "$file line $line calls "; 01837 } else { 01838 $msg .= '<li>' . $file . ' line ' . $line . ' calls '; 01839 } 01840 if ( !empty( $call['class'] ) ) { 01841 $msg .= $call['class'] . $call['type']; 01842 } 01843 $msg .= $call['function'] . '()'; 01844 01845 if ( $wgCommandLineMode ) { 01846 $msg .= "\n"; 01847 } else { 01848 $msg .= "</li>\n"; 01849 } 01850 } 01851 if ( $wgCommandLineMode ) { 01852 $msg .= "\n"; 01853 } else { 01854 $msg .= "</ul>\n"; 01855 } 01856 01857 return $msg; 01858 } 01859 01869 function wfGetCaller( $level = 2 ) { 01870 $backtrace = wfDebugBacktrace( $level + 1 ); 01871 if ( isset( $backtrace[$level] ) ) { 01872 return wfFormatStackFrame( $backtrace[$level] ); 01873 } else { 01874 return 'unknown'; 01875 } 01876 } 01877 01886 function wfGetAllCallers( $limit = 3 ) { 01887 $trace = array_reverse( wfDebugBacktrace() ); 01888 if ( !$limit || $limit > count( $trace ) - 1 ) { 01889 $limit = count( $trace ) - 1; 01890 } 01891 $trace = array_slice( $trace, -$limit - 1, $limit ); 01892 return implode( '/', array_map( 'wfFormatStackFrame', $trace ) ); 01893 } 01894 01901 function wfFormatStackFrame( $frame ) { 01902 return isset( $frame['class'] ) ? 01903 $frame['class'] . '::' . $frame['function'] : 01904 $frame['function']; 01905 } 01906 01907 /* Some generic result counters, pulled out of SearchEngine */ 01908 01916 function wfShowingResults( $offset, $limit ) { 01917 return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse(); 01918 } 01919 01931 function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { 01932 wfDeprecated( __METHOD__, '1.19' ); 01933 01934 global $wgLang; 01935 01936 $query = wfCgiToArray( $query ); 01937 01938 if ( is_object( $link ) ) { 01939 $title = $link; 01940 } else { 01941 $title = Title::newFromText( $link ); 01942 if ( is_null( $title ) ) { 01943 return false; 01944 } 01945 } 01946 01947 return $wgLang->viewPrevNext( $title, $offset, $limit, $query, $atend ); 01948 } 01949 01957 function wfClientAcceptsGzip( $force = false ) { 01958 static $result = null; 01959 if ( $result === null || $force ) { 01960 $result = false; 01961 if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) { 01962 # @todo FIXME: We may want to blacklist some broken browsers 01963 $m = array(); 01964 if ( preg_match( 01965 '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/', 01966 $_SERVER['HTTP_ACCEPT_ENCODING'], 01967 $m ) 01968 ) 01969 { 01970 if ( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) { 01971 $result = false; 01972 return $result; 01973 } 01974 wfDebug( "wfClientAcceptsGzip: client accepts gzip.\n" ); 01975 $result = true; 01976 } 01977 } 01978 } 01979 return $result; 01980 } 01981 01991 function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) { 01992 global $wgRequest; 01993 return $wgRequest->getLimitOffset( $deflimit, $optionname ); 01994 } 01995 02005 function wfEscapeWikiText( $text ) { 02006 static $repl = null, $repl2 = null; 02007 if ( $repl === null ) { 02008 $repl = array( 02009 '"' => '"', '&' => '&', "'" => ''', '<' => '<', 02010 '=' => '=', '>' => '>', '[' => '[', ']' => ']', 02011 '{' => '{', '|' => '|', '}' => '}', ';' => ';', 02012 "\n#" => "\n#", "\r#" => "\r#", 02013 "\n*" => "\n*", "\r*" => "\r*", 02014 "\n:" => "\n:", "\r:" => "\r:", 02015 "\n " => "\n ", "\r " => "\r ", 02016 "\n\n" => "\n ", "\r\n" => " \n", 02017 "\n\r" => "\n ", "\r\r" => "\r ", 02018 "\n\t" => "\n	", "\r\t" => "\r	", // "\n\t\n" is treated like "\n\n" 02019 "\n----" => "\n----", "\r----" => "\r----", 02020 '__' => '__', '://' => '://', 02021 ); 02022 02023 // We have to catch everything "\s" matches in PCRE 02024 foreach ( array( 'ISBN', 'RFC', 'PMID' ) as $magic ) { 02025 $repl["$magic "] = "$magic "; 02026 $repl["$magic\t"] = "$magic	"; 02027 $repl["$magic\r"] = "$magic "; 02028 $repl["$magic\n"] = "$magic "; 02029 $repl["$magic\f"] = "$magic"; 02030 } 02031 02032 // And handle protocols that don't use "://" 02033 global $wgUrlProtocols; 02034 $repl2 = array(); 02035 foreach ( $wgUrlProtocols as $prot ) { 02036 if ( substr( $prot, -1 ) === ':' ) { 02037 $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' ); 02038 } 02039 } 02040 $repl2 = $repl2 ? '/\b(' . join( '|', $repl2 ) . '):/i' : '/^(?!)/'; 02041 } 02042 $text = substr( strtr( "\n$text", $repl ), 1 ); 02043 $text = preg_replace( $repl2, '$1:', $text ); 02044 return $text; 02045 } 02046 02052 function wfTime() { 02053 wfDeprecated( __FUNCTION__, '1.22' ); 02054 return microtime( true ); 02055 } 02056 02067 function wfSetVar( &$dest, $source, $force = false ) { 02068 $temp = $dest; 02069 if ( !is_null( $source ) || $force ) { 02070 $dest = $source; 02071 } 02072 return $temp; 02073 } 02074 02084 function wfSetBit( &$dest, $bit, $state = true ) { 02085 $temp = (bool)( $dest & $bit ); 02086 if ( !is_null( $state ) ) { 02087 if ( $state ) { 02088 $dest |= $bit; 02089 } else { 02090 $dest &= ~$bit; 02091 } 02092 } 02093 return $temp; 02094 } 02095 02102 function wfVarDump( $var ) { 02103 global $wgOut; 02104 $s = str_replace( "\n", "<br />\n", var_export( $var, true ) . "\n" ); 02105 if ( headers_sent() || !isset( $wgOut ) || !is_object( $wgOut ) ) { 02106 print $s; 02107 } else { 02108 $wgOut->addHTML( $s ); 02109 } 02110 } 02111 02119 function wfHttpError( $code, $label, $desc ) { 02120 global $wgOut; 02121 $wgOut->disable(); 02122 header( "HTTP/1.0 $code $label" ); 02123 header( "Status: $code $label" ); 02124 $wgOut->sendCacheControl(); 02125 02126 header( 'Content-type: text/html; charset=utf-8' ); 02127 print "<!doctype html>" . 02128 '<html><head><title>' . 02129 htmlspecialchars( $label ) . 02130 '</title></head><body><h1>' . 02131 htmlspecialchars( $label ) . 02132 '</h1><p>' . 02133 nl2br( htmlspecialchars( $desc ) ) . 02134 "</p></body></html>\n"; 02135 } 02136 02154 function wfResetOutputBuffers( $resetGzipEncoding = true ) { 02155 if ( $resetGzipEncoding ) { 02156 // Suppress Content-Encoding and Content-Length 02157 // headers from 1.10+s wfOutputHandler 02158 global $wgDisableOutputCompression; 02159 $wgDisableOutputCompression = true; 02160 } 02161 while ( $status = ob_get_status() ) { 02162 if ( $status['type'] == 0 /* PHP_OUTPUT_HANDLER_INTERNAL */ ) { 02163 // Probably from zlib.output_compression or other 02164 // PHP-internal setting which can't be removed. 02165 // 02166 // Give up, and hope the result doesn't break 02167 // output behavior. 02168 break; 02169 } 02170 if ( !ob_end_clean() ) { 02171 // Could not remove output buffer handler; abort now 02172 // to avoid getting in some kind of infinite loop. 02173 break; 02174 } 02175 if ( $resetGzipEncoding ) { 02176 if ( $status['name'] == 'ob_gzhandler' ) { 02177 // Reset the 'Content-Encoding' field set by this handler 02178 // so we can start fresh. 02179 header_remove( 'Content-Encoding' ); 02180 break; 02181 } 02182 } 02183 } 02184 } 02185 02198 function wfClearOutputBuffers() { 02199 wfResetOutputBuffers( false ); 02200 } 02201 02210 function wfAcceptToPrefs( $accept, $def = '*/*' ) { 02211 # No arg means accept anything (per HTTP spec) 02212 if ( !$accept ) { 02213 return array( $def => 1.0 ); 02214 } 02215 02216 $prefs = array(); 02217 02218 $parts = explode( ',', $accept ); 02219 02220 foreach ( $parts as $part ) { 02221 # @todo FIXME: Doesn't deal with params like 'text/html; level=1' 02222 $values = explode( ';', trim( $part ) ); 02223 $match = array(); 02224 if ( count( $values ) == 1 ) { 02225 $prefs[$values[0]] = 1.0; 02226 } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) { 02227 $prefs[$values[0]] = floatval( $match[1] ); 02228 } 02229 } 02230 02231 return $prefs; 02232 } 02233 02246 function mimeTypeMatch( $type, $avail ) { 02247 if ( array_key_exists( $type, $avail ) ) { 02248 return $type; 02249 } else { 02250 $parts = explode( '/', $type ); 02251 if ( array_key_exists( $parts[0] . '/*', $avail ) ) { 02252 return $parts[0] . '/*'; 02253 } elseif ( array_key_exists( '*/*', $avail ) ) { 02254 return '*/*'; 02255 } else { 02256 return null; 02257 } 02258 } 02259 } 02260 02274 function wfNegotiateType( $cprefs, $sprefs ) { 02275 $combine = array(); 02276 02277 foreach ( array_keys( $sprefs ) as $type ) { 02278 $parts = explode( '/', $type ); 02279 if ( $parts[1] != '*' ) { 02280 $ckey = mimeTypeMatch( $type, $cprefs ); 02281 if ( $ckey ) { 02282 $combine[$type] = $sprefs[$type] * $cprefs[$ckey]; 02283 } 02284 } 02285 } 02286 02287 foreach ( array_keys( $cprefs ) as $type ) { 02288 $parts = explode( '/', $type ); 02289 if ( $parts[1] != '*' && !array_key_exists( $type, $sprefs ) ) { 02290 $skey = mimeTypeMatch( $type, $sprefs ); 02291 if ( $skey ) { 02292 $combine[$type] = $sprefs[$skey] * $cprefs[$type]; 02293 } 02294 } 02295 } 02296 02297 $bestq = 0; 02298 $besttype = null; 02299 02300 foreach ( array_keys( $combine ) as $type ) { 02301 if ( $combine[$type] > $bestq ) { 02302 $besttype = $type; 02303 $bestq = $combine[$type]; 02304 } 02305 } 02306 02307 return $besttype; 02308 } 02309 02315 function wfSuppressWarnings( $end = false ) { 02316 static $suppressCount = 0; 02317 static $originalLevel = false; 02318 02319 if ( $end ) { 02320 if ( $suppressCount ) { 02321 --$suppressCount; 02322 if ( !$suppressCount ) { 02323 error_reporting( $originalLevel ); 02324 } 02325 } 02326 } else { 02327 if ( !$suppressCount ) { 02328 $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT ) ); 02329 } 02330 ++$suppressCount; 02331 } 02332 } 02333 02337 function wfRestoreWarnings() { 02338 wfSuppressWarnings( true ); 02339 } 02340 02341 # Autodetect, convert and provide timestamps of various types 02342 02346 define( 'TS_UNIX', 0 ); 02347 02351 define( 'TS_MW', 1 ); 02352 02356 define( 'TS_DB', 2 ); 02357 02361 define( 'TS_RFC2822', 3 ); 02362 02368 define( 'TS_ISO_8601', 4 ); 02369 02377 define( 'TS_EXIF', 5 ); 02378 02382 define( 'TS_ORACLE', 6 ); 02383 02387 define( 'TS_POSTGRES', 7 ); 02388 02392 define( 'TS_ISO_8601_BASIC', 9 ); 02393 02403 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) { 02404 try { 02405 $timestamp = new MWTimestamp( $ts ); 02406 return $timestamp->getTimestamp( $outputtype ); 02407 } catch ( TimestampException $e ) { 02408 wfDebug( "wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n" ); 02409 return false; 02410 } 02411 } 02412 02421 function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) { 02422 if ( is_null( $ts ) ) { 02423 return null; 02424 } else { 02425 return wfTimestamp( $outputtype, $ts ); 02426 } 02427 } 02428 02434 function wfTimestampNow() { 02435 # return NOW 02436 return wfTimestamp( TS_MW, time() ); 02437 } 02438 02444 function wfIsWindows() { 02445 static $isWindows = null; 02446 if ( $isWindows === null ) { 02447 $isWindows = substr( php_uname(), 0, 7 ) == 'Windows'; 02448 } 02449 return $isWindows; 02450 } 02451 02457 function wfIsHipHop() { 02458 return defined( 'HPHP_VERSION' ); 02459 } 02460 02467 function swap( &$x, &$y ) { 02468 $z = $x; 02469 $x = $y; 02470 $y = $z; 02471 } 02472 02484 function wfTempDir() { 02485 global $wgTmpDirectory; 02486 02487 if ( $wgTmpDirectory !== false ) { 02488 return $wgTmpDirectory; 02489 } 02490 02491 $tmpDir = array_map( "getenv", array( 'TMPDIR', 'TMP', 'TEMP' ) ); 02492 02493 foreach ( $tmpDir as $tmp ) { 02494 if ( $tmp && file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) { 02495 return $tmp; 02496 } 02497 } 02498 return sys_get_temp_dir(); 02499 } 02500 02510 function wfMkdirParents( $dir, $mode = null, $caller = null ) { 02511 global $wgDirectoryMode; 02512 02513 if ( FileBackend::isStoragePath( $dir ) ) { // sanity 02514 throw new MWException( __FUNCTION__ . " given storage path '$dir'." ); 02515 } 02516 02517 if ( !is_null( $caller ) ) { 02518 wfDebug( "$caller: called wfMkdirParents($dir)\n" ); 02519 } 02520 02521 if ( strval( $dir ) === '' || ( file_exists( $dir ) && is_dir( $dir ) ) ) { 02522 return true; 02523 } 02524 02525 $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir ); 02526 02527 if ( is_null( $mode ) ) { 02528 $mode = $wgDirectoryMode; 02529 } 02530 02531 // Turn off the normal warning, we're doing our own below 02532 wfSuppressWarnings(); 02533 $ok = mkdir( $dir, $mode, true ); // PHP5 <3 02534 wfRestoreWarnings(); 02535 02536 if ( !$ok ) { 02537 //directory may have been created on another request since we last checked 02538 if ( is_dir( $dir ) ) { 02539 return true; 02540 } 02541 02542 // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis. 02543 wfLogWarning( sprintf( "failed to mkdir \"%s\" mode 0%o", $dir, $mode ) ); 02544 } 02545 return $ok; 02546 } 02547 02552 function wfRecursiveRemoveDir( $dir ) { 02553 wfDebug( __FUNCTION__ . "( $dir )\n" ); 02554 // taken from http://de3.php.net/manual/en/function.rmdir.php#98622 02555 if ( is_dir( $dir ) ) { 02556 $objects = scandir( $dir ); 02557 foreach ( $objects as $object ) { 02558 if ( $object != "." && $object != ".." ) { 02559 if ( filetype( $dir . '/' . $object ) == "dir" ) { 02560 wfRecursiveRemoveDir( $dir . '/' . $object ); 02561 } else { 02562 unlink( $dir . '/' . $object ); 02563 } 02564 } 02565 } 02566 reset( $objects ); 02567 rmdir( $dir ); 02568 } 02569 } 02570 02577 function wfPercent( $nr, $acc = 2, $round = true ) { 02578 $ret = sprintf( "%.${acc}f", $nr ); 02579 return $round ? round( $ret, $acc ) . '%' : "$ret%"; 02580 } 02581 02591 function in_string( $needle, $str, $insensitive = false ) { 02592 wfDeprecated( __METHOD__, '1.21' ); 02593 $func = 'strpos'; 02594 if ( $insensitive ) { 02595 $func = 'stripos'; 02596 } 02597 02598 return $func( $str, $needle ) !== false; 02599 } 02600 02624 function wfIniGetBool( $setting ) { 02625 $val = strtolower( ini_get( $setting ) ); 02626 // 'on' and 'true' can't have whitespace around them, but '1' can. 02627 return $val == 'on' 02628 || $val == 'true' 02629 || $val == 'yes' 02630 || preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function 02631 } 02632 02644 function wfEscapeShellArg() { 02645 wfInitShellLocale(); 02646 02647 $args = func_get_args(); 02648 $first = true; 02649 $retVal = ''; 02650 foreach ( $args as $arg ) { 02651 if ( !$first ) { 02652 $retVal .= ' '; 02653 } else { 02654 $first = false; 02655 } 02656 02657 if ( wfIsWindows() ) { 02658 // Escaping for an MSVC-style command line parser and CMD.EXE 02659 // Refs: 02660 // * http://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html 02661 // * http://technet.microsoft.com/en-us/library/cc723564.aspx 02662 // * Bug #13518 02663 // * CR r63214 02664 // Double the backslashes before any double quotes. Escape the double quotes. 02665 $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE ); 02666 $arg = ''; 02667 $iteration = 0; 02668 foreach ( $tokens as $token ) { 02669 if ( $iteration % 2 == 1 ) { 02670 // Delimiter, a double quote preceded by zero or more slashes 02671 $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"'; 02672 } elseif ( $iteration % 4 == 2 ) { 02673 // ^ in $token will be outside quotes, need to be escaped 02674 $arg .= str_replace( '^', '^^', $token ); 02675 } else { // $iteration % 4 == 0 02676 // ^ in $token will appear inside double quotes, so leave as is 02677 $arg .= $token; 02678 } 02679 $iteration++; 02680 } 02681 // Double the backslashes before the end of the string, because 02682 // we will soon add a quote 02683 $m = array(); 02684 if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) { 02685 $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] ); 02686 } 02687 02688 // Add surrounding quotes 02689 $retVal .= '"' . $arg . '"'; 02690 } else { 02691 $retVal .= escapeshellarg( $arg ); 02692 } 02693 } 02694 return $retVal; 02695 } 02696 02702 function wfShellExecDisabled() { 02703 static $disabled = null; 02704 if ( is_null( $disabled ) ) { 02705 $disabled = false; 02706 if ( wfIniGetBool( 'safe_mode' ) ) { 02707 wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" ); 02708 $disabled = 'safemode'; 02709 } else { 02710 $functions = explode( ',', ini_get( 'disable_functions' ) ); 02711 $functions = array_map( 'trim', $functions ); 02712 $functions = array_map( 'strtolower', $functions ); 02713 if ( in_array( 'passthru', $functions ) ) { 02714 wfDebug( "passthru is in disabled_functions\n" ); 02715 $disabled = 'passthru'; 02716 } 02717 } 02718 } 02719 return $disabled; 02720 } 02721 02736 function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array(), $options = array() ) { 02737 global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime, 02738 $wgMaxShellWallClockTime, $wgShellCgroup; 02739 02740 $disabled = wfShellExecDisabled(); 02741 if ( $disabled ) { 02742 $retval = 1; 02743 return $disabled == 'safemode' ? 02744 'Unable to run external programs in safe mode.' : 02745 'Unable to run external programs, passthru() is disabled.'; 02746 } 02747 02748 $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr']; 02749 02750 wfInitShellLocale(); 02751 02752 $envcmd = ''; 02753 foreach ( $environ as $k => $v ) { 02754 if ( wfIsWindows() ) { 02755 /* Surrounding a set in quotes (method used by wfEscapeShellArg) makes the quotes themselves 02756 * appear in the environment variable, so we must use carat escaping as documented in 02757 * http://technet.microsoft.com/en-us/library/cc723564.aspx 02758 * Note however that the quote isn't listed there, but is needed, and the parentheses 02759 * are listed there but doesn't appear to need it. 02760 */ 02761 $envcmd .= "set $k=" . preg_replace( '/([&|()<>^"])/', '^\\1', $v ) . '&& '; 02762 } else { 02763 /* Assume this is a POSIX shell, thus required to accept variable assignments before the command 02764 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_01 02765 */ 02766 $envcmd .= "$k=" . escapeshellarg( $v ) . ' '; 02767 } 02768 } 02769 $cmd = $envcmd . $cmd; 02770 02771 if ( php_uname( 's' ) == 'Linux' ) { 02772 $time = intval ( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime ); 02773 if ( isset( $limits['walltime'] ) ) { 02774 $wallTime = intval( $limits['walltime'] ); 02775 } elseif ( isset( $limits['time'] ) ) { 02776 $wallTime = $time; 02777 } else { 02778 $wallTime = intval( $wgMaxShellWallClockTime ); 02779 } 02780 $mem = intval ( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory ); 02781 $filesize = intval ( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize ); 02782 02783 if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) { 02784 $cmd = '/bin/bash ' . escapeshellarg( "$IP/includes/limit.sh" ) . ' ' . 02785 escapeshellarg( $cmd ) . ' ' . 02786 escapeshellarg( 02787 "MW_INCLUDE_STDERR=" . ( $includeStderr ? '1' : '' ) . ';' . 02788 "MW_CPU_LIMIT=$time; " . 02789 'MW_CGROUP=' . escapeshellarg( $wgShellCgroup ) . '; ' . 02790 "MW_MEM_LIMIT=$mem; " . 02791 "MW_FILE_SIZE_LIMIT=$filesize; " . 02792 "MW_WALL_CLOCK_LIMIT=$wallTime" 02793 ); 02794 } elseif ( $includeStderr ) { 02795 $cmd .= ' 2>&1'; 02796 } 02797 } elseif ( $includeStderr ) { 02798 $cmd .= ' 2>&1'; 02799 } 02800 wfDebug( "wfShellExec: $cmd\n" ); 02801 02802 // Default to an unusual value that shouldn't happen naturally, 02803 // so in the unlikely event of a weird php bug, it would be 02804 // more obvious what happened. 02805 $retval = 200; 02806 ob_start(); 02807 passthru( $cmd, $retval ); 02808 $output = ob_get_contents(); 02809 ob_end_clean(); 02810 02811 if ( $retval == 127 ) { 02812 wfDebugLog( 'exec', "Possibly missing executable file: $cmd\n" ); 02813 } 02814 return $output; 02815 } 02816 02831 function wfShellExecWithStderr( $cmd, &$retval = null, $environ = array(), $limits = array() ) { 02832 return wfShellExec( $cmd, $retval, $environ, $limits, array( 'duplicateStderr' => true ) ); 02833 } 02834 02839 function wfInitShellLocale() { 02840 static $done = false; 02841 if ( $done ) { 02842 return; 02843 } 02844 $done = true; 02845 global $wgShellLocale; 02846 if ( !wfIniGetBool( 'safe_mode' ) ) { 02847 putenv( "LC_CTYPE=$wgShellLocale" ); 02848 setlocale( LC_CTYPE, $wgShellLocale ); 02849 } 02850 } 02851 02856 function wfShellMaintenanceCmd( $script, array $parameters = array(), array $options = array() ) { 02857 return wfShellWikiCmd( $script, $parameters, $options ); 02858 } 02859 02871 function wfShellWikiCmd( $script, array $parameters = array(), array $options = array() ) { 02872 global $wgPhpCli; 02873 // Give site config file a chance to run the script in a wrapper. 02874 // The caller may likely want to call wfBasename() on $script. 02875 wfRunHooks( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) ); 02876 $cmd = isset( $options['php'] ) ? array( $options['php'] ) : array( $wgPhpCli ); 02877 if ( isset( $options['wrapper'] ) ) { 02878 $cmd[] = $options['wrapper']; 02879 } 02880 $cmd[] = $script; 02881 // Escape each parameter for shell 02882 return implode( " ", array_map( 'wfEscapeShellArg', array_merge( $cmd, $parameters ) ) ); 02883 } 02884 02895 function wfMerge( $old, $mine, $yours, &$result ) { 02896 global $wgDiff3; 02897 02898 # This check may also protect against code injection in 02899 # case of broken installations. 02900 wfSuppressWarnings(); 02901 $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 ); 02902 wfRestoreWarnings(); 02903 02904 if ( !$haveDiff3 ) { 02905 wfDebug( "diff3 not found\n" ); 02906 return false; 02907 } 02908 02909 # Make temporary files 02910 $td = wfTempDir(); 02911 $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' ); 02912 $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' ); 02913 $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' ); 02914 02915 # NOTE: diff3 issues a warning to stderr if any of the files does not end with 02916 # a newline character. To avoid this, we normalize the trailing whitespace before 02917 # creating the diff. 02918 02919 fwrite( $oldtextFile, rtrim( $old ) . "\n" ); 02920 fclose( $oldtextFile ); 02921 fwrite( $mytextFile, rtrim( $mine ) . "\n" ); 02922 fclose( $mytextFile ); 02923 fwrite( $yourtextFile, rtrim( $yours ) . "\n" ); 02924 fclose( $yourtextFile ); 02925 02926 # Check for a conflict 02927 $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a --overlap-only ' . 02928 wfEscapeShellArg( $mytextName ) . ' ' . 02929 wfEscapeShellArg( $oldtextName ) . ' ' . 02930 wfEscapeShellArg( $yourtextName ); 02931 $handle = popen( $cmd, 'r' ); 02932 02933 if ( fgets( $handle, 1024 ) ) { 02934 $conflict = true; 02935 } else { 02936 $conflict = false; 02937 } 02938 pclose( $handle ); 02939 02940 # Merge differences 02941 $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a -e --merge ' . 02942 wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName ); 02943 $handle = popen( $cmd, 'r' ); 02944 $result = ''; 02945 do { 02946 $data = fread( $handle, 8192 ); 02947 if ( strlen( $data ) == 0 ) { 02948 break; 02949 } 02950 $result .= $data; 02951 } while ( true ); 02952 pclose( $handle ); 02953 unlink( $mytextName ); 02954 unlink( $oldtextName ); 02955 unlink( $yourtextName ); 02956 02957 if ( $result === '' && $old !== '' && !$conflict ) { 02958 wfDebug( "Unexpected null result from diff3. Command: $cmd\n" ); 02959 $conflict = true; 02960 } 02961 return !$conflict; 02962 } 02963 02973 function wfDiff( $before, $after, $params = '-u' ) { 02974 if ( $before == $after ) { 02975 return ''; 02976 } 02977 02978 global $wgDiff; 02979 wfSuppressWarnings(); 02980 $haveDiff = $wgDiff && file_exists( $wgDiff ); 02981 wfRestoreWarnings(); 02982 02983 # This check may also protect against code injection in 02984 # case of broken installations. 02985 if ( !$haveDiff ) { 02986 wfDebug( "diff executable not found\n" ); 02987 $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) ); 02988 $format = new UnifiedDiffFormatter(); 02989 return $format->format( $diffs ); 02990 } 02991 02992 # Make temporary files 02993 $td = wfTempDir(); 02994 $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' ); 02995 $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' ); 02996 02997 fwrite( $oldtextFile, $before ); 02998 fclose( $oldtextFile ); 02999 fwrite( $newtextFile, $after ); 03000 fclose( $newtextFile ); 03001 03002 // Get the diff of the two files 03003 $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName ); 03004 03005 $h = popen( $cmd, 'r' ); 03006 03007 $diff = ''; 03008 03009 do { 03010 $data = fread( $h, 8192 ); 03011 if ( strlen( $data ) == 0 ) { 03012 break; 03013 } 03014 $diff .= $data; 03015 } while ( true ); 03016 03017 // Clean up 03018 pclose( $h ); 03019 unlink( $oldtextName ); 03020 unlink( $newtextName ); 03021 03022 // Kill the --- and +++ lines. They're not useful. 03023 $diff_lines = explode( "\n", $diff ); 03024 if ( strpos( $diff_lines[0], '---' ) === 0 ) { 03025 unset( $diff_lines[0] ); 03026 } 03027 if ( strpos( $diff_lines[1], '+++' ) === 0 ) { 03028 unset( $diff_lines[1] ); 03029 } 03030 03031 $diff = implode( "\n", $diff_lines ); 03032 03033 return $diff; 03034 } 03035 03052 function wfUsePHP( $req_ver ) { 03053 $php_ver = PHP_VERSION; 03054 03055 if ( version_compare( $php_ver, (string)$req_ver, '<' ) ) { 03056 throw new MWException( "PHP $req_ver required--this is only $php_ver" ); 03057 } 03058 } 03059 03074 function wfUseMW( $req_ver ) { 03075 global $wgVersion; 03076 03077 if ( version_compare( $wgVersion, (string)$req_ver, '<' ) ) { 03078 throw new MWException( "MediaWiki $req_ver required--this is only $wgVersion" ); 03079 } 03080 } 03081 03094 function wfBaseName( $path, $suffix = '' ) { 03095 $encSuffix = ( $suffix == '' ) 03096 ? '' 03097 : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' ); 03098 $matches = array(); 03099 if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) { 03100 return $matches[1]; 03101 } else { 03102 return ''; 03103 } 03104 } 03105 03115 function wfRelativePath( $path, $from ) { 03116 // Normalize mixed input on Windows... 03117 $path = str_replace( '/', DIRECTORY_SEPARATOR, $path ); 03118 $from = str_replace( '/', DIRECTORY_SEPARATOR, $from ); 03119 03120 // Trim trailing slashes -- fix for drive root 03121 $path = rtrim( $path, DIRECTORY_SEPARATOR ); 03122 $from = rtrim( $from, DIRECTORY_SEPARATOR ); 03123 03124 $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) ); 03125 $against = explode( DIRECTORY_SEPARATOR, $from ); 03126 03127 if ( $pieces[0] !== $against[0] ) { 03128 // Non-matching Windows drive letters? 03129 // Return a full path. 03130 return $path; 03131 } 03132 03133 // Trim off common prefix 03134 while ( count( $pieces ) && count( $against ) 03135 && $pieces[0] == $against[0] ) { 03136 array_shift( $pieces ); 03137 array_shift( $against ); 03138 } 03139 03140 // relative dots to bump us to the parent 03141 while ( count( $against ) ) { 03142 array_unshift( $pieces, '..' ); 03143 array_shift( $against ); 03144 } 03145 03146 array_push( $pieces, wfBaseName( $path ) ); 03147 03148 return implode( DIRECTORY_SEPARATOR, $pieces ); 03149 } 03150 03158 function wfDoUpdates( $commit = '' ) { 03159 wfDeprecated( __METHOD__, '1.19' ); 03160 DeferredUpdates::doUpdates( $commit ); 03161 } 03162 03178 function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true, $engine = 'auto' ) { 03179 $input = (string)$input; 03180 if ( 03181 $sourceBase < 2 || 03182 $sourceBase > 36 || 03183 $destBase < 2 || 03184 $destBase > 36 || 03185 $sourceBase != (int)$sourceBase || 03186 $destBase != (int)$destBase || 03187 $pad != (int)$pad || 03188 !preg_match( "/^[" . substr( '0123456789abcdefghijklmnopqrstuvwxyz', 0, $sourceBase ) . "]+$/i", $input ) 03189 ) { 03190 return false; 03191 } 03192 03193 static $baseChars = array( 03194 10 => 'a', 11 => 'b', 12 => 'c', 13 => 'd', 14 => 'e', 15 => 'f', 03195 16 => 'g', 17 => 'h', 18 => 'i', 19 => 'j', 20 => 'k', 21 => 'l', 03196 22 => 'm', 23 => 'n', 24 => 'o', 25 => 'p', 26 => 'q', 27 => 'r', 03197 28 => 's', 29 => 't', 30 => 'u', 31 => 'v', 32 => 'w', 33 => 'x', 03198 34 => 'y', 35 => 'z', 03199 03200 '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, 03201 '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'a' => 10, 'b' => 11, 03202 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17, 03203 'i' => 18, 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23, 03204 'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27, 's' => 28, 't' => 29, 03205 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35 03206 ); 03207 03208 if ( extension_loaded( 'gmp' ) && ( $engine == 'auto' || $engine == 'gmp' ) ) { 03209 $result = gmp_strval( gmp_init( $input, $sourceBase ), $destBase ); 03210 } elseif ( extension_loaded( 'bcmath' ) && ( $engine == 'auto' || $engine == 'bcmath' ) ) { 03211 $decimal = '0'; 03212 foreach ( str_split( strtolower( $input ) ) as $char ) { 03213 $decimal = bcmul( $decimal, $sourceBase ); 03214 $decimal = bcadd( $decimal, $baseChars[$char] ); 03215 } 03216 03217 for ( $result = ''; bccomp( $decimal, 0 ); $decimal = bcdiv( $decimal, $destBase, 0 ) ) { 03218 $result .= $baseChars[bcmod( $decimal, $destBase )]; 03219 } 03220 03221 $result = strrev( $result ); 03222 } else { 03223 $inDigits = array(); 03224 foreach ( str_split( strtolower( $input ) ) as $char ) { 03225 $inDigits[] = $baseChars[$char]; 03226 } 03227 03228 // Iterate over the input, modulo-ing out an output digit 03229 // at a time until input is gone. 03230 $result = ''; 03231 while ( $inDigits ) { 03232 $work = 0; 03233 $workDigits = array(); 03234 03235 // Long division... 03236 foreach ( $inDigits as $digit ) { 03237 $work *= $sourceBase; 03238 $work += $digit; 03239 03240 if ( $workDigits || $work >= $destBase ) { 03241 $workDigits[] = (int)( $work / $destBase ); 03242 } 03243 $work %= $destBase; 03244 } 03245 03246 // All that division leaves us with a remainder, 03247 // which is conveniently our next output digit. 03248 $result .= $baseChars[$work]; 03249 03250 // And we continue! 03251 $inDigits = $workDigits; 03252 } 03253 03254 $result = strrev( $result ); 03255 } 03256 03257 if ( !$lowercase ) { 03258 $result = strtoupper( $result ); 03259 } 03260 03261 return str_pad( $result, $pad, '0', STR_PAD_LEFT ); 03262 } 03263 03272 function wfCreateObject( $name, $p ) { 03273 wfDeprecated( __FUNCTION__, '1.18' ); 03274 return MWFunction::newObj( $name, $p ); 03275 } 03276 03280 function wfHttpOnlySafe() { 03281 global $wgHttpOnlyBlacklist; 03282 03283 if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) { 03284 foreach ( $wgHttpOnlyBlacklist as $regex ) { 03285 if ( preg_match( $regex, $_SERVER['HTTP_USER_AGENT'] ) ) { 03286 return false; 03287 } 03288 } 03289 } 03290 03291 return true; 03292 } 03293 03298 function wfCheckEntropy() { 03299 return ( 03300 ( wfIsWindows() && version_compare( PHP_VERSION, '5.3.3', '>=' ) ) 03301 || ini_get( 'session.entropy_file' ) 03302 ) 03303 && intval( ini_get( 'session.entropy_length' ) ) >= 32; 03304 } 03305 03310 function wfFixSessionID() { 03311 // If the cookie or session id is already set we already have a session and should abort 03312 if ( isset( $_COOKIE[session_name()] ) || session_id() ) { 03313 return; 03314 } 03315 03316 // PHP's built-in session entropy is enabled if: 03317 // - entropy_file is set or you're on Windows with php 5.3.3+ 03318 // - AND entropy_length is > 0 03319 // We treat it as disabled if it doesn't have an entropy length of at least 32 03320 $entropyEnabled = wfCheckEntropy(); 03321 03322 // If built-in entropy is not enabled or not sufficient override php's built in session id generation code 03323 if ( !$entropyEnabled ) { 03324 wfDebug( __METHOD__ . ": PHP's built in entropy is disabled or not sufficient, overriding session id generation using our cryptrand source.\n" ); 03325 session_id( MWCryptRand::generateHex( 32 ) ); 03326 } 03327 } 03328 03333 function wfResetSessionID() { 03334 global $wgCookieSecure; 03335 $oldSessionId = session_id(); 03336 $cookieParams = session_get_cookie_params(); 03337 if ( wfCheckEntropy() && $wgCookieSecure == $cookieParams['secure'] ) { 03338 session_regenerate_id( false ); 03339 } else { 03340 $tmp = $_SESSION; 03341 session_destroy(); 03342 wfSetupSession( MWCryptRand::generateHex( 32 ) ); 03343 $_SESSION = $tmp; 03344 } 03345 $newSessionId = session_id(); 03346 wfRunHooks( 'ResetSessionID', array( $oldSessionId, $newSessionId ) ); 03347 } 03348 03349 03355 function wfSetupSession( $sessionId = false ) { 03356 global $wgSessionsInMemcached, $wgSessionsInObjectCache, $wgCookiePath, $wgCookieDomain, 03357 $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler; 03358 if ( $wgSessionsInObjectCache || $wgSessionsInMemcached ) { 03359 ObjectCacheSessionHandler::install(); 03360 } elseif ( $wgSessionHandler && $wgSessionHandler != ini_get( 'session.save_handler' ) ) { 03361 # Only set this if $wgSessionHandler isn't null and session.save_handler 03362 # hasn't already been set to the desired value (that causes errors) 03363 ini_set( 'session.save_handler', $wgSessionHandler ); 03364 } 03365 $httpOnlySafe = wfHttpOnlySafe() && $wgCookieHttpOnly; 03366 wfDebugLog( 'cookie', 03367 'session_set_cookie_params: "' . implode( '", "', 03368 array( 03369 0, 03370 $wgCookiePath, 03371 $wgCookieDomain, 03372 $wgCookieSecure, 03373 $httpOnlySafe ) ) . '"' ); 03374 session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe ); 03375 session_cache_limiter( 'private, must-revalidate' ); 03376 if ( $sessionId ) { 03377 session_id( $sessionId ); 03378 } else { 03379 wfFixSessionID(); 03380 } 03381 wfSuppressWarnings(); 03382 session_start(); 03383 wfRestoreWarnings(); 03384 } 03385 03392 function wfGetPrecompiledData( $name ) { 03393 global $IP; 03394 03395 $file = "$IP/serialized/$name"; 03396 if ( file_exists( $file ) ) { 03397 $blob = file_get_contents( $file ); 03398 if ( $blob ) { 03399 return unserialize( $blob ); 03400 } 03401 } 03402 return false; 03403 } 03404 03411 function wfMemcKey( /*... */ ) { 03412 global $wgCachePrefix; 03413 $prefix = $wgCachePrefix === false ? wfWikiID() : $wgCachePrefix; 03414 $args = func_get_args(); 03415 $key = $prefix . ':' . implode( ':', $args ); 03416 $key = str_replace( ' ', '_', $key ); 03417 return $key; 03418 } 03419 03428 function wfForeignMemcKey( $db, $prefix /*, ... */ ) { 03429 $args = array_slice( func_get_args(), 2 ); 03430 if ( $prefix ) { 03431 $key = "$db-$prefix:" . implode( ':', $args ); 03432 } else { 03433 $key = $db . ':' . implode( ':', $args ); 03434 } 03435 return str_replace( ' ', '_', $key ); 03436 } 03437 03444 function wfWikiID() { 03445 global $wgDBprefix, $wgDBname; 03446 if ( $wgDBprefix ) { 03447 return "$wgDBname-$wgDBprefix"; 03448 } else { 03449 return $wgDBname; 03450 } 03451 } 03452 03460 function wfSplitWikiID( $wiki ) { 03461 $bits = explode( '-', $wiki, 2 ); 03462 if ( count( $bits ) < 2 ) { 03463 $bits[] = ''; 03464 } 03465 return $bits; 03466 } 03467 03490 function &wfGetDB( $db, $groups = array(), $wiki = false ) { 03491 return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki ); 03492 } 03493 03500 function wfGetLB( $wiki = false ) { 03501 return wfGetLBFactory()->getMainLB( $wiki ); 03502 } 03503 03509 function &wfGetLBFactory() { 03510 return LBFactory::singleton(); 03511 } 03512 03533 function wfFindFile( $title, $options = array() ) { 03534 return RepoGroup::singleton()->findFile( $title, $options ); 03535 } 03536 03544 function wfLocalFile( $title ) { 03545 return RepoGroup::singleton()->getLocalRepo()->newFile( $title ); 03546 } 03547 03552 function wfStreamFile( $fname, $headers = array() ) { 03553 wfDeprecated( __FUNCTION__, '1.19' ); 03554 StreamFile::stream( $fname, $headers ); 03555 } 03556 03563 function wfQueriesMustScale() { 03564 global $wgMiserMode; 03565 return $wgMiserMode 03566 || ( SiteStats::pages() > 100000 03567 && SiteStats::edits() > 1000000 03568 && SiteStats::users() > 10000 ); 03569 } 03570 03579 function wfScript( $script = 'index' ) { 03580 global $wgScriptPath, $wgScriptExtension, $wgScript, $wgLoadScript; 03581 if ( $script === 'index' ) { 03582 return $wgScript; 03583 } elseif ( $script === 'load' ) { 03584 return $wgLoadScript; 03585 } else { 03586 return "{$wgScriptPath}/{$script}{$wgScriptExtension}"; 03587 } 03588 } 03589 03595 function wfGetScriptUrl() { 03596 if ( isset( $_SERVER['SCRIPT_NAME'] ) ) { 03597 # 03598 # as it was called, minus the query string. 03599 # 03600 # Some sites use Apache rewrite rules to handle subdomains, 03601 # and have PHP set up in a weird way that causes PHP_SELF 03602 # to contain the rewritten URL instead of the one that the 03603 # outside world sees. 03604 # 03605 # If in this mode, use SCRIPT_URL instead, which mod_rewrite 03606 # provides containing the "before" URL. 03607 return $_SERVER['SCRIPT_NAME']; 03608 } else { 03609 return $_SERVER['URL']; 03610 } 03611 } 03612 03620 function wfBoolToStr( $value ) { 03621 return $value ? 'true' : 'false'; 03622 } 03623 03629 function wfGetNull() { 03630 return wfIsWindows() 03631 ? 'NUL' 03632 : '/dev/null'; 03633 } 03634 03646 function wfWaitForSlaves( $maxLag = false, $wiki = false, $cluster = false ) { 03647 $lb = ( $cluster !== false ) 03648 ? wfGetLBFactory()->getExternalLB( $cluster ) 03649 : wfGetLB( $wiki ); 03650 // bug 27975 - Don't try to wait for slaves if there are none 03651 // Prevents permission error when getting master position 03652 if ( $lb->getServerCount() > 1 ) { 03653 $dbw = $lb->getConnection( DB_MASTER, array(), $wiki ); 03654 $pos = $dbw->getMasterPos(); 03655 // The DBMS may not support getMasterPos() or the whole 03656 // load balancer might be fake (e.g. $wgAllDBsAreLocalhost). 03657 if ( $pos !== false ) { 03658 $lb->waitForAll( $pos ); 03659 } 03660 } 03661 } 03662 03667 function wfOut( $s ) { 03668 wfDeprecated( __FUNCTION__, '1.18' ); 03669 global $wgCommandLineMode; 03670 if ( $wgCommandLineMode ) { 03671 echo $s; 03672 } else { 03673 echo htmlspecialchars( $s ); 03674 } 03675 flush(); 03676 } 03677 03684 function wfCountDown( $n ) { 03685 for ( $i = $n; $i >= 0; $i-- ) { 03686 if ( $i != $n ) { 03687 echo str_repeat( "\x08", strlen( $i + 1 ) ); 03688 } 03689 echo $i; 03690 flush(); 03691 if ( $i ) { 03692 sleep( 1 ); 03693 } 03694 } 03695 echo "\n"; 03696 } 03697 03707 function wfGenerateToken( $salt = '' ) { 03708 wfDeprecated( __METHOD__, '1.20' ); 03709 $salt = serialize( $salt ); 03710 return md5( mt_rand( 0, 0x7fffffff ) . $salt ); 03711 } 03712 03721 function wfStripIllegalFilenameChars( $name ) { 03722 global $wgIllegalFileChars; 03723 $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : ''; 03724 $name = wfBaseName( $name ); 03725 $name = preg_replace( 03726 "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/", 03727 '-', 03728 $name 03729 ); 03730 return $name; 03731 } 03732 03738 function wfMemoryLimit() { 03739 global $wgMemoryLimit; 03740 $memlimit = wfShorthandToInteger( ini_get( 'memory_limit' ) ); 03741 if ( $memlimit != -1 ) { 03742 $conflimit = wfShorthandToInteger( $wgMemoryLimit ); 03743 if ( $conflimit == -1 ) { 03744 wfDebug( "Removing PHP's memory limit\n" ); 03745 wfSuppressWarnings(); 03746 ini_set( 'memory_limit', $conflimit ); 03747 wfRestoreWarnings(); 03748 return $conflimit; 03749 } elseif ( $conflimit > $memlimit ) { 03750 wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" ); 03751 wfSuppressWarnings(); 03752 ini_set( 'memory_limit', $conflimit ); 03753 wfRestoreWarnings(); 03754 return $conflimit; 03755 } 03756 } 03757 return $memlimit; 03758 } 03759 03766 function wfShorthandToInteger( $string = '' ) { 03767 $string = trim( $string ); 03768 if ( $string === '' ) { 03769 return -1; 03770 } 03771 $last = $string[strlen( $string ) - 1]; 03772 $val = intval( $string ); 03773 switch ( $last ) { 03774 case 'g': 03775 case 'G': 03776 $val *= 1024; 03777 // break intentionally missing 03778 case 'm': 03779 case 'M': 03780 $val *= 1024; 03781 // break intentionally missing 03782 case 'k': 03783 case 'K': 03784 $val *= 1024; 03785 } 03786 03787 return $val; 03788 } 03789 03797 function wfBCP47( $code ) { 03798 $codeSegment = explode( '-', $code ); 03799 $codeBCP = array(); 03800 foreach ( $codeSegment as $segNo => $seg ) { 03801 // when previous segment is x, it is a private segment and should be lc 03802 if ( $segNo > 0 && strtolower( $codeSegment[( $segNo - 1 )] ) == 'x' ) { 03803 $codeBCP[$segNo] = strtolower( $seg ); 03804 // ISO 3166 country code 03805 } elseif ( ( strlen( $seg ) == 2 ) && ( $segNo > 0 ) ) { 03806 $codeBCP[$segNo] = strtoupper( $seg ); 03807 // ISO 15924 script code 03808 } elseif ( ( strlen( $seg ) == 4 ) && ( $segNo > 0 ) ) { 03809 $codeBCP[$segNo] = ucfirst( strtolower( $seg ) ); 03810 // Use lowercase for other cases 03811 } else { 03812 $codeBCP[$segNo] = strtolower( $seg ); 03813 } 03814 } 03815 $langCode = implode( '-', $codeBCP ); 03816 return $langCode; 03817 } 03818 03825 function wfGetCache( $inputType ) { 03826 return ObjectCache::getInstance( $inputType ); 03827 } 03828 03834 function wfGetMainCache() { 03835 global $wgMainCacheType; 03836 return ObjectCache::getInstance( $wgMainCacheType ); 03837 } 03838 03844 function wfGetMessageCacheStorage() { 03845 global $wgMessageCacheType; 03846 return ObjectCache::getInstance( $wgMessageCacheType ); 03847 } 03848 03854 function wfGetParserCacheStorage() { 03855 global $wgParserCacheType; 03856 return ObjectCache::getInstance( $wgParserCacheType ); 03857 } 03858 03864 function wfGetLangConverterCacheStorage() { 03865 global $wgLanguageConverterCacheType; 03866 return ObjectCache::getInstance( $wgLanguageConverterCacheType ); 03867 } 03868 03876 function wfRunHooks( $event, array $args = array() ) { 03877 return Hooks::run( $event, $args ); 03878 } 03879 03894 function wfUnpack( $format, $data, $length = false ) { 03895 if ( $length !== false ) { 03896 $realLen = strlen( $data ); 03897 if ( $realLen < $length ) { 03898 throw new MWException( "Tried to use wfUnpack on a " 03899 . "string of length $realLen, but needed one " 03900 . "of at least length $length." 03901 ); 03902 } 03903 } 03904 03905 wfSuppressWarnings(); 03906 $result = unpack( $format, $data ); 03907 wfRestoreWarnings(); 03908 03909 if ( $result === false ) { 03910 // If it cannot extract the packed data. 03911 throw new MWException( "unpack could not unpack binary data" ); 03912 } 03913 return $result; 03914 } 03915 03930 function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) { 03931 static $badImageCache = null; // based on bad_image_list msg 03932 wfProfileIn( __METHOD__ ); 03933 03934 # Handle redirects 03935 $redirectTitle = RepoGroup::singleton()->checkRedirect( Title::makeTitle( NS_FILE, $name ) ); 03936 if ( $redirectTitle ) { 03937 $name = $redirectTitle->getDBkey(); 03938 } 03939 03940 # Run the extension hook 03941 $bad = false; 03942 if ( !wfRunHooks( 'BadImage', array( $name, &$bad ) ) ) { 03943 wfProfileOut( __METHOD__ ); 03944 return $bad; 03945 } 03946 03947 $cacheable = ( $blacklist === null ); 03948 if ( $cacheable && $badImageCache !== null ) { 03949 $badImages = $badImageCache; 03950 } else { // cache miss 03951 if ( $blacklist === null ) { 03952 $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list 03953 } 03954 # Build the list now 03955 $badImages = array(); 03956 $lines = explode( "\n", $blacklist ); 03957 foreach ( $lines as $line ) { 03958 # List items only 03959 if ( substr( $line, 0, 1 ) !== '*' ) { 03960 continue; 03961 } 03962 03963 # Find all links 03964 $m = array(); 03965 if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) { 03966 continue; 03967 } 03968 03969 $exceptions = array(); 03970 $imageDBkey = false; 03971 foreach ( $m[1] as $i => $titleText ) { 03972 $title = Title::newFromText( $titleText ); 03973 if ( !is_null( $title ) ) { 03974 if ( $i == 0 ) { 03975 $imageDBkey = $title->getDBkey(); 03976 } else { 03977 $exceptions[$title->getPrefixedDBkey()] = true; 03978 } 03979 } 03980 } 03981 03982 if ( $imageDBkey !== false ) { 03983 $badImages[$imageDBkey] = $exceptions; 03984 } 03985 } 03986 if ( $cacheable ) { 03987 $badImageCache = $badImages; 03988 } 03989 } 03990 03991 $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false; 03992 $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] ); 03993 wfProfileOut( __METHOD__ ); 03994 return $bad; 03995 } 03996 04004 function wfCanIPUseHTTPS( $ip ) { 04005 $canDo = true; 04006 wfRunHooks( 'CanIPUseHTTPS', array( $ip, &$canDo ) ); 04007 return !!$canDo; 04008 }