From ee4c7f2f4916d043c0710242f72899aa44d23dde Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Sun, 2 Nov 2003 13:57:24 +0000 Subject: [PATCH] Various fixes, see the version of [[m:Development status]] before this commit for details --- docs/memcached.doc | 4 +-- includes/Article.php | 21 ++++++++--- includes/DatabaseFunctions.php | 6 ++++ includes/GlobalFunctions.php | 57 +++++++++++++++++++++--------- includes/MagicWord.php | 2 +- includes/OutputPage.php | 35 ++++++++++++++---- includes/Profiling.php | 18 ++++++---- languages/Language.php | 8 +++++ maintenance/InitialiseMessages.php | 2 +- maintenance/rebuildlinks.inc | 44 +++++++++++------------ 10 files changed, 138 insertions(+), 59 deletions(-) diff --git a/docs/memcached.doc b/docs/memcached.doc index 93e402d336..eba62ca14c 100644 --- a/docs/memcached.doc +++ b/docs/memcached.doc @@ -113,6 +113,6 @@ MediaWiki namespace: key: $wgDBname:messages ex: wikidb:messages stores: an array where the keys are DB keys and the values are messages - set in: wfMsg() - cleared by: Article::editUpdates() + set in: wfMsg(), Article::editUpdates() both call wfLoadAllMessages() + cleared by: nothing ... more to come ... diff --git a/includes/Article.php b/includes/Article.php index 43fda886ee..4c6d3b5c12 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -97,6 +97,7 @@ class Article { $t = $this->mTitle->getPrefixedText(); if ( $oldid ) { $t .= ",oldid={$oldid}"; } if ( $redirect ) { $t .= ",redirect={$redirect}"; } + $this->mContent = str_replace( "$1", $t, wfMsg( "missingarticle" ) ); if ( ! $oldid ) { # Retrieve current version @@ -106,11 +107,13 @@ class Article { $sql = "SELECT " . "cur_text,cur_timestamp,cur_user,cur_counter,cur_restrictions,cur_touched " . "FROM cur WHERE cur_id={$id}"; + wfDebug( "$sql\n" ); $res = wfQuery( $sql, DB_READ, $fname ); - if ( 0 == wfNumRows( $res ) ) { return; } + if ( 0 == wfNumRows( $res ) ) { + return; + } $s = wfFetchObject( $res ); - # If we got a redirect, follow it (unless we've been told # not to by either the function parameter or the query if ( ( "no" != $redirect ) && ( false == $noredir ) && @@ -146,6 +149,7 @@ class Article { } } } + $this->mContent = $s->cur_text; $this->mUser = $s->cur_user; $this->mCounter = $s->cur_counter; @@ -989,7 +993,12 @@ class Article { array_push( $wgDeferredUpdateList, $u ); if ( $this->getNamespace == NS_MEDIAWIKI ) { - $wgMemc->delete( "$wgDBname:messages" ); + $messageCache = $wgMemc->get( "$wgDBname:messages" ); + if (!$messageCache) { + $messageCache = wfLoadAllMessages(); + } + $messageCache[$title] = $text; + $wgMemc->set( "$wgDBname:messages" ); } } } @@ -1074,7 +1083,7 @@ class Article { # {{SUBST:xxx}} variables # $mw =& MagicWord::get( MAG_SUBST ); - $text = $mw->substituteCallback( $text, "replaceMsgVar" ); + $text = $mw->substituteCallback( $text, "wfReplaceSubstVar" ); return $text; } @@ -1131,4 +1140,8 @@ class Article { } +function wfReplaceSubstVar( $matches ) { + return wfMsg( $matches[1] ); +} + ?> diff --git a/includes/DatabaseFunctions.php b/includes/DatabaseFunctions.php index cdee2564ea..2d74af4b62 100644 --- a/includes/DatabaseFunctions.php +++ b/includes/DatabaseFunctions.php @@ -97,6 +97,12 @@ function wfQuery( $sql, $db, $fname = "" ) { global $wgLastDatabaseQuery, $wgOut; ## wfProfileIn( "wfQuery" ); + + if ( !is_numeric( $db ) ) { + # Someone has tried to call this the old way + $wgOut->fatalError( wfMsgNoDB( "wrong_wfQuery_params" ) ); + } + $wgLastDatabaseQuery = $sql; $conn = wfGetDB(); $ret = mysql_query( $sql, $conn ); diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 32175884eb..42dd1a10ee 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -150,6 +150,7 @@ function wfReadOnly() $wgReplacementKeys = array( "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9" ); +# Get a message from anywhere function wfMsg( $key ) { $args = func_get_args(); if ( count( $args ) ) { @@ -158,6 +159,7 @@ function wfMsg( $key ) { return wfMsgReal( $key, $args, true ); } +# Get a message from the language file function wfMsgNoDB( $key ) { $args = func_get_args(); if ( count( $args ) ) { @@ -166,10 +168,11 @@ function wfMsgNoDB( $key ) { return wfMsgReal( $key, $args, false ); } +# Really get a message function wfMsgReal( $key, $args, $useDB ) { global $wgLang, $wgReplacementKeys, $wgMemc, $wgDBname; global $wgUseDatabaseMessages, $wgUseMemCached, $wgOut; - global $wgAllMessagesEn; + global $wgAllMessagesEn, $wgLanguageCode; $fname = "wfMsg"; wfProfileIn( $fname ); @@ -194,17 +197,16 @@ function wfMsgReal( $key, $args, $useDB ) { } # If there's nothing in memcached, load all the messages from the database + # This should only happen on server reset -- ordinary changes should update + # memcached in editUpdates() if ( !$messageCache ) { # Other threads don't need to load the messages if another thread is doing it. $wgMemc->set( $memcKey, "loading", time() + 60 ); - - $sql = "SELECT cur_title,cur_text FROM cur WHERE cur_namespace=" . NS_MEDIAWIKI; - $res = wfQuery( $sql, DB_READ, $fname ); - for ( $row = wfFetchObject( $res ); $row; $row = wfFetchObject( $res ) ) { - $messageCache[$row->cur_title] = $row->cur_text; - } + $messageCache = wfLoadAllMessages(); # Save in memcached $wgMemc->set( $memcKey, $messageCache, time() + 3600 ); + + } if ( is_array( $messageCache ) && array_key_exists( $title, $messageCache ) ) { $message = $messageCache[$title]; @@ -226,10 +228,15 @@ function wfMsgReal( $key, $args, $useDB ) { } } - # Finally, try the array in $wgLang + # Try the array in $wgLang if ( !$message ) { $message = $wgLang->getMessage( $key ); } + + # Try the English array + if ( !$message && $wgLanguageCode != "en" ) { + $message = Language::getMessage( $key ); + } # Replace arguments if( count( $args ) ) { @@ -237,7 +244,7 @@ function wfMsgReal( $key, $args, $useDB ) { } wfProfileOut( $fname ); if ( !$message ) { - # Failed, message not translated + # Failed, message does not exist return "<$key>"; } return $message; @@ -620,14 +627,32 @@ function wfCheckLimits( $deflimit = 50, $optionname = "rclimit" ) { return array( $limit, $offset ); } -# Used in OutputPage::replaceVariables and Article:pstPass2 -function replaceMsgVar( $matches ) { - return wfMsg( $matches[1] ); -} - -function replaceMsgVarNw( $matches ) { - $text = htmlspecialchars( wfMsg( $matches[1] ) ); +# Escapes the given text so that it may be output using addWikiText() +# without any linking, formatting, etc. making its way through. This +# is achieved by substituting certain characters with HTML entities. +# As required by the callers, is not used. It currently does +# not filter out characters which have special meaning only at the +# start of a line, such as "*". +function wfEscapeWikiText( $text ) +{ + $text = str_replace( + array( '[', "'", 'ISBN ' , '://'), + array( '[', ''', 'ISBN ', '://'), + htmlspecialchars($text) ); return $text; } +# Loads the entire MediaWiki namespace, retuns the array +function wfLoadAllMessages() +{ + $sql = "SELECT cur_title,cur_text FROM cur WHERE cur_namespace=" . NS_MEDIAWIKI; + $res = wfQuery( $sql, DB_READ, $fname ); + + $messages = array(); + for ( $row = wfFetchObject( $res ); $row; $row = wfFetchObject( $res ) ) { + $messages[$row->cur_title] = $row->cur_text; + } + wfFreeResult( $res ); + return $messages; +} ?> diff --git a/includes/MagicWord.php b/includes/MagicWord.php index b8d39da1e2..91bc2c43f1 100644 --- a/includes/MagicWord.php +++ b/includes/MagicWord.php @@ -54,7 +54,7 @@ class MagicWord { $case = $this->mCaseSensitive ? "" : "i"; $this->mRegex = "/{$this->mBaseRegex}/{$case}"; $this->mRegexStart = "/^{$this->mBaseRegex}/{$case}"; - $this->mVariableRegex = str_replace( "\\$1", "([A-Za-z0-9]*)", $this->mRegex ); + $this->mVariableRegex = str_replace( "\\$1", "([A-Za-z0-9_\-]*)", $this->mRegex ); } function getRegex() diff --git a/includes/OutputPage.php b/includes/OutputPage.php index adc63df86e..995187da8a 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -938,7 +938,6 @@ $t[] = "" ; else { # Invalid form; output directly $s .= "[[" . $line ; - wfProfileOut( "$fname-loop1" ); continue; } if(substr($m[1],0,1)=="/") { # subpage @@ -1203,8 +1202,12 @@ $t[] = "" ; $fname = "OutputPage::replaceVariables"; wfProfileIn( $fname ); - /* As with sigs, use server's local time -- - ensure this is appropriate for your audience! */ + + # Basic variables + # See Language.php for the definition of each magic word + + # As with sigs, this uses the server's local time -- ensure + # this is appropriate for your audience! $v = date( "m" ); $mw =& MagicWord::get( MAG_CURRENTMONTH ); $text = $mw->replace( $v, $text ); @@ -1239,17 +1242,19 @@ $t[] = "" ; $text = $mw->replace( $v, $text ); } - # The callbacks are in GlobalFunctions.php + # "Variables" with an additional parameter e.g. {{MSG:wikipedia}} + # The callbacks are at the bottom of this file $mw =& MagicWord::get( MAG_MSG ); - $text = $mw->substituteCallback( $text, "replaceMsgVar" ); + $text = $mw->substituteCallback( $text, "wfReplaceMsgVar" ); $mw =& MagicWord::get( MAG_MSGNW ); - $text = $mw->substituteCallback( $text, "replaceMsgVarNw" ); + $text = $mw->substituteCallback( $text, "wfReplaceMsgnwVar" ); wfProfileOut( $fname ); return $text; } + # Cleans up HTML, removes dangerous tags and attributes /* private */ function removeHTMLtags( $text ) { $fname = "OutputPage::removeHTMLtags"; @@ -1576,4 +1581,22 @@ $t[] = "" ; } } +# Regex callbacks, used in OutputPage::replaceVariables + +# Just get rid of the dangerous stuff +# Necessary because replaceVariables is called after removeHTMLtags, +# and message text can come from any user +function wfReplaceMsgVar( $matches ) { + global $wgOut; + $text = $wgOut->removeHTMLtags( wfMsg( $matches[1] ) ); + return $text; +} + +# Effective +# Not real because this is called after nowiki sections are processed +function wfReplaceMsgnwVar( $matches ) { + $text = wfEscapeWikiText( wfMsg( $matches[1] ) ); + return $text; +} + ?> diff --git a/includes/Profiling.php b/includes/Profiling.php index ee82e4f121..7be7028b64 100755 --- a/includes/Profiling.php +++ b/includes/Profiling.php @@ -48,15 +48,19 @@ class Profiler global $wgDebugProfiling; $bit = array_pop( $this->mWorkStack ); - if ( $wgDebugProfiling ) { - if ( $functionname == "close" ) { - wfDebug( "Profile section ended by close(): {$bit[0]}\n" ); - } elseif ( $bit[0] != $functionname ) { - wfDebug( "Profiling error: in({$bit[0]}), out($functionname)\n" ); + if ( !$bit ) { + wfDebug( "Profiling error, !\$bit: $functionname\n" ); + } else { + if ( $wgDebugProfiling ) { + if ( $functionname == "close" ) { + wfDebug( "Profile section ended by close(): {$bit[0]}\n" ); + } elseif ( $bit[0] != $functionname ) { + wfDebug( "Profiling error: in({$bit[0]}), out($functionname)\n" ); + } } + array_push( $bit, microtime() ); + array_push( $this->mStack, $bit ); } - array_push( $bit, microtime() ); - array_push( $this->mStack, $bit ); } function close() diff --git a/languages/Language.php b/languages/Language.php index 6cf4f84574..9897a81e4b 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -349,6 +349,13 @@ this (alternative: like this?).", "Debug" => "Debugging information" ); +#------------------------------------------------------------------- +# Default messages +#------------------------------------------------------------------- +# Allowed characters in keys are: A-Z, a-z, 0-9, underscore (_) and +# hyphen (-). If you need more characters, you may be able to change +# the regex in MagicWord::initRegex + /* private */ $wgAllMessagesEn = array( # Bits of text used by many pages: @@ -496,6 +503,7 @@ an incorrectly linked inter-language or inter-wiki title.", because it slows the database down to the point that no one can use the wiki.", "perfdisabledsub" => "Here's a saved copy from $1:", +"wrong_wfQuery_params" => "Incorrect parameters to wfQuery", # Login and logout pages # diff --git a/maintenance/InitialiseMessages.php b/maintenance/InitialiseMessages.php index fcd8e907a6..1851834e7a 100644 --- a/maintenance/InitialiseMessages.php +++ b/maintenance/InitialiseMessages.php @@ -64,7 +64,7 @@ function getAllMessages() $mw = $mwObj->getSynonym( 0 ); $mw = str_replace( "$1", $key, $mw ); - $message = htmlspecialchars( $message ); + $message = wfEscapeWikiText( $message ); $navText .= " [$wgServer$wgScript?title=MediaWiki:$title&action=edit $key] diff --git a/maintenance/rebuildlinks.inc b/maintenance/rebuildlinks.inc index 7dd3ddee50..0c7169fcac 100644 --- a/maintenance/rebuildlinks.inc +++ b/maintenance/rebuildlinks.inc @@ -12,23 +12,23 @@ function rebuildLinkTablesPass1() print "Rebuilding link tables (pass 1).\n"; $sql = "DROP TABLE IF EXISTS rebuildlinks"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "CREATE TABLE rebuildlinks ( rl_f_id int(8) unsigned NOT NULL default 0, rl_f_title varchar(255) binary NOT NULL default '', rl_to varchar(255) binary NOT NULL default '', INDEX rl_to (rl_to) ) TYPE=MyISAM"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); - $sql = "LOCK TABLES cur READ, rebuildlinks WRITE"; - wfQuery( $sql ); + $sql = "LOCK TABLES cur READ, rebuildlinks WRITE, interwiki READ"; + wfQuery( $sql, DB_WRITE ); $sql = "DELETE FROM rebuildlinks"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "SELECT cur_id,cur_namespace,cur_title,cur_text FROM cur"; - $res = wfQuery( $sql ); + $res = wfQuery( $sql, DB_WRITE ); $total = wfNumRows( $res ); $tc = Title::legalChars(); @@ -53,7 +53,7 @@ function rebuildLinkTablesPass1() if ( 0 != $i ) { $sql .= ","; } $sql .= "({$id},'{$title}','{$dest}')"; } - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); } if ( ( ++$count % 1000 ) == 0 ) { print "$count of $total articles scanned.\n"; @@ -63,7 +63,7 @@ function rebuildLinkTablesPass1() mysql_free_result( $res ); $sql = "UNLOCK TABLES"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); } function rebuildLinkTablesPass2() @@ -72,24 +72,24 @@ function rebuildLinkTablesPass2() $count = 0; print "Rebuilding link tables (pass 2).\n"; - $sql = "LOCK TABLES cur READ, rebuildlinks READ, " . + $sql = "LOCK TABLES cur READ, rebuildlinks READ, interwiki READ, " . "links WRITE, brokenlinks WRITE, imagelinks WRITE"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "DELETE FROM links"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "DELETE FROM brokenlinks"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "DELETE FROM links"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $ins = $wgLang->getNsText( Namespace::getImage() ); $inslen = strlen($ins)+1; $sql = "SELECT rl_f_title,rl_to FROM rebuildlinks " . "WHERE rl_to LIKE '$ins:%'"; - $res = wfQuery( $sql ); + $res = wfQuery( $sql, DB_WRITE ); $sql = "INSERT INTO imagelinks (il_from,il_to) VALUES "; $sqlX = ""; @@ -106,12 +106,12 @@ function rebuildLinkTablesPass2() if ($sqlX != "") { $sql .= $sqlX; wfFreeResult( $res ); - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); } $sql = "SELECT DISTINCT rl_to FROM rebuildlinks " . "ORDER BY rl_to"; - $res = wfQuery( $sql ); + $res = wfQuery( $sql, DB_WRITE ); $count = 0; $total = wfNumRows( $res ); @@ -124,7 +124,7 @@ function rebuildLinkTablesPass2() if ( 0 == $id ) { $sql = "SELECT rl_f_id FROM rebuildlinks WHERE rl_to='{$to}'"; - $res2 = wfQuery( $sql ); + $res2 = wfQuery( $sql, DB_WRITE ); $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES "; $first = true; @@ -135,10 +135,10 @@ function rebuildLinkTablesPass2() $sql .= "({$from},'{$to}')"; } wfFreeResult( $res2 ); - if ( ! $first ) { wfQuery( $sql ); } + if ( ! $first ) { wfQuery( $sql, DB_WRITE ); } } else { $sql = "SELECT rl_f_title FROM rebuildlinks WHERE rl_to='{$to}'"; - $res2 = wfQuery( $sql ); + $res2 = wfQuery( $sql, DB_WRITE ); $sql = "INSERT INTO links (l_from,l_to) VALUES "; $first = true; @@ -149,7 +149,7 @@ function rebuildLinkTablesPass2() $sql .= "('{$from}',{$id})"; } wfFreeResult( $res2 ); - if ( ! $first ) { wfQuery( $sql ); } + if ( ! $first ) { wfQuery( $sql, DB_WRITE ); } } if ( ( ++$count % 1000 ) == 0 ) { print "$count of $total titles processed.\n"; @@ -158,9 +158,9 @@ function rebuildLinkTablesPass2() wfFreeResult( $res ); $sql = "UNLOCK TABLES"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); $sql = "DROP TABLE rebuildlinks"; - wfQuery( $sql ); + wfQuery( $sql, DB_WRITE ); } ?> -- 2.20.1