X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FGlobalFunctions.php;h=68d68657128519460ed9e4a6c4a5f2c51eca9e74;hb=48bbe8b848fd7021a0d32729b9c8c77038762fa1;hp=3053553074a2b0e1859b5f8f5d791168b09cc1a0;hpb=938a8eb347d1f14a726729390adbaa3e65ba1bfa;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 3053553074..68d6865712 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -8,10 +8,6 @@ if ( !defined( 'MEDIAWIKI' ) ) { die( "This file is part of MediaWiki, it is not a valid entry point" ); } -if ( !defined( 'MW_COMPILED' ) ) { - require_once( dirname( __FILE__ ) . '/normal/UtfNormalUtil.php' ); -} - // Hide compatibility functions from Doxygen /// @cond @@ -54,7 +50,7 @@ if( !function_exists( 'mb_strpos' ) ) { function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) { return Fallback::mb_strpos( $haystack, $needle, $offset, $encoding ); } - + } if( !function_exists( 'mb_strrpos' ) ) { @@ -89,6 +85,12 @@ if ( !function_exists( 'istainted' ) ) { function wfArrayDiff2( $a, $b ) { return array_udiff( $a, $b, 'wfArrayDiff2_cmp' ); } + +/** + * @param $a + * @param $b + * @return int + */ function wfArrayDiff2_cmp( $a, $b ) { if ( !is_array( $a ) ) { return strcmp( $a, $b ); @@ -107,6 +109,151 @@ function wfArrayDiff2_cmp( $a, $b ) { } } +/** + * Array lookup + * Returns an array where the values in the first array are replaced by the + * values in the second array with the corresponding keys + * + * @param $a Array + * @param $b Array + * @return array + */ +function wfArrayLookup( $a, $b ) { + return array_flip( array_intersect( array_flip( $a ), array_keys( $b ) ) ); +} + +/** + * Appends to second array if $value differs from that in $default + * + * @param $key String|Int + * @param $value Mixed + * @param $default Mixed + * @param $changed Array to alter + */ +function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) { + if ( is_null( $changed ) ) { + throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' ); + } + if ( $default[$key] !== $value ) { + $changed[$key] = $value; + } +} + +/** + * Backwards array plus for people who haven't bothered to read the PHP manual + * XXX: will not darn your socks for you. + * + * @param $array1 Array + * @param [$array2, [...]] Arrays + * @return Array + */ +function wfArrayMerge( $array1/* ... */ ) { + $args = func_get_args(); + $args = array_reverse( $args, true ); + $out = array(); + foreach ( $args as $arg ) { + $out += $arg; + } + return $out; +} + +/** + * Merge arrays in the style of getUserPermissionsErrors, with duplicate removal + * e.g. + * wfMergeErrorArrays( + * array( array( 'x' ) ), + * array( array( 'x', '2' ) ), + * array( array( 'x' ) ), + * array( array( 'y') ) + * ); + * returns: + * array( + * array( 'x', '2' ), + * array( 'x' ), + * array( 'y' ) + * ) + * @param varargs + * @return Array + */ +function wfMergeErrorArrays( /*...*/ ) { + $args = func_get_args(); + $out = array(); + foreach ( $args as $errors ) { + foreach ( $errors as $params ) { + # @todo FIXME: Sometimes get nested arrays for $params, + # which leads to E_NOTICEs + $spec = implode( "\t", $params ); + $out[$spec] = $params; + } + } + return array_values( $out ); +} + +/** + * Insert array into another array after the specified *KEY* + * + * @param $array Array: The array. + * @param $insert Array: The array to insert. + * @param $after Mixed: The key to insert after + * @return Array + */ +function wfArrayInsertAfter( $array, $insert, $after ) { + // Find the offset of the element to insert after. + $keys = array_keys( $array ); + $offsetByKey = array_flip( $keys ); + + $offset = $offsetByKey[$after]; + + // Insert at the specified offset + $before = array_slice( $array, 0, $offset + 1, true ); + $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true ); + + $output = $before + $insert + $after; + + return $output; +} + +/** + * Recursively converts the parameter (an object) to an array with the same data + * + * @param $objOrArray Object|Array + * @param $recursive Bool + * @return Array + */ +function wfObjectToArray( $objOrArray, $recursive = true ) { + $array = array(); + if( is_object( $objOrArray ) ) { + $objOrArray = get_object_vars( $objOrArray ); + } + foreach ( $objOrArray as $key => $value ) { + if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) { + $value = wfObjectToArray( $value ); + } + + $array[$key] = $value; + } + + return $array; +} + +/** + * Wrapper around array_map() which also taints variables + * + * @param $function Callback + * @param $input Array + * @return Array + */ +function wfArrayMap( $function, $input ) { + $ret = array_map( $function, $input ); + foreach ( $ret as $key => $value ) { + $taint = istainted( $input[$key] ); + if ( $taint ) { + taint( $ret[$key], $taint ); + } + } + return $ret; +} + /** * Get a random decimal value between 0 and 1, in a way * not likely to give duplicate values for any realistic @@ -147,6 +294,11 @@ function wfRandom() { */ function wfUrlencode( $s ) { static $needle; + if ( is_null( $s ) ) { + $needle = null; + return; + } + if ( is_null( $needle ) ) { $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' ); if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) || ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false ) ) { @@ -164,6 +316,313 @@ function wfUrlencode( $s ) { return $s; } +/** + * This function takes two arrays as input, and returns a CGI-style string, e.g. + * "days=7&limit=100". Options in the first array override options in the second. + * Options set to "" will not be output. + * + * @param $array1 Array ( String|Array ) + * @param $array2 Array ( String|Array ) + * @param $prefix String + * @return String + */ +function wfArrayToCGI( $array1, $array2 = null, $prefix = '' ) { + if ( !is_null( $array2 ) ) { + $array1 = $array1 + $array2; + } + + $cgi = ''; + foreach ( $array1 as $key => $value ) { + if ( $value !== '' ) { + if ( $cgi != '' ) { + $cgi .= '&'; + } + if ( $prefix !== '' ) { + $key = $prefix . "[$key]"; + } + if ( is_array( $value ) ) { + $firstTime = true; + foreach ( $value as $k => $v ) { + $cgi .= $firstTime ? '' : '&'; + if ( is_array( $v ) ) { + $cgi .= wfArrayToCGI( $v, null, $key . "[$k]" ); + } else { + $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v ); + } + $firstTime = false; + } + } else { + if ( is_object( $value ) ) { + $value = $value->__toString(); + } + $cgi .= urlencode( $key ) . '=' . urlencode( $value ); + } + } + } + return $cgi; +} + +/** + * This is the logical opposite of wfArrayToCGI(): it accepts a query string as + * its argument and returns the same string in array form. This allows compa- + * tibility with legacy functions that accept raw query strings instead of nice + * arrays. Of course, keys and values are urldecode()d. Don't try passing in- + * valid query strings, or it will explode. + * + * @param $query String: query string + * @return array Array version of input + */ +function wfCgiToArray( $query ) { + if ( isset( $query[0] ) && $query[0] == '?' ) { + $query = substr( $query, 1 ); + } + $bits = explode( '&', $query ); + $ret = array(); + foreach ( $bits as $bit ) { + if ( $bit === '' ) { + continue; + } + list( $key, $value ) = explode( '=', $bit ); + $key = urldecode( $key ); + $value = urldecode( $value ); + if ( strpos( $key, '[' ) !== false ) { + $keys = array_reverse( explode( '[', $key ) ); + $key = array_pop( $keys ); + $temp = $value; + foreach ( $keys as $k ) { + $k = substr( $k, 0, -1 ); + $temp = array( $k => $temp ); + } + if ( isset( $ret[$key] ) ) { + $ret[$key] = array_merge( $ret[$key], $temp ); + } else { + $ret[$key] = $temp; + } + } else { + $ret[$key] = $value; + } + } + return $ret; +} + +/** + * Append a query string to an existing URL, which may or may not already + * have query string parameters already. If so, they will be combined. + * + * @param $url String + * @param $query Mixed: string or associative array + * @return string + */ +function wfAppendQuery( $url, $query ) { + if ( is_array( $query ) ) { + $query = wfArrayToCGI( $query ); + } + if( $query != '' ) { + if( false === strpos( $url, '?' ) ) { + $url .= '?'; + } else { + $url .= '&'; + } + $url .= $query; + } + return $url; +} + +/** + * Expand a potentially local URL to a fully-qualified URL. Assumes $wgServer + * is correct. + * + * The meaning of the PROTO_* constants is as follows: + * PROTO_HTTP: Output a URL starting with http:// + * PROTO_HTTPS: Output a URL starting with https:// + * PROTO_RELATIVE: Output a URL starting with // (protocol-relative URL) + * PROTO_CURRENT: Output a URL starting with either http:// or https:// , depending on which protocol was used for the current incoming request + * + * @todo this won't work with current-path-relative URLs + * like "subdir/foo.html", etc. + * + * @param $url String: either fully-qualified or a local path + query + * @param $defaultProto Mixed: one of the PROTO_* constants. Determines the protocol to use if $url or $wgServer is protocol-relative + * @return string Fully-qualified URL + */ +function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) { + global $wgServer; + if ( $defaultProto === PROTO_CURRENT ) { + $defaultProto = WebRequest::detectProtocol() . '://'; + } + + // Analyze $wgServer to obtain its protocol + $bits = wfParseUrl( $wgServer ); + $serverHasProto = $bits && $bits['scheme'] != ''; + $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 ); + + if( substr( $url, 0, 2 ) == '//' ) { + return $defaultProtoWithoutSlashes . $url; + } elseif( substr( $url, 0, 1 ) == '/' ) { + // If $wgServer is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone + return ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $wgServer . $url; + } else { + return $url; + } +} + +/** + * Returns a regular expression of url protocols + * + * @param $includeProtocolRelative bool If false, remove '//' from the returned protocol list. + * DO NOT USE this directy, use wfUrlProtocolsWithoutProtRel() instead + * @return String + */ +function wfUrlProtocols( $includeProtocolRelative = true ) { + global $wgUrlProtocols; + + // Cache return values separately based on $includeProtocolRelative + static $retval = array( true => null, false => null ); + if ( !is_null( $retval[$includeProtocolRelative] ) ) { + return $retval[$includeProtocolRelative]; + } + + // Support old-style $wgUrlProtocols strings, for backwards compatibility + // with LocalSettings files from 1.5 + if ( is_array( $wgUrlProtocols ) ) { + $protocols = array(); + foreach ( $wgUrlProtocols as $protocol ) { + // Filter out '//' if !$includeProtocolRelative + if ( $includeProtocolRelative || $protocol !== '//' ) { + $protocols[] = preg_quote( $protocol, '/' ); + } + } + + $retval[$includeProtocolRelative] = implode( '|', $protocols ); + } else { + // Ignore $includeProtocolRelative in this case + // This case exists for pre-1.6 compatibility, and we can safely assume + // that '//' won't appear in a pre-1.6 config because protocol-relative + // URLs weren't supported until 1.18 + $retval[$includeProtocolRelative] = $wgUrlProtocols; + } + return $retval[$includeProtocolRelative]; +} + +/** + * Like wfUrlProtocols(), but excludes '//' from the protocol list. Use this if + * you need a regex that matches all URL protocols but does not match protocol- + * relative URLs + */ +function wfUrlProtocolsWithoutProtRel() { + return wfUrlProtocols( false ); +} + +/** + * parse_url() work-alike, but non-broken. Differences: + * + * 1) Does not raise warnings on bad URLs (just returns false) + * 2) Handles protocols that don't use :// (e.g., mailto: and news: , as well as protocol-relative URLs) correctly + * 3) Adds a "delimiter" element to the array, either '://', ':' or '//' (see (2)) + * + * @param $url String: a URL to parse + * @return Array: bits of the URL in an associative array, per PHP docs + */ +function wfParseUrl( $url ) { + global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php + + // Protocol-relative URLs are handled really badly by parse_url(). It's so bad that the easiest + // way to handle them is to just prepend 'http:' and strip the protocol out later + $wasRelative = substr( $url, 0, 2 ) == '//'; + if ( $wasRelative ) { + $url = "http:$url"; + } + wfSuppressWarnings(); + $bits = parse_url( $url ); + wfRestoreWarnings(); + // parse_url() returns an array without scheme for some invalid URLs, e.g. + // parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' ) + if ( !$bits || !isset( $bits['scheme'] ) ) { + return false; + } + + // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it + if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) { + $bits['delimiter'] = '://'; + } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) { + $bits['delimiter'] = ':'; + // parse_url detects for news: and mailto: the host part of an url as path + // We have to correct this wrong detection + if ( isset( $bits['path'] ) ) { + $bits['host'] = $bits['path']; + $bits['path'] = ''; + } + } else { + return false; + } + + /* Provide an empty host for eg. file:/// urls (see bug 28627) */ + if ( !isset( $bits['host'] ) ) { + $bits['host'] = ''; + + /* parse_url loses the third / for file:///c:/ urls (but not on variants) */ + if ( substr( $bits['path'], 0, 1 ) !== '/' ) { + $bits['path'] = '/' . $bits['path']; + } + } + + // If the URL was protocol-relative, fix scheme and delimiter + if ( $wasRelative ) { + $bits['scheme'] = ''; + $bits['delimiter'] = '//'; + } + return $bits; +} + +/** + * Make a URL index, appropriate for the el_index field of externallinks. + * + * @param $url String + * @return String + */ +function wfMakeUrlIndex( $url ) { + $bits = wfParseUrl( $url ); + + // Reverse the labels in the hostname, convert to lower case + // For emails reverse domainpart only + if ( $bits['scheme'] == 'mailto' ) { + $mailparts = explode( '@', $bits['host'], 2 ); + if ( count( $mailparts ) === 2 ) { + $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) ); + } else { + // No domain specified, don't mangle it + $domainpart = ''; + } + $reversedHost = $domainpart . '@' . $mailparts[0]; + } else { + $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) ); + } + // Add an extra dot to the end + // Why? Is it in wrong place in mailto links? + if ( substr( $reversedHost, -1, 1 ) !== '.' ) { + $reversedHost .= '.'; + } + // Reconstruct the pseudo-URL + $prot = $bits['scheme']; + $index = $prot . $bits['delimiter'] . $reversedHost; + // Leave out user and password. Add the port, path, query and fragment + if ( isset( $bits['port'] ) ) { + $index .= ':' . $bits['port']; + } + if ( isset( $bits['path'] ) ) { + $index .= $bits['path']; + } else { + $index .= '/'; + } + if ( isset( $bits['query'] ) ) { + $index .= '?' . $bits['query']; + } + if ( isset( $bits['fragment'] ) ) { + $index .= '#' . $bits['fragment']; + } + return $index; +} + /** * Sends a line to the debug log if enabled or, optionally, to a comment in output. * In normal operation this is a NOP. @@ -184,29 +643,57 @@ function wfDebug( $text, $logonly = false ) { static $cache = array(); // Cache of unoutputted messages $text = wfDebugTimer() . $text; - # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet - if ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' && !$wgDebugRawPage ) { + if ( !$wgDebugRawPage && wfIsDebugRawPage() ) { return; } if ( ( $wgDebugComments || $wgShowDebug ) && !$logonly ) { $cache[] = $text; - if ( isset( $wgOut ) && StubObject::isRealObject( $wgOut ) ) { + if ( isset( $wgOut ) && is_object( $wgOut ) ) { // add the message and any cached messages to the output array_map( array( $wgOut, 'debug' ), $cache ); $cache = array(); } } - if ( $wgDebugLogFile != '' && !$wgProfileOnly ) { - # Strip unprintables; they can switch terminal modes when binary data - # gets dumped, which is pretty annoying. - $text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $text ); - $text = $wgDebugLogPrefix . $text; - wfErrorLog( $text, $wgDebugLogFile ); + if ( wfRunHooks( 'Debug', array( $text, null /* no log group */ ) ) ) { + if ( $wgDebugLogFile != '' && !$wgProfileOnly ) { + # Strip unprintables; they can switch terminal modes when binary data + # gets dumped, which is pretty annoying. + $text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $text ); + $text = $wgDebugLogPrefix . $text; + wfErrorLog( $text, $wgDebugLogFile ); + } } } +/** + * Returns true if debug logging should be suppressed if $wgDebugRawPage = false + */ +function wfIsDebugRawPage() { + static $cache; + if ( $cache !== null ) { + return $cache; + } + # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet + if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' ) + || ( + isset( $_SERVER['SCRIPT_NAME'] ) + && substr( $_SERVER['SCRIPT_NAME'], -8 ) == 'load.php' + ) ) + { + $cache = true; + } else { + $cache = false; + } + return $cache; +} + +/** + * Get microsecond timestamps for debug logs + * + * @return string + */ function wfDebugTimer() { global $wgDebugTimestamps; if ( !$wgDebugTimestamps ) { @@ -226,6 +713,7 @@ function wfDebugTimer() { /** * Send a line giving PHP memory usage. + * * @param $exact Bool: print exact values instead of kilobytes (default: false) */ function wfDebugMem( $exact = false ) { @@ -258,7 +746,9 @@ function wfDebugLog( $logGroup, $text, $public = true ) { } else { $host = ''; } - wfErrorLog( "$time $host $wiki: $text", $wgDebugLogGroups[$logGroup] ); + if ( wfRunHooks( 'Debug', array( $text, $logGroup ) ) ) { + wfErrorLog( "$time $host $wiki: $text", $wgDebugLogGroups[$logGroup] ); + } } elseif ( $public === true ) { wfDebug( $text, true ); } @@ -266,6 +756,7 @@ function wfDebugLog( $logGroup, $text, $public = true ) { /** * Log for database errors + * * @param $text String: database error message. */ function wfLogDBError( $text ) { @@ -282,6 +773,9 @@ function wfLogDBError( $text ) { * * Can also log to TCP or UDP with the syntax udp://host:port/prefix. This will * send lines to the specified port, prefixed by the specified prefix and a space. + * + * @param $text String + * @param $file String filename */ function wfErrorLog( $text, $file ) { if ( substr( $file, 0, 4 ) == 'udp:' ) { @@ -342,49 +836,60 @@ function wfErrorLog( $text, $file ) { */ function wfLogProfilingData() { global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; - global $wgProfiler, $wgProfileLimit, $wgUser; + global $wgProfileLimit, $wgUser; + + $profiler = Profiler::instance(); + # Profiling must actually be enabled... - if( is_null( $wgProfiler ) ) { + if ( $profiler->isStub() ) { return; } - # Get total page request time + + // Get total page request time and only show pages that longer than + // $wgProfileLimit time (default is 0) $now = wfTime(); $elapsed = $now - $wgRequestTime; - # Only show pages that longer than $wgProfileLimit time (default is 0) - if( $elapsed <= $wgProfileLimit ) { + if ( $elapsed <= $wgProfileLimit ) { + return; + } + + $profiler->logData(); + + // Check whether this should be logged in the debug file. + if ( $wgDebugLogFile == '' || ( !$wgDebugRawPage && wfIsDebugRawPage() ) ) { return; } - $prof = wfGetProfilingOutput( $wgRequestTime, $elapsed ); + $forward = ''; - if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { + if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; } - if( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { + if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP']; } - if( !empty( $_SERVER['HTTP_FROM'] ) ) { + if ( !empty( $_SERVER['HTTP_FROM'] ) ) { $forward .= ' from ' . $_SERVER['HTTP_FROM']; } - if( $forward ) { + if ( $forward ) { $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; } - // Don't unstub $wgUser at this late stage just for statistics purposes - // FIXME: We can detect some anons even if it is not loaded. See User::getId() - if( $wgUser->mDataLoaded && $wgUser->isAnon() ) { + // Don't load $wgUser at this late stage just for statistics purposes + // @todo FIXME: We can detect some anons even if it is not loaded. See User::getId() + if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) { $forward .= ' anon'; } $log = sprintf( "%s\t%04.3f\t%s\n", gmdate( 'YmdHis' ), $elapsed, urldecode( $wgRequest->getRequestURL() . $forward ) ); - if ( $wgDebugLogFile != '' && ( $wgRequest->getVal( 'action' ) != 'raw' || $wgDebugRawPage ) ) { - wfErrorLog( $log . $prof, $wgDebugLogFile ); - } + + wfErrorLog( $log . $profiler->getOutput(), $wgDebugLogFile ); } /** * Check if the wiki read-only lock file is present. This can be used to lock * off editing functions, but doesn't guarantee that the database will not be * modified. + * * @return bool */ function wfReadOnly() { @@ -413,6 +918,7 @@ function wfReadOnlyReason() { /** * Return a Language object from $langcode + * * @param $langcode Mixed: either: * - a Language object * - code of the language to get the message for, if it is @@ -458,15 +964,15 @@ function wfGetLangObj( $langcode = false ) { } /** - * Use this instead of $wgContLang, when working with user interface. - * User interface is currently hard coded according to wiki content language - * in many ways, especially regarding to text direction. There is lots stuff - * to fix, hence this function to keep the old behaviour unless the global - * $wgBetterDirectionality is enabled (or removed when everything works). + * Old function when $wgBetterDirectionality existed + * Removed in core, kept in extensions for backwards compat. + * + * @deprecated since 1.18 + * @return Language */ function wfUILang() { - global $wgBetterDirectionality; - return wfGetLangObj( !$wgBetterDirectionality ); + global $wgLang; + return $wgLang; } /** @@ -491,8 +997,8 @@ function wfMessage( $key /*...*/) { * This function accepts multiple message keys and returns a message instance * for the first message which is non-empty. If all messages are empty then an * instance of the first message key is returned. - * Varargs: message keys - * @return \type{Message} + * @param varargs: message keys + * @return Message * @since 1.18 */ function wfMessageFallback( /*...*/ ) { @@ -509,18 +1015,25 @@ function wfMessageFallback( /*...*/ ) { * @param $key String: lookup key for the message, usually * defined in languages/Language.php * - * This function also takes extra optional parameters (not - * shown in the function definition), which can be used to - * insert variable text into the predefined message. + * Parameters to the message, which can be used to insert variable text into + * it, can be passed to this function in the following formats: + * - One per argument, starting at the second parameter + * - As an array in the second parameter + * These are not shown in the function definition. + * + * @return String */ function wfMsg( $key ) { $args = func_get_args(); array_shift( $args ); - return wfMsgReal( $key, $args, true ); + return wfMsgReal( $key, $args ); } /** * Same as above except doesn't transform the message + * + * @param $key String + * @return String */ function wfMsgNoTrans( $key ) { $args = func_get_args(); @@ -548,7 +1061,8 @@ function wfMsgNoTrans( $key ) { * order to, e.g., fix a link in every possible language. * * @param $key String: lookup key for the message, usually - * defined in languages/Language.php + * defined in languages/Language.php + * @return String */ function wfMsgForContent( $key ) { global $wgForceUIMsgAsContentMsg; @@ -565,6 +1079,9 @@ function wfMsgForContent( $key ) { /** * Same as above except doesn't transform the message + * + * @param $key String + * @return String */ function wfMsgForContentNoTrans( $key ) { global $wgForceUIMsgAsContentMsg; @@ -579,34 +1096,9 @@ function wfMsgForContentNoTrans( $key ) { return wfMsgReal( $key, $args, true, $forcontent, false ); } -/** - * Get a message from the language file, for the UI elements - */ -function wfMsgNoDB( $key ) { - $args = func_get_args(); - array_shift( $args ); - return wfMsgReal( $key, $args, false ); -} - -/** - * Get a message from the language file, for the content - */ -function wfMsgNoDBForContent( $key ) { - global $wgForceUIMsgAsContentMsg; - $args = func_get_args(); - array_shift( $args ); - $forcontent = true; - if( is_array( $wgForceUIMsgAsContentMsg ) && - in_array( $key, $wgForceUIMsgAsContentMsg ) ) - { - $forcontent = false; - } - return wfMsgReal( $key, $args, false, $forcontent ); -} - - /** * Really get a message + * * @param $key String: key to get. * @param $args * @param $useDB Boolean @@ -622,23 +1114,9 @@ function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform return $message; } -/** - * This function provides the message source for messages to be edited which are *not* stored in the database. - * - * @deprecated in 1.18; use wfMessage() - * @param $key String - */ -function wfMsgWeirdKey( $key ) { - $source = wfMsgGetKey( $key, false, true, false ); - if ( wfEmptyMsg( $key ) ) { - return ''; - } else { - return $source; - } -} - /** * Fetch a message string value, but don't replace any keys yet. + * * @param $key String * @param $useDB Bool * @param $langCode String: Code of the language to get the message for, or @@ -646,7 +1124,7 @@ function wfMsgWeirdKey( $key ) { * @param $transform Boolean: whether to parse magic words, etc. * @return string */ -function wfMsgGetKey( $key, $useDB, $langCode = false, $transform = true ) { +function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true ) { wfRunHooks( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) ); $cache = MessageCache::singleton(); @@ -701,7 +1179,7 @@ function wfMsgReplaceArgs( $message, $args ) { function wfMsgHtml( $key ) { $args = func_get_args(); array_shift( $args ); - return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key, true ) ), $args ); + return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key ) ), $args ); } /** @@ -716,10 +1194,12 @@ function wfMsgHtml( $key ) { * @return string */ function wfMsgWikiHtml( $key ) { - global $wgOut; $args = func_get_args(); array_shift( $args ); - return wfMsgReplaceArgs( $wgOut->parse( wfMsgGetKey( $key, true ), /* can't be set to false */ true ), $args ); + return wfMsgReplaceArgs( + MessageCache::singleton()->parse( wfMsgGetKey( $key ), null, + /* can't be set to false */ true, /* interface */ true )->getText(), + $args ); } /** @@ -736,13 +1216,12 @@ function wfMsgWikiHtml( $key ) { * content: fetch message for content language instead of interface * Also can accept a single associative argument, of the form 'language' => 'xx': * language: Language object or language code to fetch message for - * (overriden by content), its behaviour with parse, parseinline - * and parsemag is undefined. + * (overriden by content). * Behavior for conflicting options (e.g., parse+parseinline) is undefined. + * + * @return String */ function wfMsgExt( $key, $options ) { - global $wgOut; - $args = func_get_args(); array_shift( $args ); array_shift( $args ); @@ -780,16 +1259,17 @@ function wfMsgExt( $key, $options ) { $string = wfMsgReplaceArgs( $string, $args ); } + $messageCache = MessageCache::singleton(); if( in_array( 'parse', $options, true ) ) { - $string = $wgOut->parse( $string, true, !$forContent, $langCodeObj ); + $string = $messageCache->parse( $string, null, true, !$forContent, $langCodeObj )->getText(); } elseif ( in_array( 'parseinline', $options, true ) ) { - $string = $wgOut->parse( $string, true, !$forContent, $langCodeObj ); + $string = $messageCache->parse( $string, null, true, !$forContent, $langCodeObj )->getText(); $m = array(); if( preg_match( '/^

