= 3) { $end = func_get_arg(2); return join("",array_slice($ar[0],$start,$end)); } else { return join("",array_slice($ar[0],$start)); } } } /** * html_entity_decode exists in PHP 4.3.0+ but is FATALLY BROKEN even then, * with no UTF-8 support. * * @param string $string String having html entities * @param $quote_style * @param string $charset Encoding set to use (default 'ISO-8859-1') */ function do_html_entity_decode( $string, $quote_style=ENT_COMPAT, $charset='ISO-8859-1' ) { static $trans; if( !isset( $trans ) ) { $trans = array_flip( get_html_translation_table( HTML_ENTITIES, $quote_style ) ); # Assumes $charset will always be the same through a run, and only understands # utf-8 or default. Note - mixing latin1 named entities and unicode numbered # ones will result in a bad link. if( strcasecmp( 'utf-8', $charset ) == 0 ) { $trans = array_map( 'utf8_encode', $trans ); } } return strtr( $string, $trans ); } /** * Where as we got a random seed * @var bool $wgTotalViews */ $wgRandomSeeded = false; /** * Seed Mersenne Twister * Only necessary in PHP < 4.2.0 * * @return bool */ function wfSeedRandom() { global $wgRandomSeeded; if ( ! $wgRandomSeeded && version_compare( phpversion(), '4.2.0' ) < 0 ) { $seed = hexdec(substr(md5(microtime()),-8)) & 0x7fffffff; mt_srand( $seed ); $wgRandomSeeded = true; } } /** * Generates a URL from a URL-encoded title and a query string * Title::getLocalURL() is preferred in most cases * * @param string $a URL encoded title * @param string $q URL (default '') */ function wfLocalUrl( $a, $q = '' ) { global $wgServer, $wgScript, $wgArticlePath; $a = str_replace( ' ', '_', $a ); if ( '' == $a ) { if( '' == $q ) { $a = $wgScript; } else { $a = $wgScript.'?'.$q; } } else if ( '' == $q ) { $a = str_replace( '$1', $a, $wgArticlePath ); } else if ($wgScript != '' ) { $a = "{$wgScript}?title={$a}&{$q}"; } else { //XXX hackish solution for toplevel wikis $a = "/{$a}?{$q}"; } return $a; } /** * @todo document * @param string $a URL encoded title * @param string $q URL (default '') */ function wfLocalUrlE( $a, $q = '' ) { return htmlspecialchars( wfLocalUrl( $a, $q ) ); # die( "Call to obsolete function wfLocalUrlE()" ); } /** * We want / and : to be included as literal characters in our title URLs. * %2F in the page titles seems to fatally break for some reason. * * @param string $s * @return string */ function wfUrlencode ( $s ) { $s = urlencode( $s ); $s = preg_replace( '/%3[Aa]/', ':', $s ); $s = preg_replace( '/%2[Ff]/', '/', $s ); return $s; } /** * Return the UTF-8 sequence for a given Unicode code point. * Currently doesn't work for values outside the Basic Multilingual Plane. * * @param string $codepoint UTF-8 code point. * @return string HTML UTF-8 Entitie such as 'Ӓ'. */ function wfUtf8Sequence( $codepoint ) { if($codepoint < 0x80) return chr($codepoint); if($codepoint < 0x800) return chr($codepoint >> 6 & 0x3f | 0xc0) . chr($codepoint & 0x3f | 0x80); if($codepoint < 0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) . chr($codepoint >> 6 & 0x3f | 0x80) . chr($codepoint & 0x3f | 0x80); if($codepoint < 0x110000) return chr($codepoint >> 18 & 0x07 | 0xf0) . chr($codepoint >> 12 & 0x3f | 0x80) . chr($codepoint >> 6 & 0x3f | 0x80) . chr($codepoint & 0x3f | 0x80); # There should be no assigned code points outside this range, but... return "&#$codepoint;"; } /** * Converts numeric character entities to UTF-8 * * @param string $string String to convert. * @return string Converted string. */ function wfMungeToUtf8( $string ) { global $wgInputEncoding; # This is debatable #$string = iconv($wgInputEncoding, "UTF-8", $string); $string = preg_replace ( '/&#([0-9]+);/e', 'wfUtf8Sequence($1)', $string ); $string = preg_replace ( '/&#x([0-9a-f]+);/ie', 'wfUtf8Sequence(0x$1)', $string ); # Should also do named entities here return $string; } /** * Converts a single UTF-8 character into the corresponding HTML character * entity (for use with preg_replace_callback) * * @param array $matches * */ function wfUtf8Entity( $matches ) { $char = $matches[0]; # Find the length $z = ord( $char{0} ); if ( $z & 0x80 ) { $length = 0; while ( $z & 0x80 ) { $length++; $z <<= 1; } } else { $length = 1; } if ( $length != strlen( $char ) ) { return ''; } if ( $length == 1 ) { return $char; } # Mask off the length-determining bits and shift back to the original location $z &= 0xff; $z >>= $length; # Add in the free bits from subsequent bytes for ( $i=1; $i<$length; $i++ ) { $z <<= 6; $z |= ord( $char{$i} ) & 0x3f; } # Make entity return "&#$z;"; } /** * Converts all multi-byte characters in a UTF-8 string into the appropriate * character entity */ function wfUtf8ToHTML($string) { return preg_replace_callback( '/[\\xc0-\\xfd][\\x80-\\xbf]*/', 'wfUtf8Entity', $string ); } /** * @todo document */ function wfDebug( $text, $logonly = false ) { global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly, $wgDebugRawPage; # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet if ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' && !$wgDebugRawPage ) { return; } if ( isset( $wgOut ) && $wgDebugComments && !$logonly ) { $wgOut->debug( $text ); } if ( '' != $wgDebugLogFile && !$wgProfileOnly ) { error_log( $text, 3, $wgDebugLogFile ); } } /** * Log for database errors * @param string $text Database error message. */ function wfLogDBError( $text ) { global $wgDBerrorLog; if ( $wgDBerrorLog ) { $text = date('D M j G:i:s T Y') . "\t".$text; error_log( $text, 3, $wgDBerrorLog ); } } /** * @todo document */ function logProfilingData() { global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; global $wgProfiling, $wgProfileStack, $wgProfileLimit, $wgUser; $now = wfTime(); list( $usec, $sec ) = explode( ' ', $wgRequestTime ); $start = (float)$sec + (float)$usec; $elapsed = $now - $start; if ( $wgProfiling ) { $prof = wfGetProfilingOutput( $start, $elapsed ); $forward = ''; if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; if( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP']; if( !empty( $_SERVER['HTTP_FROM'] ) ) $forward .= ' from ' . $_SERVER['HTTP_FROM']; if( $forward ) $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; if($wgUser->getId() == 0) $forward .= ' anon'; $log = sprintf( "%s\t%04.3f\t%s\n", gmdate( 'YmdHis' ), $elapsed, urldecode( $_SERVER['REQUEST_URI'] . $forward ) ); if ( '' != $wgDebugLogFile && ( $wgRequest->getVal('action') != 'raw' || $wgDebugRawPage ) ) { error_log( $log . $prof, 3, $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() { global $wgReadOnlyFile; if ( '' == $wgReadOnlyFile ) { return false; } return is_file( $wgReadOnlyFile ); } /** * Keys strings for replacement * @global array $wgReplacementKeys */ $wgReplacementKeys = array( '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9' ); /** * Get a message from anywhere */ function wfMsg( $key ) { global $wgRequest; if ( $wgRequest->getVal( 'debugmsg' ) ) { if ( $key == 'linktrail' /* a special case where we want to return something specific */ ) return "/^()(.*)$/sD"; else return $key; } $args = func_get_args(); if ( count( $args ) ) { array_shift( $args ); } return wfMsgReal( $key, $args, true ); } /** * Get a message from anywhere, but don't call Language::convert */ function wfMsgNoConvert( $key ) { global $wgRequest; if ( $wgRequest->getVal( 'debugmsg' ) ) { if ( $key == 'linktrail' /* a special case where we want to return something specific */ ) return "/^()(.*)$/sD"; else return $key; } $args = func_get_args(); if ( count( $args ) ) { array_shift( $args ); } return wfMsgReal( $key, $args, true, false ); } /** * Get a message from the language file */ function wfMsgNoDB( $key ) { $args = func_get_args(); if ( count( $args ) ) { array_shift( $args ); } return wfMsgReal( $key, $args, false ); } /** * Get a message from the language file, but don't call Language::convert */ function wfMsgNoDBNoConvert( $key ) { $args = func_get_args(); if ( count( $args ) ) { array_shift( $args ); } return wfMsgReal( $key, $args, false, false ); } /** * Really get a message */ function wfMsgReal( $key, $args, $useDB, $convert=true ) { global $wgReplacementKeys, $wgMessageCache, $wgLang; $fname = 'wfMsg'; wfProfileIn( $fname ); if ( $wgMessageCache ) { $message = $wgMessageCache->get( $key, $useDB ); } elseif ( $wgLang ) { $message = $wgLang->getMessage( $key ); } else { wfDebug( "No language object when getting $key\n" ); $message = "<$key>"; } if ( $convert ) { $message = $wgLang->convert($message); } # Replace arguments if( count( $args ) ) { $message = str_replace( $wgReplacementKeys, $args, $message ); } wfProfileOut( $fname ); return $message; } /** * Just like exit() but makes a note of it. * Commits open transactions except if the error parameter is set */ function wfAbruptExit( $error = false ){ global $wgLoadBalancer; static $called = false; if ( $called ){ exit(); } $called = true; if( function_exists( 'debug_backtrace' ) ){ // PHP >= 4.3 $bt = debug_backtrace(); for($i = 0; $i < count($bt) ; $i++){ $file = $bt[$i]['file']; $line = $bt[$i]['line']; wfDebug("WARNING: Abrupt exit in $file at line $line\n"); } } else { wfDebug('WARNING: Abrupt exit\n'); } if ( !$error ) { $wgLoadBalancer->closeAll(); } exit(); } /** * @todo document */ function wfErrorExit() { wfAbruptExit( true ); } /** * Die with a backtrace * This is meant as a debugging aid to track down where bad data comes from. * Shouldn't be used in production code except maybe in "shouldn't happen" areas. * * @param string $msg Message shown when dieing. */ function wfDebugDieBacktrace( $msg = '' ) { global $wgCommandLineMode; if ( function_exists( 'debug_backtrace' ) ) { if ( $wgCommandLineMode ) { $msg .= "\nBacktrace:\n"; } else { $msg .= "\n

Backtrace:

\n