(.*)\n?<\/p>\n?$/sU', $string, $m ) ) { $string = $m[1]; } } elseif ( in_array( 'parsemag', $options, true ) ) { - $string = MessageCache::singleton()->transform( $string, + $string = $messageCache->transform( $string, !$forContent, $langCodeObj ); } @@ -806,65 +1286,16 @@ function wfMsgExt( $key, $options ) { return $string; } - /** - * Just like exit() but makes a note of it. - * Commits open transactions except if the error parameter is set + * Since wfMsg() and co suck, they don't return false if the message key they + * looked up didn't exist but a XHTML string, this function checks for the + * nonexistance of messages by checking the MessageCache::get() result directly. * - * @deprecated Please return control to the caller or throw an exception. Will - * be removed in 1.19. - */ -function wfAbruptExit( $error = false ) { - static $called = false; - if ( $called ) { - exit( -1 ); - } - $called = true; - - wfDeprecated( __FUNCTION__ ); - $bt = wfDebugBacktrace(); - if( $bt ) { - for( $i = 0; $i < count( $bt ); $i++ ) { - $file = isset( $bt[$i]['file'] ) ? $bt[$i]['file'] : 'unknown'; - $line = isset( $bt[$i]['line'] ) ? $bt[$i]['line'] : 'unknown'; - wfDebug( "WARNING: Abrupt exit in $file at line $line\n"); - } - } else { - wfDebug( "WARNING: Abrupt exit\n" ); - } - - wfLogProfilingData(); - - if ( !$error ) { - wfGetLB()->closeAll(); - } - exit( -1 ); -} - -/** - * @deprecated Please return control the caller or throw an exception. Will - * be removed in 1.19. - */ -function wfErrorExit() { - wfDeprecated( __FUNCTION__ ); - wfAbruptExit( true ); -} - -/** - * Print an error message and die, returning nonzero to the shell if any. Plain die() - * fails to return nonzero to the shell if you pass a string. Entry points may customise - * this function to return a prettier error message, but implementations must not assume - * access to any of the usual MediaWiki infrastructure (AutoLoader, localisation, database, - * etc). This should not be called directly once $wgFullyInitialised is set; instead, - * throw an exception and let Exception.php handle whether or not it's possible to show - * a prettier error. - * @param $msg String + * @param $key String: the message key looked up + * @return Boolean True if the message *doesn't* exist. */ -if( !function_exists( 'wfDie' ) ){ - function wfDie( $msg = '' ) { - echo $msg; - die( 1 ); - } +function wfEmptyMsg( $key ) { + return MessageCache::singleton()->get( $key, /*useDB*/true, /*content*/false ) === false; } /** @@ -881,6 +1312,7 @@ function wfDebugDieBacktrace( $msg = '' ) { * Fetch server name for use in error reporting etc. * Use real server name if available, so we know which machine * in a server farm generated the current page. + * * @return string */ function wfHostname() { @@ -888,7 +1320,7 @@ function wfHostname() { if ( is_null( $host ) ) { if ( function_exists( 'posix_uname' ) ) { // This function not present on Windows - $uname = @posix_uname(); + $uname = posix_uname(); } else { $uname = false; } @@ -908,6 +1340,7 @@ function wfHostname() { /** * Returns a HTML comment with the elapsed time since request. * This method has no side effects. + * * @return string */ function wfReportTime() { @@ -934,7 +1367,7 @@ function wfReportTime() { * * @return array of backtrace information */ -function wfDebugBacktrace() { +function wfDebugBacktrace( $limit = 0 ) { static $disabled = null; if( extension_loaded( 'Zend Optimizer' ) ) { @@ -956,9 +1389,18 @@ function wfDebugBacktrace() { return array(); } - return array_slice( debug_backtrace(), 1 ); + if ( $limit && version_compare( PHP_VERSION, '5.4.0', '>=' ) ) { + return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, 1 ), 1 ); + } else { + return array_slice( debug_backtrace(), 1 ); + } } +/** + * Get a debug backtrace as a string + * + * @return string + */ function wfBacktrace() { global $wgCommandLineMode; @@ -986,7 +1428,7 @@ function wfBacktrace() { $msg .= '

  • ' . $file . ' line ' . $line . ' calls '; } if( !empty( $call['class'] ) ) { - $msg .= $call['class'] . '::'; + $msg .= $call['class'] . $call['type']; } $msg .= $call['function'] . '()'; @@ -1005,12 +1447,61 @@ function wfBacktrace() { return $msg; } +/** + * Get the name of the function which called this function + * + * @param $level Int + * @return Bool|string + */ +function wfGetCaller( $level = 2 ) { + $backtrace = wfDebugBacktrace( $level ); + if ( isset( $backtrace[$level] ) ) { + return wfFormatStackFrame( $backtrace[$level] ); + } else { + $caller = 'unknown'; + } + return $caller; +} + +/** + * Return a string consisting of callers in the stack. Useful sometimes + * for profiling specific points. + * + * @param $limit The maximum depth of the stack frame to return, or false for + * the entire stack. + * @return String + */ +function wfGetAllCallers( $limit = 3 ) { + $trace = array_reverse( wfDebugBacktrace() ); + if ( !$limit || $limit > count( $trace ) - 1 ) { + $limit = count( $trace ) - 1; + } + $trace = array_slice( $trace, -$limit - 1, $limit ); + return implode( '/', array_map( 'wfFormatStackFrame', $trace ) ); +} + +/** + * Return a string representation of frame + * + * @param $frame Array + * @return Bool + */ +function wfFormatStackFrame( $frame ) { + return isset( $frame['class'] ) ? + $frame['class'] . '::' . $frame['function'] : + $frame['function']; +} + /* Some generic result counters, pulled out of SearchEngine */ /** * @todo document + * + * @param $offset Int + * @param $limit Int + * @return String */ function wfShowingResults( $offset, $limit ) { global $wgLang; @@ -1022,32 +1513,20 @@ function wfShowingResults( $offset, $limit ) { ); } -/** - * @todo document - */ -function wfShowingResultsNum( $offset, $limit, $num ) { - global $wgLang; - return wfMsgExt( - 'showingresultsnum', - array( 'parseinline' ), - $wgLang->formatNum( $limit ), - $wgLang->formatNum( $offset + 1 ), - $wgLang->formatNum( $num ) - ); -} - /** * Generate (prev x| next x) (20|50|100...) type links for paging + * * @param $offset String * @param $limit Integer * @param $link String * @param $query String: optional URL query parameter string * @param $atend Bool: optional param for specified if this is the last page + * @return String */ function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { global $wgLang; $fmtLimit = $wgLang->formatNum( $limit ); - // FIXME: Why on earth this needs one message for the text and another one for tooltip?? + // @todo FIXME: Why on earth this needs one message for the text and another one for tooltip? # Get prev/next link display text $prev = wfMsgExt( 'prevn', array( 'parsemag', 'escape' ), $fmtLimit ); $next = wfMsgExt( 'nextn', array( 'parsemag', 'escape' ), $fmtLimit ); @@ -1099,6 +1578,7 @@ function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { /** * Generate links for (20|50|100...) items-per-page links + * * @param $offset String * @param $limit Integer * @param $title Title @@ -1120,8 +1600,9 @@ function wfNumLink( $offset, $limit, $title, $query = '' ) { /** * @todo document - * @todo FIXME: we may want to blacklist some broken browsers + * @todo FIXME: We may want to blacklist some broken browsers * + * @param $force Bool * @return bool Whereas client accept gzip compression */ function wfClientAcceptsGzip( $force = false ) { @@ -1129,7 +1610,7 @@ function wfClientAcceptsGzip( $force = false ) { if ( $result === null || $force ) { $result = false; if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) { - # FIXME: we may want to blacklist some broken browsers + # @todo FIXME: We may want to blacklist some broken browsers $m = array(); if( preg_match( '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/', @@ -1153,8 +1634,8 @@ function wfClientAcceptsGzip( $force = false ) { * Obtain the offset and limit values from the request string; * used in special pages * - * @param $deflimit Default limit if none supplied - * @param $optionname Name of a user preference to check against + * @param $deflimit Int default limit if none supplied + * @param $optionname String Name of a user preference to check against * @return array * */ @@ -1170,6 +1651,7 @@ function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) { * As required by the callers, is not used. * * @param $text String: text to be escaped + * @return String */ function wfEscapeWikiText( $text ) { $text = strtr( "\n$text", array( @@ -1184,148 +1666,48 @@ function wfEscapeWikiText( $text ) { } /** - * @todo document - * @return float + * Get the current unix timetstamp with microseconds. Useful for profiling + * @return Float */ function wfTime() { - return microtime( true ); -} - -/** - * Sets dest to source and returns the original value of dest - * If source is NULL, it just returns the value, it doesn't set the variable - * If force is true, it will set the value even if source is NULL - */ -function wfSetVar( &$dest, $source, $force = false ) { - $temp = $dest; - if ( !is_null( $source ) || $force ) { - $dest = $source; - } - return $temp; -} - -/** - * As for wfSetVar except setting a bit - */ -function wfSetBit( &$dest, $bit, $state = true ) { - $temp = (bool)( $dest & $bit ); - if ( !is_null( $state ) ) { - if ( $state ) { - $dest |= $bit; - } else { - $dest &= ~$bit; - } - } - return $temp; -} - -/** - * This function takes two arrays as input, and returns a CGI-style string, e.g. - * "days=7&limit=100". Options in the first array override options in the second. - * Options set to "" will not be output. - */ -function wfArrayToCGI( $array1, $array2 = null ) { - if ( !is_null( $array2 ) ) { - $array1 = $array1 + $array2; - } - - $cgi = ''; - foreach ( $array1 as $key => $value ) { - if ( $value !== '' ) { - if ( $cgi != '' ) { - $cgi .= '&'; - } - if ( is_array( $value ) ) { - $firstTime = true; - foreach ( $value as $v ) { - $cgi .= ( $firstTime ? '' : '&') . - urlencode( $key . '[]' ) . '=' . - urlencode( $v ); - $firstTime = false; - } - } else { - if ( is_object( $value ) ) { - $value = $value->__toString(); - } - $cgi .= urlencode( $key ) . '=' . - urlencode( $value ); - } - } - } - return $cgi; -} - -/** - * This is the logical opposite of wfArrayToCGI(): it accepts a query string as - * its argument and returns the same string in array form. This allows compa- - * tibility with legacy functions that accept raw query strings instead of nice - * arrays. Of course, keys and values are urldecode()d. Don't try passing in- - * valid query strings, or it will explode. - * - * @param $query String: query string - * @return array Array version of input - */ -function wfCgiToArray( $query ) { - if( isset( $query[0] ) && $query[0] == '?' ) { - $query = substr( $query, 1 ); - } - $bits = explode( '&', $query ); - $ret = array(); - foreach( $bits as $bit ) { - if( $bit === '' ) { - continue; - } - list( $key, $value ) = explode( '=', $bit ); - $key = urldecode( $key ); - $value = urldecode( $value ); - $ret[$key] = $value; - } - return $ret; -} - -/** - * Append a query string to an existing URL, which may or may not already - * have query string parameters already. If so, they will be combined. - * - * @param $url String - * @param $query Mixed: string or associative array - * @return string - */ -function wfAppendQuery( $url, $query ) { - if ( is_array( $query ) ) { - $query = wfArrayToCGI( $query ); - } - if( $query != '' ) { - if( false === strpos( $url, '?' ) ) { - $url .= '?'; - } else { - $url .= '&'; - } - $url .= $query; - } - return $url; + return microtime( true ); } /** - * Expand a potentially local URL to a fully-qualified URL. Assumes $wgServer - * and $wgProto are correct. + * Sets dest to source and returns the original value of dest + * If source is NULL, it just returns the value, it doesn't set the variable + * If force is true, it will set the value even if source is NULL * - * @todo this won't work with current-path-relative URLs - * like "subdir/foo.html", etc. + * @param $dest Mixed + * @param $source Mixed + * @param $force Bool + * @return Mixed + */ +function wfSetVar( &$dest, $source, $force = false ) { + $temp = $dest; + if ( !is_null( $source ) || $force ) { + $dest = $source; + } + return $temp; +} + +/** + * As for wfSetVar except setting a bit * - * @param $url String: either fully-qualified or a local path + query - * @return string Fully-qualified URL + * @param $dest Int + * @param $bit Int + * @param $state Bool */ -function wfExpandUrl( $url ) { - if( substr( $url, 0, 2 ) == '//' ) { - global $wgProto; - return $wgProto . ':' . $url; - } elseif( substr( $url, 0, 1 ) == '/' ) { - global $wgServer; - return $wgServer . $url; - } else { - return $url; +function wfSetBit( &$dest, $bit, $state = true ) { + $temp = (bool)( $dest & $bit ); + if ( !is_null( $state ) ) { + if ( $state ) { + $dest |= $bit; + } else { + $dest &= ~$bit; + } } + return $temp; } /** @@ -1335,6 +1717,9 @@ function wfExpandUrl( $url ) { * * Also fixes the locale problems on Linux in PHP 5.2.6+ (bug backported to * earlier distro releases of PHP) + * + * @param varargs + * @return String */ function wfEscapeShellArg( ) { wfInitShellLocale(); @@ -1392,6 +1777,12 @@ function wfEscapeShellArg( ) { /** * wfMerge attempts to merge differences between three texts. * Returns true for a clean merge and false for failure or a conflict. + * + * @param $old String + * @param $mine String + * @param $yours String + * @param $result String + * @return Bool */ function wfMerge( $old, $mine, $yours, &$result ) { global $wgDiff3; @@ -1461,6 +1852,7 @@ function wfMerge( $old, $mine, $yours, &$result ) { /** * Returns unified plain-text diff of two texts. * Useful for machine processing of diffs. + * * @param $before String: the text before the changes. * @param $after String: the text after the changes. * @param $params String: command-line options for the diff command. @@ -1538,7 +1930,7 @@ function wfDiff( $before, $after, $params = '-u' ) { function wfVarDump( $var ) { global $wgOut; $s = str_replace( "\n", "
    \n", var_export( $var, true ) . "\n" ); - if ( headers_sent() || !@is_object( $wgOut ) ) { + if ( headers_sent() || !isset( $wgOut ) || !is_object( $wgOut ) ) { print $s; } else { $wgOut->addHTML( $s ); @@ -1547,6 +1939,10 @@ function wfVarDump( $var ) { /** * Provide a simple HTTP error. + * + * @param $code Int|String + * @param $label String + * @param $desc String */ function wfHttpError( $code, $label, $desc ) { global $wgOut; @@ -1640,6 +2036,10 @@ function wfClearOutputBuffers() { /** * Converts an Accept-* header into an array mapping string values to quality * factors + * + * @param $accept String + * @param $def String default + * @return Array */ function wfAcceptToPrefs( $accept, $def = '*/*' ) { # No arg means accept anything (per HTTP spec) @@ -1652,13 +2052,13 @@ function wfAcceptToPrefs( $accept, $def = '*/*' ) { $parts = explode( ',', $accept ); foreach( $parts as $part ) { - # FIXME: doesn't deal with params like 'text/html; level=1' - @list( $value, $qpart ) = explode( ';', trim( $part ) ); + # @todo FIXME: Doesn't deal with params like 'text/html; level=1' + $values = explode( ';', trim( $part ) ); $match = array(); - if( !isset( $qpart ) ) { - $prefs[$value] = 1.0; - } elseif( preg_match( '/q\s*=\s*(\d*\.\d+)/', $qpart, $match ) ) { - $prefs[$value] = floatval( $match[1] ); + if ( count( $values ) == 1 ) { + $prefs[$values[0]] = 1.0; + } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) { + $prefs[$values[0]] = floatval( $match[1] ); } } @@ -1702,7 +2102,7 @@ function mimeTypeMatch( $type, $avail ) { * @param $sprefs Array: server's offered types * @return string * - * @todo FIXME: doesn't handle params like 'text/plain; charset=UTF-8' + * @todo FIXME: Doesn't handle params like 'text/plain; charset=UTF-8' * XXX: generalize to negotiate other stuff */ function wfNegotiateType( $cprefs, $sprefs ) { @@ -1741,28 +2141,10 @@ function wfNegotiateType( $cprefs, $sprefs ) { return $besttype; } -/** - * Array lookup - * Returns an array where the values in the first array are replaced by the - * values in the second array with the corresponding keys - * - * @return array - */ -function wfArrayLookup( $a, $b ) { - return array_flip( array_intersect( array_flip( $a ), array_keys( $b ) ) ); -} - -/** - * Convenience function; returns MediaWiki timestamp for the present time. - * @return string - */ -function wfTimestampNow() { - # return NOW - return wfTimestamp( TS_MW, time() ); -} - /** * Reference-counted warning suppression + * + * @param $end Bool */ function wfSuppressWarnings( $end = false ) { static $suppressCount = 0; @@ -1777,7 +2159,11 @@ function wfSuppressWarnings( $end = false ) { } } else { if ( !$suppressCount ) { - $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE ) ); + // E_DEPRECATED is undefined in PHP 5.2 + if( !defined( 'E_DEPRECATED' ) ){ + define( 'E_DEPRECATED', 8192 ); + } + $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED ) ); } ++$suppressCount; } @@ -1844,13 +2230,13 @@ define( 'TS_POSTGRES', 7 ); define( 'TS_DB2', 8 ); /** - * ISO 8601 basic format with no timezone: 19860209T200000Z - * - * This is used by ResourceLoader + * ISO 8601 basic format with no timezone: 19860209T200000Z. This is used by ResourceLoader */ define( 'TS_ISO_8601_BASIC', 9 ); /** + * Get a timestamp string in one of various formats + * * @param $outputtype Mixed: A timestamp in one of the supported formats, the * function will autodetect which format is supplied and act * accordingly. @@ -1908,8 +2294,6 @@ function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) { return false; } - - static $formats = array( TS_UNIX => 'U', TS_MW => 'YmdHis', @@ -1977,6 +2361,7 @@ function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) { /** * Return a formatted timestamp, or null if input is null. * For dealing with nullable timestamp columns in the database. + * * @param $outputtype Integer * @param $ts String * @return String @@ -1989,6 +2374,16 @@ function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) { } } +/** + * Convenience function; returns MediaWiki timestamp for the present time. + * + * @return string + */ +function wfTimestampNow() { + # return NOW + return wfTimestamp( TS_MW, time() ); +} + /** * Check if the operating system is Windows * @@ -2004,6 +2399,8 @@ function wfIsWindows() { /** * Check if we are running under HipHop + * + * @return Bool */ function wfIsHipHop() { return function_exists( 'hphp_thread_set_warmup_enabled' ); @@ -2011,6 +2408,9 @@ function wfIsHipHop() { /** * Swap two variables + * + * @param $x Mixed + * @param $y Mixed */ function swap( &$x, &$y ) { $z = $x; @@ -2018,15 +2418,6 @@ function swap( &$x, &$y ) { $y = $z; } -/** - * BC wrapper for MimeMagic::singleton() - * @deprecated No longer needed as of 1.17 (r68836). Remove in 1.19. - */ -function &wfGetMimeMagic() { - wfDeprecated( __FUNCTION__ ); - return MimeMagic::singleton(); -} - /** * Tries to get the system directory for temporary files. The TMPDIR, TMP, and * TEMP environment variables are then checked in sequence, and if none are set @@ -2092,6 +2483,9 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) { /** * Increment a statistics counter + * + * @param $key String + * @param $count Int */ function wfIncrStats( $key, $count = 1 ) { global $wgStatsMethod; @@ -2149,44 +2543,6 @@ function wfPercent( $nr, $acc = 2, $round = true ) { return $round ? round( $ret, $acc ) . '%' : "$ret%"; } -/** - * Encrypt a username/password. - * - * @param $userid Integer: ID of the user - * @param $password String: password of the user - * @return String: hashed password - * @deprecated Use User::crypt() or User::oldCrypt() instead - */ -function wfEncryptPassword( $userid, $password ) { - wfDeprecated(__FUNCTION__); - # Just wrap around User::oldCrypt() - return User::oldCrypt( $password, $userid ); -} - -/** - * Appends to second array if $value differs from that in $default - */ -function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) { - if ( is_null( $changed ) ) { - throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' ); - } - if ( $default[$key] !== $value ) { - $changed[$key] = $value; - } -} - -/** - * Since wfMsg() and co suck, they don't return false if the message key they - * looked up didn't exist but a XHTML string, this function checks for the - * nonexistance of messages by looking at wfMsg() output - * - * @param $key String: the message key looked up - * @return Boolean True if the message *doesn't* exist. - */ -function wfEmptyMsg( $key ) { - return MessageCache::singleton()->get( $key, /*useDB*/true, /*content*/false ) === false; -} - /** * Find out whether or not a mixed variable exists in a string * @@ -2198,42 +2554,25 @@ function wfEmptyMsg( $key ) { function in_string( $needle, $str, $insensitive = false ) { $func = 'strpos'; if( $insensitive ) $func = 'stripos'; - - return $func( $str, $needle ) !== false; -} -function wfSpecialList( $page, $details ) { - global $wgContLang; - $details = $details ? ' ' . $wgContLang->getDirMark() . "($details)" : ''; - return $page . $details; + return $func( $str, $needle ) !== false; } /** - * Returns a regular expression of url protocols + * Make a list item, used by various special pages * + * @param $page String Page link + * @param $details String Text between brackets + * @param $oppositedm Boolean Add the direction mark opposite to your + * language, to display text properly * @return String */ -function wfUrlProtocols() { - global $wgUrlProtocols; - - static $retval = null; - if ( !is_null( $retval ) ) { - return $retval; - } - - // Support old-style $wgUrlProtocols strings, for backwards compatibility - // with LocalSettings files from 1.5 - if ( is_array( $wgUrlProtocols ) ) { - $protocols = array(); - foreach ( $wgUrlProtocols as $protocol ) { - $protocols[] = preg_quote( $protocol, '/' ); - } - - $retval = implode( '|', $protocols ); - } else { - $retval = $wgUrlProtocols; - } - return $retval; +function wfSpecialList( $page, $details, $oppositedm = true ) { + global $wgLang; + $dirmark = ( $oppositedm ? $wgLang->getDirMark( true ) : '' ) . + $wgLang->getDirMark(); + $details = $details ? $dirmark . " ($details)" : ''; + return $page . $details; } /** @@ -2274,19 +2613,30 @@ function wfIniGetBool( $setting ) { * * @param $extension String A PHP extension. The file suffix (.so or .dll) * should be omitted + * @param $fileName String Name of the library, if not $extension.suffix * @return Bool - Whether or not the extension is loaded */ -function wfDl( $extension ) { +function wfDl( $extension, $fileName = null ) { if( extension_loaded( $extension ) ) { return true; } - $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' ) + $canDl = false; + $sapi = php_sapi_name(); + if( version_compare( PHP_VERSION, '5.3.0', '<' ) || + $sapi == 'cli' || $sapi == 'cgi' || $sapi == 'embed' ) + { + $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' ) && wfIniGetBool( 'enable_dl' ) && !wfIniGetBool( 'safe_mode' ) ); + } if( $canDl ) { + $fileName = $fileName ? $fileName : $extension; + if( wfIsWindows() ) { + $fileName = 'php_' . $fileName; + } wfSuppressWarnings(); - dl( $extension . '.' . PHP_SHLIB_SUFFIX ); + dl( $fileName . '.' . PHP_SHLIB_SUFFIX ); wfRestoreWarnings(); } return extension_loaded( $extension ); @@ -2446,203 +2796,72 @@ function wfUseMW( $req_ver ) { } /** - * Return the final portion of a pathname. - * Reimplemented because PHP5's basename() is buggy with multibyte text. - * http://bugs.php.net/bug.php?id=33898 - * - * PHP's basename() only considers '\' a pathchar on Windows and Netware. - * We'll consider it so always, as we don't want \s in our Unix paths either. - * - * @param $path String - * @param $suffix String: to remove if present - * @return String - */ -function wfBaseName( $path, $suffix = '' ) { - $encSuffix = ( $suffix == '' ) - ? '' - : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' ); - $matches = array(); - if( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) { - return $matches[1]; - } else { - return ''; - } -} - -/** - * Generate a relative path name to the given file. - * May explode on non-matching case-insensitive paths, - * funky symlinks, etc. - * - * @param $path String: absolute destination path including target filename - * @param $from String: Absolute source path, directory only - * @return String - */ -function wfRelativePath( $path, $from ) { - // Normalize mixed input on Windows... - $path = str_replace( '/', DIRECTORY_SEPARATOR, $path ); - $from = str_replace( '/', DIRECTORY_SEPARATOR, $from ); - - // Trim trailing slashes -- fix for drive root - $path = rtrim( $path, DIRECTORY_SEPARATOR ); - $from = rtrim( $from, DIRECTORY_SEPARATOR ); - - $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) ); - $against = explode( DIRECTORY_SEPARATOR, $from ); - - if( $pieces[0] !== $against[0] ) { - // Non-matching Windows drive letters? - // Return a full path. - return $path; - } - - // Trim off common prefix - while( count( $pieces ) && count( $against ) - && $pieces[0] == $against[0] ) { - array_shift( $pieces ); - array_shift( $against ); - } - - // relative dots to bump us to the parent - while( count( $against ) ) { - array_unshift( $pieces, '..' ); - array_shift( $against ); - } - - array_push( $pieces, wfBaseName( $path ) ); - - return implode( DIRECTORY_SEPARATOR, $pieces ); -} - -/** - * Backwards array plus for people who haven't bothered to read the PHP manual - * XXX: will not darn your socks for you. - * - * @param $array1 Array - * @param [$array2, [...]] Arrays - * @return Array - */ -function wfArrayMerge( $array1/* ... */ ) { - $args = func_get_args(); - $args = array_reverse( $args, true ); - $out = array(); - foreach ( $args as $arg ) { - $out += $arg; - } - return $out; -} - -/** - * Merge arrays in the style of getUserPermissionsErrors, with duplicate removal - * e.g. - * wfMergeErrorArrays( - * array( array( 'x' ) ), - * array( array( 'x', '2' ) ), - * array( array( 'x' ) ), - * array( array( 'y') ) - * ); - * returns: - * array( - * array( 'x', '2' ), - * array( 'x' ), - * array( 'y' ) - * ) - */ -function wfMergeErrorArrays( /*...*/ ) { - $args = func_get_args(); - $out = array(); - foreach ( $args as $errors ) { - foreach ( $errors as $params ) { - # FIXME: sometimes get nested arrays for $params, - # which leads to E_NOTICEs - $spec = implode( "\t", $params ); - $out[$spec] = $params; - } - } - return array_values( $out ); -} - -/** - * parse_url() work-alike, but non-broken. Differences: + * Return the final portion of a pathname. + * Reimplemented because PHP5's basename() is buggy with multibyte text. + * http://bugs.php.net/bug.php?id=33898 * - * 1) Does not raise warnings on bad URLs (just returns false) - * 2) Handles protocols that don't use :// (e.g., mailto: and news:) correctly - * 3) Adds a "delimiter" element to the array, either '://' or ':' (see (2)) + * PHP's basename() only considers '\' a pathchar on Windows and Netware. + * We'll consider it so always, as we don't want \s in our Unix paths either. * - * @param $url String: a URL to parse - * @return Array: bits of the URL in an associative array, per PHP docs + * @param $path String + * @param $suffix String: to remove if present + * @return String */ -function wfParseUrl( $url ) { - global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php - wfSuppressWarnings(); - $bits = parse_url( $url ); - wfRestoreWarnings(); - if ( !$bits ) { - return false; - } - - // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it - if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) { - $bits['delimiter'] = '://'; - } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) { - $bits['delimiter'] = ':'; - // parse_url detects for news: and mailto: the host part of an url as path - // We have to correct this wrong detection - if ( isset( $bits['path'] ) ) { - $bits['host'] = $bits['path']; - $bits['path'] = ''; - } +function wfBaseName( $path, $suffix = '' ) { + $encSuffix = ( $suffix == '' ) + ? '' + : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' ); + $matches = array(); + if( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) { + return $matches[1]; } else { - return false; + return ''; } - - return $bits; } /** - * Make a URL index, appropriate for the el_index field of externallinks. + * Generate a relative path name to the given file. + * May explode on non-matching case-insensitive paths, + * funky symlinks, etc. + * + * @param $path String: absolute destination path including target filename + * @param $from String: Absolute source path, directory only + * @return String */ -function wfMakeUrlIndex( $url ) { - $bits = wfParseUrl( $url ); +function wfRelativePath( $path, $from ) { + // Normalize mixed input on Windows... + $path = str_replace( '/', DIRECTORY_SEPARATOR, $path ); + $from = str_replace( '/', DIRECTORY_SEPARATOR, $from ); - // Reverse the labels in the hostname, convert to lower case - // For emails reverse domainpart only - if ( $bits['scheme'] == 'mailto' ) { - $mailparts = explode( '@', $bits['host'], 2 ); - if ( count( $mailparts ) === 2 ) { - $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) ); - } else { - // No domain specified, don't mangle it - $domainpart = ''; - } - $reversedHost = $domainpart . '@' . $mailparts[0]; - } else { - $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) ); - } - // Add an extra dot to the end - // Why? Is it in wrong place in mailto links? - if ( substr( $reversedHost, -1, 1 ) !== '.' ) { - $reversedHost .= '.'; - } - // Reconstruct the pseudo-URL - $prot = $bits['scheme']; - $index = $prot . $bits['delimiter'] . $reversedHost; - // Leave out user and password. Add the port, path, query and fragment - if ( isset( $bits['port'] ) ) { - $index .= ':' . $bits['port']; - } - if ( isset( $bits['path'] ) ) { - $index .= $bits['path']; - } else { - $index .= '/'; + // Trim trailing slashes -- fix for drive root + $path = rtrim( $path, DIRECTORY_SEPARATOR ); + $from = rtrim( $from, DIRECTORY_SEPARATOR ); + + $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) ); + $against = explode( DIRECTORY_SEPARATOR, $from ); + + if( $pieces[0] !== $against[0] ) { + // Non-matching Windows drive letters? + // Return a full path. + return $path; } - if ( isset( $bits['query'] ) ) { - $index .= '?' . $bits['query']; + + // Trim off common prefix + while( count( $pieces ) && count( $against ) + && $pieces[0] == $against[0] ) { + array_shift( $pieces ); + array_shift( $against ); } - if ( isset( $bits['fragment'] ) ) { - $index .= '#' . $bits['fragment']; + + // relative dots to bump us to the parent + while( count( $against ) ) { + array_unshift( $pieces, '..' ); + array_shift( $against ); } - return $index; + + array_push( $pieces, wfBaseName( $path ) ); + + return implode( DIRECTORY_SEPARATOR, $pieces ); } /** @@ -2714,7 +2933,7 @@ function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = t // Decode and validate input string $input = strtolower( $input ); for( $i = 0; $i < strlen( $input ); $i++ ) { - $n = strpos( $digitChars, $input{$i} ); + $n = strpos( $digitChars, $input[$i] ); if( $n === false || $n > $sourceBase ) { return false; } @@ -2768,11 +2987,13 @@ function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = t /** * Create an object with a given name and an array of construct parameters + * * @param $name String * @param $p Array: parameters - * @deprecated + * @deprecated since 1.18, warnings in 1.18, removal in 1.20 */ function wfCreateObject( $name, $p ) { + wfDeprecated( __FUNCTION__ ); return MWFunction::newObj( $name, $p ); } @@ -2792,19 +3013,22 @@ function wfHttpOnlySafe() { /** * Initialise php session + * + * @param $sessionId Bool */ function wfSetupSession( $sessionId = false ) { global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler; if( $wgSessionsInMemcached ) { if ( !defined( 'MW_COMPILED' ) ) { - require_once( 'MemcachedSessions.php' ); + global $IP; + require_once( "$IP/includes/cache/MemcachedSessions.php" ); } - session_set_save_handler( 'memsess_open', 'memsess_close', 'memsess_read', + session_set_save_handler( 'memsess_open', 'memsess_close', 'memsess_read', 'memsess_write', 'memsess_destroy', 'memsess_gc' ); - // It's necessary to register a shutdown function to call session_write_close(), - // because by the time the request shutdown function for the session module is + // It's necessary to register a shutdown function to call session_write_close(), + // because by the time the request shutdown function for the session module is // called, $wgMemc has already been destroyed. Shutdown functions registered // this way are called before object destruction. register_shutdown_function( 'memsess_write_close' ); @@ -2835,6 +3059,7 @@ function wfSetupSession( $sessionId = false ) { /** * Get an object from the precompiled serialized directory * + * @param $name String * @return Mixed: the variable on success, false on failure */ function wfGetPrecompiledData( $name ) { @@ -2850,43 +3075,11 @@ function wfGetPrecompiledData( $name ) { return false; } -function wfGetCaller( $level = 2 ) { - $backtrace = wfDebugBacktrace(); - if ( isset( $backtrace[$level] ) ) { - return wfFormatStackFrame( $backtrace[$level] ); - } else { - $caller = 'unknown'; - } - return $caller; -} - -/** - * Return a string consisting of callers in the stack. Useful sometimes - * for profiling specific points. - * - * @param $limit The maximum depth of the stack frame to return, or false for - * the entire stack. - */ -function wfGetAllCallers( $limit = 3 ) { - $trace = array_reverse( wfDebugBacktrace() ); - if ( !$limit || $limit > count( $trace ) - 1 ) { - $limit = count( $trace ) - 1; - } - $trace = array_slice( $trace, -$limit - 1, $limit ); - return implode( '/', array_map( 'wfFormatStackFrame', $trace ) ); -} - -/** - * Return a string representation of frame - */ -function wfFormatStackFrame( $frame ) { - return isset( $frame['class'] ) ? - $frame['class'] . '::' . $frame['function'] : - $frame['function']; -} - /** * Get a cache key + * + * @param varargs + * @return String */ function wfMemcKey( /*... */ ) { $args = func_get_args(); @@ -2897,6 +3090,11 @@ function wfMemcKey( /*... */ ) { /** * Get a cache key for a foreign DB + * + * @param $db String + * @param $prefix String + * @param varargs String + * @return String */ function wfForeignMemcKey( $db, $prefix /*, ... */ ) { $args = array_slice( func_get_args(), 2 ); @@ -2911,6 +3109,8 @@ function wfForeignMemcKey( $db, $prefix /*, ... */ ) { /** * Get an ASCII string identifying this wiki * This is used as a prefix in memcached keys + * + * @return String */ function wfWikiID() { global $wgDBprefix, $wgDBname; @@ -2923,6 +3123,9 @@ function wfWikiID() { /** * Split a wiki ID into DB name and table prefix + * + * @param $wiki String + * @param $bits String */ function wfSplitWikiID( $wiki ) { $bits = explode( '-', $wiki, 2 ); @@ -2934,6 +3137,7 @@ function wfSplitWikiID( $wiki ) { /** * Get a Database object. + * * @param $db Integer: index of the connection to get. May be DB_MASTER for the * master (for write queries), DB_SLAVE for potentially lagged read * queries, or an integer >= 0 for a particular server. @@ -2948,6 +3152,9 @@ function wfSplitWikiID( $wiki ) { * will always return the same object, unless the underlying connection or load * balancer is manually destroyed. * + * Note 2: use $this->getDB() in maintenance scripts that may be invoked by + * updater to ensure that a proper database is being updated. + * * @return DatabaseBase */ function &wfGetDB( $db, $groups = array(), $wiki = false ) { @@ -2966,6 +3173,7 @@ function wfGetLB( $wiki = false ) { /** * Get the load balancer factory object + * * @return LBFactory */ function &wfGetLBFactory() { @@ -2975,6 +3183,7 @@ function &wfGetLBFactory() { /** * Find a file. * Shortcut for RepoGroup::singleton()->findFile() + * * @param $title String or Title object * @param $options Associative array of options: * time: requested time for an archived image, or false for the @@ -2998,6 +3207,7 @@ function wfFindFile( $title, $options = array() ) { /** * Get an object referring to a locally registered file. * Returns a valid placeholder object if the file does not exist. + * * @param $title Title or String * @return File, or null if passed an invalid Title */ @@ -3005,6 +3215,14 @@ function wfLocalFile( $title ) { return RepoGroup::singleton()->getLocalRepo()->newFile( $title ); } +/** + * Stream a file to the browser. Back-compat alias for StreamFile::stream() + * @deprecated since 1.19 + */ +function wfStreamFile( $fname, $headers = array() ) { + StreamFile::stream( $fname, $headers ); +} + /** * Should low-performance queries be disabled? * @@ -3067,16 +3285,16 @@ function wfBoolToStr( $value ) { /** * Load an extension messages file - * @deprecated in 1.16, warnings in 1.18, remove in 1.20 + * + * @deprecated since 1.16, warnings in 1.18, remove in 1.20 * @codeCoverageIgnore */ -function wfLoadExtensionMessages( $extensionName, $langcode = false ) { +function wfLoadExtensionMessages() { wfDeprecated( __FUNCTION__ ); } /** - * Get a platform-independent path to the null file, e.g. - * /dev/null + * Get a platform-independent path to the null file, e.g. /dev/null * * @return string */ @@ -3088,6 +3306,7 @@ function wfGetNull() { /** * Throws a warning that $function is deprecated + * * @param $function String * @return null */ @@ -3104,32 +3323,33 @@ function wfDeprecated( $function ) { * $wgDevelopmentWarnings * * @param $msg String: message to send - * @param $callerOffset Integer: number of itmes to go back in the backtrace to + * @param $callerOffset Integer: number of items to go back in the backtrace to * find the correct caller (1 = function calling wfWarn, ...) * @param $level Integer: PHP error level; only used when $wgDevelopmentWarnings * is true */ function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) { + global $wgDevelopmentWarnings; + $callers = wfDebugBacktrace(); - if( isset( $callers[$callerOffset + 1] ) ){ + if ( isset( $callers[$callerOffset + 1] ) ) { $callerfunc = $callers[$callerOffset + 1]; $callerfile = $callers[$callerOffset]; - if( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) { + if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) { $file = $callerfile['file'] . ' at line ' . $callerfile['line']; } else { $file = '(internal function)'; } $func = ''; - if( isset( $callerfunc['class'] ) ) { + if ( isset( $callerfunc['class'] ) ) { $func .= $callerfunc['class'] . '::'; } - if( isset( $callerfunc['function'] ) ) { + if ( isset( $callerfunc['function'] ) ) { $func .= $callerfunc['function']; } $msg .= " [Called from $func in $file]"; } - global $wgDevelopmentWarnings; if ( $wgDevelopmentWarnings ) { trigger_error( $msg, $level ); } else { @@ -3138,44 +3358,35 @@ function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) { } /** - * Sleep until the worst slave's replication lag is less than or equal to - * $maxLag, in seconds. Use this when updating very large numbers of rows, as + * Modern version of wfWaitForSlaves(). Instead of looking at replication lag + * and waiting for it to go down, this waits for the slaves to catch up to the + * master position. Use this when updating very large numbers of rows, as * in maintenance scripts, to avoid causing too much lag. Of course, this is * a no-op if there are no slaves. * - * Every time the function has to wait for a slave, it will print a message to - * that effect (and then sleep for a little while), so it's probably not best - * to use this outside maintenance scripts in its present form. - * - * @param $maxLag Integer + * @param $maxLag Integer (deprecated) * @param $wiki mixed Wiki identifier accepted by wfGetLB * @return null */ -function wfWaitForSlaves( $maxLag, $wiki = false ) { - if( $maxLag ) { - $lb = wfGetLB( $wiki ); - list( $host, $lag ) = $lb->getMaxLag( $wiki ); - while( $lag > $maxLag ) { - wfSuppressWarnings(); - $name = gethostbyaddr( $host ); - wfRestoreWarnings(); - if( $name !== false ) { - $host = $name; - } - print "Waiting for $host (lagged $lag seconds)...\n"; - sleep( $maxLag ); - list( $host, $lag ) = $lb->getMaxLag(); - } +function wfWaitForSlaves( $maxLag = false, $wiki = false ) { + $lb = wfGetLB( $wiki ); + // bug 27975 - Don't try to wait for slaves if there are none + // Prevents permission error when getting master position + if ( $lb->getServerCount() > 1 ) { + $dbw = $lb->getConnection( DB_MASTER ); + $pos = $dbw->getMasterPos(); + $lb->waitForAll( $pos ); } } /** * Used to be used for outputting text in the installer/updater - * @deprecated Warnings in 1.19, removal in 1.20 + * @deprecated since 1.18, warnings in 1.18, remove in 1.20 */ function wfOut( $s ) { + wfDeprecated( __METHOD__ ); global $wgCommandLineMode; - if ( $wgCommandLineMode && !defined( 'MEDIAWIKI_INSTALL' ) ) { + if ( $wgCommandLineMode ) { echo $s; } else { echo htmlspecialchars( $s ); @@ -3206,6 +3417,7 @@ function wfCountDown( $n ) { * Generate a random 32-character hexadecimal token. * @param $salt Mixed: some sort of salt, if necessary, to add to random * characters before hashing. + * @return string * @codeCoverageIgnore */ function wfGenerateToken( $salt = '' ) { @@ -3215,7 +3427,9 @@ function wfGenerateToken( $salt = '' ) { /** * Replace all invalid characters with - + * * @param $name Mixed: filename to process + * @return String */ function wfStripIllegalFilenameChars( $name ) { global $wgIllegalFileChars; @@ -3230,47 +3444,9 @@ function wfStripIllegalFilenameChars( $name ) { return $name; } -/** - * Insert array into another array after the specified *KEY* - * @param $array Array: The array. - * @param $insert Array: The array to insert. - * @param $after Mixed: The key to insert after - */ -function wfArrayInsertAfter( $array, $insert, $after ) { - // Find the offset of the element to insert after. - $keys = array_keys( $array ); - $offsetByKey = array_flip( $keys ); - - $offset = $offsetByKey[$after]; - - // Insert at the specified offset - $before = array_slice( $array, 0, $offset + 1, true ); - $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true ); - - $output = $before + $insert + $after; - - return $output; -} - -/* Recursively converts the parameter (an object) to an array with the same data */ -function wfObjectToArray( $objOrArray, $recursive = true ) { - $array = array(); - if( is_object( $objOrArray ) ) { - $objOrArray = get_object_vars( $objOrArray ); - } - foreach ( $objOrArray as $key => $value ) { - if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) { - $value = wfObjectToArray( $value ); - } - - $array[$key] = $value; - } - - return $array; -} - /** * Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit; + * * @return Integer value memory was set to. */ function wfMemoryLimit() { @@ -3297,6 +3473,7 @@ function wfMemoryLimit() { /** * Converts shorthand byte notation to integer form + * * @param $string String * @return Integer */ @@ -3327,14 +3504,16 @@ function wfShorthandToInteger( $string = '' ) { /** * Get the normalised IETF language tag * See unit test for examples. + * * @param $code String: The language code. * @return $langCode String: The language code which complying with BCP 47 standards. */ function wfBCP47( $code ) { $codeSegment = explode( '-', $code ); + $codeBCP = array(); foreach ( $codeSegment as $segNo => $seg ) { if ( count( $codeSegment ) > 0 ) { - // when previous segment is x, it is a private segment and should be lc + // when previous segment is x, it is a private segment and should be lc if( $segNo > 0 && strtolower( $codeSegment[($segNo - 1)] ) == 'x') { $codeBCP[$segNo] = strtolower( $seg ); // ISO 3166 country code @@ -3356,43 +3535,53 @@ function wfBCP47( $code ) { return $langCode; } -function wfArrayMap( $function, $input ) { - $ret = array_map( $function, $input ); - foreach ( $ret as $key => $value ) { - $taint = istainted( $input[$key] ); - if ( $taint ) { - taint( $ret[$key], $taint ); - } - } - return $ret; -} - - /** * Get a cache object. - * @param integer $inputType Cache type, one the the CACHE_* constants. * + * @param $inputType integer Cache type, one the the CACHE_* constants. * @return BagOStuff */ function wfGetCache( $inputType ) { return ObjectCache::getInstance( $inputType ); } -/** Get the main cache object */ +/** + * Get the main cache object + * + * @return BagOStuff + */ function wfGetMainCache() { global $wgMainCacheType; return ObjectCache::getInstance( $wgMainCacheType ); } -/** Get the cache object used by the message cache */ +/** + * Get the cache object used by the message cache + * + * @return BagOStuff + */ function wfGetMessageCacheStorage() { global $wgMessageCacheType; return ObjectCache::getInstance( $wgMessageCacheType ); } -/** Get the cache object used by the parser cache */ +/** + * Get the cache object used by the parser cache + * + * @return BagOStuff + */ function wfGetParserCacheStorage() { global $wgParserCacheType; return ObjectCache::getInstance( $wgParserCacheType ); } +/** + * Call hook functions defined in $wgHooks + * + * @param $event String: event name + * @param $args Array: parameters passed to hook functions + * @return Boolean + */ +function wfRunHooks( $event, $args = array() ) { + return Hooks::run( $event, $args ); +}