X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FArticle.php;h=b588066135a5dca8d0f6902a6fc6c42bda08160c;hb=e8b8cce1794e4602c82d7c7e266db91cdd7c0eb0;hp=4bc527bc1c507e28bd7c31abdc0726b6c9940b2a;hpb=4da8ccdbdf2a93b1084dd3793d44c20867cfcd38;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Article.php b/includes/Article.php index 4bc527bc1c..b588066135 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -20,25 +20,55 @@ class Article { /* private */ var $mCounter, $mComment, $mCountAdjustment; /* private */ var $mMinorEdit, $mRedirectedFrom; /* private */ var $mTouched, $mFileCache, $mTitle; - + /* private */ var $mId, $mTable; + function Article( &$title ) { $this->mTitle =& $title; $this->clear(); } - + /* private */ function clear() { $this->mContentLoaded = false; - $this->mUser = $this->mCounter = -1; # Not loaded + $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded $this->mRedirectedFrom = $this->mUserText = $this->mTimestamp = $this->mComment = $this->mFileCache = ""; $this->mCountAdjustment = 0; $this->mTouched = "19700101000000"; } + /* static */ function getRevisionText( $row, $prefix = "old_" ) { + # Deal with optional compression of archived pages. + # This can be done periodically via maintenance/compressOld.php, and + # as pages are saved if $wgCompressRevisions is set. + $text = $prefix . "text"; + $flags = $prefix . "flags"; + if( isset( $row->$flags ) && (false !== strpos( $row->$flags, "gzip" ) ) ) { + return gzinflate( $row->$text ); + } + if( isset( $row->$text ) ) { + return $row->$text; + } + return false; + } + + /* static */ function compressRevisionText( &$text ) { + global $wgCompressRevisions; + if( !$wgCompressRevisions ) { + return ""; + } + if( !function_exists( "gzdeflate" ) ) { + wfDebug( "Article::compressRevisionText() -- no zlib support, not compressing\n" ); + return ""; + } + $text = gzdeflate( $text ); + return "gzip"; + } + # Note that getContent/loadContent may follow redirects if # not told otherwise, and so may cause a change to mTitle. + # Return the text of this revision function getContent( $noredir = false ) { global $action,$section,$count; # From query string @@ -89,7 +119,8 @@ class Article { } } } - + + # Load the revision (including cur_text) into this object function loadContent( $noredir = false ) { global $wgOut, $wgMwRedir; @@ -97,21 +128,8 @@ class Article { if ( $this->mContentLoaded ) return; $fname = "Article::loadContent"; - - # Pre-fill content with error message so that if something - # fails we'll have something telling us what we intended. - - $t = $this->mTitle->getPrefixedText(); - if ( isset( $oldid ) ) { - $oldid = IntVal( $oldid ); - $t .= ",oldid={$oldid}"; - } - if ( isset( $redirect ) ) { - $redirect = ($redirect == "no") ? "no" : "yes"; - $t .= ",redirect={$redirect}"; - } - $this->mContent = wfMsg( "missingarticle", $t ); - + $success = true; + if ( ! $oldid ) { # Retrieve current version $id = $this->getID(); if ( 0 == $id ) return; @@ -133,30 +151,31 @@ class Article { if ( preg_match( "/\\[\\[([^\\]\\|]+)[\\]\\|]/", $s->cur_text, $m ) ) { $rt = Title::newFromText( $m[1] ); - - # Gotta hand redirects to special pages differently: - # Fill the HTTP response "Location" header and ignore - # the rest of the page we're on. - - if ( $rt->getInterwiki() != "" ) { - $wgOut->redirect( $rt->getFullURL() ) ; - return; - } - if ( $rt->getNamespace() == Namespace::getSpecial() ) { - $wgOut->redirect( wfLocalUrl( - $rt->getPrefixedURL() ) ); - return; - } - $rid = $rt->getArticleID(); - if ( 0 != $rid ) { - $sql = "SELECT cur_text,cur_timestamp,cur_user," . - "cur_counter,cur_restrictions,cur_touched FROM cur WHERE cur_id={$rid}"; - $res = wfQuery( $sql, DB_READ, $fname ); - - if ( 0 != wfNumRows( $res ) ) { - $this->mRedirectedFrom = $this->mTitle->getPrefixedText(); - $this->mTitle = $rt; - $s = wfFetchObject( $res ); + if( $rt ) { + # Gotta hand redirects to special pages differently: + # Fill the HTTP response "Location" header and ignore + # the rest of the page we're on. + + if ( $rt->getInterwiki() != "" ) { + $wgOut->redirect( $rt->getFullURL() ) ; + return; + } + if ( $rt->getNamespace() == Namespace::getSpecial() ) { + $wgOut->redirect( wfLocalUrl( + $rt->getPrefixedURL() ) ); + return; + } + $rid = $rt->getArticleID(); + if ( 0 != $rid ) { + $sql = "SELECT cur_text,cur_timestamp,cur_user," . + "cur_counter,cur_restrictions,cur_touched FROM cur WHERE cur_id={$rid}"; + $res = wfQuery( $sql, DB_READ, $fname ); + + if ( 0 != wfNumRows( $res ) ) { + $this->mRedirectedFrom = $this->mTitle->getPrefixedText(); + $this->mTitle = $rt; + $s = wfFetchObject( $res ); + } } } } @@ -171,18 +190,34 @@ class Article { $this->mTitle->mRestrictionsLoaded = true; wfFreeResult( $res ); } else { # oldid set, retrieve historical version - $sql = "SELECT old_text,old_timestamp,old_user FROM old " . + $sql = "SELECT old_text,old_timestamp,old_user,old_flags FROM old " . "WHERE old_id={$oldid}"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { return; } $s = wfFetchObject( $res ); - $this->mContent = $s->old_text; + $this->mContent = Article::getRevisionText( $s ); $this->mUser = $s->old_user; $this->mCounter = 0; $this->mTimestamp = $s->old_timestamp; wfFreeResult( $res ); } + + # Return error message :P + # Horrible, confusing UI and data. I think this should return false on error -- TS + if ( !$success ) { + $t = $this->mTitle->getPrefixedText(); + if ( isset( $oldid ) ) { + $oldid = IntVal( $oldid ); + $t .= ",oldid={$oldid}"; + } + if ( isset( $redirect ) ) { + $redirect = ($redirect == "no") ? "no" : "yes"; + $t .= ",redirect={$redirect}"; + } + $this->mContent = wfMsg( "missingarticle", $t ); + } + $this->mContentLoaded = true; } @@ -217,7 +252,7 @@ class Article { return 1; } - # Load the field related to the last edit time of the article. + # Loads everything from cur except cur_text # This isn't necessary for all uses, so it's only done if needed. /* private */ function loadLastEdit() @@ -295,10 +330,14 @@ class Article { return; } - if ( !isset( $oldid ) ) { - if( $this->checkTouched() ) { - $wgOut->checkLastModified( $this->mTouched ); - $this->tryFileCache(); + if ( !isset( $oldid ) and $this->checkTouched() ) { + if( $wgOut->checkLastModified( $this->mTouched ) ){ + return; + } else if ( $this->tryFileCache() ) { + # tell wgOut that output is taken care of + $wgOut->disable(); + $this->viewUpdates(); + return; } } @@ -320,6 +359,7 @@ class Article { $s = wfMsg( "redirectedfrom", $redir ); $wgOut->setSubtitle( $s ); } + $wgLinkCache->preFill( $this->mTitle ); $wgOut->addWikiText( $text ); @@ -335,7 +375,6 @@ class Article { /* private */ function insertNewArticle( $text, $summary, $isminor, $watchthis ) { global $wgOut, $wgUser, $wgLinkCache, $wgMwRedir; - global $wgEnablePersistentLC; $fname = "Article::insertNewArticle"; @@ -351,6 +390,7 @@ class Article { $won = wfInvertTimestamp( $now ); wfSeedRandom(); $rand = number_format( mt_rand() / mt_getrandmax(), 12, ".", "" ); + $isminor = ( $isminor && $wgUser->getID() ) ? 1 : 0; $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," . "cur_comment,cur_user,cur_timestamp,cur_minor_edit,cur_counter," . "cur_restrictions,cur_user_text,cur_is_redirect," . @@ -358,29 +398,16 @@ class Article { wfStrencode( $text ) . "', '" . wfStrencode( $summary ) . "', '" . $wgUser->getID() . "', '{$now}', " . - ( $isminor ? 1 : 0 ) . ", 0, '', '" . + $isminor . ", 0, '', '" . wfStrencode( $wgUser->getName() ) . "', $redir, 1, $rand, '{$now}', '{$won}')"; $res = wfQuery( $sql, DB_WRITE, $fname ); $newid = wfInsertId(); $this->mTitle->resetArticleID( $newid ); - if ( $wgEnablePersistentLC ) { - // Purge related entries in links cache on new page, to heal broken links - $ptitle = wfStrencode( $ttl ); - wfQuery("DELETE linkscc FROM linkscc,brokenlinks ". - "WHERE lcc_pageid=bl_from AND bl_to='{$ptitle}'", DB_WRITE); - } + Article::onArticleCreate( $this->mTitle, $text ); + RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary ); - $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," . - "rc_namespace,rc_title,rc_new,rc_minor,rc_cur_id,rc_user," . - "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid,rc_bot) VALUES (" . - "'{$now}','{$now}',{$ns},'" . wfStrencode( $ttl ) . "',1," . - ( $isminor ? 1 : 0 ) . ",{$newid}," . $wgUser->getID() . ",'" . - wfStrencode( $wgUser->getName() ) . "','" . - wfStrencode( $summary ) . "',0,0," . - ( $wgUser->isBot() ? 1 : 0 ) . ")"; - wfQuery( $sql, DB_WRITE, $fname ); if ($watchthis) { if(!$this->mTitle->userIsWatching()) $this->watch(); } else { @@ -397,7 +424,7 @@ class Article { $this->showArticle( $text, wfMsg( "newarticle" ) ); } - function updateArticle( $text, $summary, $minor, $watchthis, $section = "") + function updateArticle( $text, $summary, $minor, $watchthis, $section = "", $forceBot = false ) { global $wgOut, $wgUser, $wgLinkCache; global $wgDBtransactions, $wgMwRedir; @@ -421,7 +448,7 @@ class Article { } } if ( $this->mMinorEdit ) { $me1 = 1; } else { $me1 = 0; } - if ( $minor ) { $me2 = 1; } else { $me2 = 0; } + if ( $minor && $wgUser->getID() ) { $me2 = 1; } else { $me2 = 0; } if ( preg_match( "/^((" . $wgMwRedir->getBaseRegex() . ")[^\\n]+)/i", $text, $m ) ) { $redir = 1; $text = $m[1] . "\n"; # Remove all content but redirect @@ -459,9 +486,12 @@ class Article { return false; } + # This overwrites $oldtext if revision compression is on + $flags = Article::compressRevisionText( $oldtext ); + $sql = "INSERT INTO old (old_namespace,old_title,old_text," . "old_comment,old_user,old_user_text,old_timestamp," . - "old_minor_edit,inverse_timestamp) VALUES (" . + "old_minor_edit,inverse_timestamp,old_flags) VALUES (" . $this->mTitle->getNamespace() . ", '" . wfStrencode( $this->mTitle->getDBkey() ) . "', '" . wfStrencode( $oldtext ) . "', '" . @@ -469,37 +499,14 @@ class Article { $this->getUser() . ", '" . wfStrencode( $this->getUserText() ) . "', '" . $this->getTimestamp() . "', " . $me1 . ", '" . - wfInvertTimestamp( $this->getTimestamp() ) . "')"; + wfInvertTimestamp( $this->getTimestamp() ) . "','$flags')"; $res = wfQuery( $sql, DB_WRITE, $fname ); $oldid = wfInsertID( $res ); - $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," . - "rc_namespace,rc_title,rc_new,rc_minor,rc_bot,rc_cur_id,rc_user," . - "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid) VALUES (" . - "'{$now}','{$now}'," . $this->mTitle->getNamespace() . ",'" . - wfStrencode( $this->mTitle->getDBkey() ) . "',0,{$me2}," . - ( $wgUser->isBot() ? 1 : 0 ) . "," . - $this->getID() . "," . $wgUser->getID() . ",'" . - wfStrencode( $wgUser->getName() ) . "','" . - wfStrencode( $summary ) . "',0,{$oldid})"; - wfQuery( $sql, DB_WRITE, $fname ); - - $sql = "UPDATE recentchanges SET rc_this_oldid={$oldid} " . - "WHERE rc_namespace=" . $this->mTitle->getNamespace() . " AND " . - "rc_title='" . wfStrencode( $this->mTitle->getDBkey() ) . "' AND " . - "rc_timestamp='" . $this->getTimestamp() . "'"; - wfQuery( $sql, DB_WRITE, $fname ); - - $sql = "UPDATE recentchanges SET rc_cur_time='{$now}' " . - "WHERE rc_cur_id=" . $this->getID(); - wfQuery( $sql, DB_WRITE, $fname ); - - global $wgEnablePersistentLC; - if ( $wgEnablePersistentLC ) { - // Purge link cache for this page - $pageid=$this->getID(); - wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pageid}'", DB_WRITE); - } + $bot = (int)($wgUser->isBot() || $forceBot); + RecentChange::notifyEdit( $now, $this->mTitle, $me2, $wgUser, $summary, + $oldid, $this->getTimestamp(), $bot ); + Article::onArticleEdit( $this->mTitle ); } if( $wgDBtransactions ) { @@ -524,22 +531,27 @@ class Article { function showArticle( $text, $subtitle ) { - global $wgOut, $wgUser, $wgLinkCache, $wgUseBetterLinksUpdate; + global $wgOut, $wgUser, $wgLinkCache; global $wgMwRedir; $wgLinkCache = new LinkCache(); # Get old version of link table to allow incremental link updates - if ( $wgUseBetterLinksUpdate ) { - $wgLinkCache->preFill( $this->mTitle ); - $wgLinkCache->clear(); - } + $wgLinkCache->preFill( $this->mTitle ); + $wgLinkCache->clear(); # Now update the link cache by parsing the text $wgOut = new OutputPage(); $wgOut->addWikiText( $text ); - $this->editUpdates( $text ); + # Every 1000th edit, prune the recent changes table. + wfSeedRandom(); + if ( 0 == mt_rand( 0, 999 ) ) { + $cutoff = wfUnix2Timestamp( time() - ( 7 * 86400 ) ); + $sql = "DELETE FROM recentchanges WHERE rc_timestamp < '{$cutoff}'"; + wfQuery( $sql, DB_WRITE ); + } + if( $wgMwRedir->matchStart( $text ) ) $r = "redirect=no"; else @@ -590,76 +602,6 @@ class Article { $this->watch( false ); } - # This shares a lot of issues (and code) with Recent Changes - - function history() - { - global $wgUser, $wgOut, $wgLang, $offset, $limit; - - # If page hasn't changed, client can cache this - - $wgOut->checkLastModified( $this->getTimestamp() ); - $fname = "Article::history"; - wfProfileIn( $fname ); - - $wgOut->setPageTitle( $this->mTitle->getPRefixedText() ); - $wgOut->setSubtitle( wfMsg( "revhistory" ) ); - $wgOut->setArticleFlag( false ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); - - if( $this->mTitle->getArticleID() == 0 ) { - $wgOut->addHTML( wfMsg( "nohistory" ) ); - wfProfileOut( $fname ); - return; - } - - $offset = (int)$offset; - $limit = (int)$limit; - if( $limit == 0 ) $limit = 50; - $namespace = $this->mTitle->getNamespace(); - $title = $this->mTitle->getText(); - $sql = "SELECT old_id,old_user," . - "old_comment,old_user_text,old_timestamp,old_minor_edit ". - "FROM old USE INDEX (name_title_timestamp) " . - "WHERE old_namespace={$namespace} AND " . - "old_title='" . wfStrencode( $this->mTitle->getDBkey() ) . "' " . - "ORDER BY inverse_timestamp LIMIT $offset, $limit"; - $res = wfQuery( $sql, DB_READ, "Article::history" ); - - $revs = wfNumRows( $res ); - if( $this->mTitle->getArticleID() == 0 ) { - $wgOut->addHTML( wfMsg( "nohistory" ) ); - wfProfileOut( $fname ); - return; - } - - $sk = $wgUser->getSkin(); - $numbar = wfViewPrevNext( - $offset, $limit, - $this->mTitle->getPrefixedText(), - "action=history" ); - $s = $numbar; - $s .= $sk->beginHistoryList(); - - if($offset == 0 ) - $s .= $sk->historyLine( $this->getTimestamp(), $this->getUser(), - $this->getUserText(), $namespace, - $title, 0, $this->getComment(), - ( $this->getMinorEdit() > 0 ) ); - - $revs = wfNumRows( $res ); - while ( $line = wfFetchObject( $res ) ) { - $s .= $sk->historyLine( $line->old_timestamp, $line->old_user, - $line->old_user_text, $namespace, - $title, $line->old_id, - $line->old_comment, ( $line->old_minor_edit > 0 ) ); - } - $s .= $sk->endHistoryList(); - $s .= $numbar; - $wgOut->addHTML( $s ); - wfProfileOut( $fname ); - } - function protect( $limit = "sysop" ) { global $wgUser, $wgOut; @@ -697,7 +639,7 @@ class Article { function delete() { - global $wgUser, $wgOut; + global $wgUser, $wgOut, $wgMessageCache; global $wpConfirm, $wpReason, $image, $oldimage; # This code desperately needs to be totally rewritten @@ -711,6 +653,12 @@ class Article { return; } + # Can't delete cached MediaWiki namespace (i.e. vital messages) + if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && $wgMessageCache->isCacheable( $this->mTitle->getDBkey() ) ) { + $wgOut->fatalError( wfMsg( "cannotdelete" ) ); + return; + } + # Better double-check that it hasn't been deleted yet! $wgOut->setPagetitle( wfMsg( "confirmdelete" ) ); if ( ( "" == trim( $this->mTitle->getText() ) ) @@ -730,7 +678,7 @@ class Article { $ns = $this->mTitle->getNamespace(); $title = $this->mTitle->getDBkey(); $etitle = wfStrencode( $title ); - $sql = "SELECT old_text FROM old WHERE old_namespace=$ns and old_title='$etitle' ORDER BY inverse_timestamp LIMIT 1"; + $sql = "SELECT old_text,old_flags FROM old WHERE old_namespace=$ns and old_title='$etitle' ORDER BY inverse_timestamp LIMIT 1"; $res = wfQuery( $sql, DB_READ, $fname ); if( ($old=wfFetchObject($res)) && !$wpConfirm ) { $skin=$wgUser->getSkin(); @@ -749,7 +697,7 @@ class Article { $text=$s->cur_text; } else { if($old) { - $text=$old->old_text; + $text = Article::getRevisionText( $old ); $blanked=1; } @@ -846,8 +794,7 @@ class Article { function doDeleteArticle( $title ) { - global $wgUser, $wgOut, $wgLang, $wpReason, $wgDeferredUpdateList, - $wgEnablePersistentLC; + global $wgUser, $wgOut, $wgLang, $wpReason, $wgDeferredUpdateList; $fname = "Article::doDeleteArticle"; wfDebug( "$fname\n" ); @@ -899,12 +846,7 @@ class Article { $t = wfStrencode( $title->getPrefixedDBkey() ); - if ( $wgEnablePersistentLC ) { - // Purge related entries in links cache on delete, - wfQuery("DELETE linkscc FROM linkscc,links ". - "WHERE lcc_title=links.l_from AND l_to={$id}", DB_WRITE); - wfQuery("DELETE FROM linkscc WHERE lcc_title='{$t}'", DB_WRITE); - } + Article::onArticleDelete( $title ); $sql = "SELECT l_from FROM links WHERE l_to={$id}"; $res = wfQuery( $sql, DB_READ, $fname ); @@ -965,7 +907,10 @@ class Article { $wgOut->readOnlyPage( $this->getContent() ); return; } - + + # Enhanced rollback, marks edits rc_bot=1 + $bot = !!$_REQUEST['bot']; + # Replace all this user's current edits with the next one down $tt = wfStrencode( $this->mTitle->getDBKey() ); $n = $this->mTitle->getNamespace(); @@ -994,12 +939,12 @@ class Article { $wgOut->addHTML( wfMsg("editcomment", htmlspecialchars( $s->cur_comment ) ) ); - } + } return; } # Get the last edit not by this guy - $sql = "SELECT old_text,old_user,old_user_text + $sql = "SELECT old_text,old_user,old_user_text,old_timestamp,old_flags FROM old USE INDEX (name_title_timestamp) WHERE old_namespace={$n} AND old_title='{$tt}' AND (old_user <> {$uid} OR old_user_text <> '{$ut}') @@ -1012,19 +957,22 @@ class Article { return; } $s = wfFetchObject( $res ); - + + if ( $bot ) { + # Mark all reverted edits as bot + $sql = "UPDATE recentchanges SET rc_bot=1 WHERE + rc_cur_id=$pid AND rc_user=$uid AND rc_timestamp > '{$s->old_timestamp}'"; + wfQuery( $sql, DB_WRITE, $fname ); + } + # Save it! - $newcomment = wfMsg( "revertpage", $s->old_user_text ); + $newcomment = wfMsg( "revertpage", $s->old_user_text, $from ); $wgOut->setPagetitle( wfMsg( "actioncomplete" ) ); $wgOut->setRobotpolicy( "noindex,nofollow" ); $wgOut->addHTML( "

" . $newcomment . "

\n
\n" ); - $this->updateArticle( $s->old_text, $newcomment, 1, $this->mTitle->userIsWatching() ); - - global $wgEnablePersistentLC; - if ( $wgEnablePersistentLC ) { - wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); - } - + $this->updateArticle( Article::getRevisionText( $s ), $newcomment, 1, $this->mTitle->userIsWatching(), "", $bot ); + + Article::onArticleEdit( $this->mTitle ); $wgOut->returnToMain( false ); } @@ -1034,12 +982,10 @@ class Article { /* private */ function viewUpdates() { global $wgDeferredUpdateList; - if ( 0 != $this->getID() ) { global $wgDisableCounters; if( !$wgDisableCounters ) { - $u = new ViewCountUpdate( $this->getID() ); - array_push( $wgDeferredUpdateList, $u ); + Article::incViewCount( $this->getID() ); $u = new SiteStatsUpdate( 1, 0, 0 ); array_push( $wgDeferredUpdateList, $u ); } @@ -1049,45 +995,7 @@ class Article { } } - # Do standard deferred updates after page edit. - # Every 1000th edit, prune the recent changes table. - - /* private */ function editUpdates( $text ) - { - global $wgDeferredUpdateList, $wgDBname, $wgMemc; - - wfSeedRandom(); - if ( 0 == mt_rand( 0, 999 ) ) { - $cutoff = wfUnix2Timestamp( time() - ( 7 * 86400 ) ); - $sql = "DELETE FROM recentchanges WHERE rc_timestamp < '{$cutoff}'"; - wfQuery( $sql, DB_WRITE ); - } - $id = $this->getID(); - $title = $this->mTitle->getPrefixedDBkey(); - $adj = $this->mCountAdjustment; - if ( 0 != $id ) { - $u = new LinksUpdate( $id, $title ); - array_push( $wgDeferredUpdateList, $u ); - $u = new SiteStatsUpdate( 0, 1, $adj ); - array_push( $wgDeferredUpdateList, $u ); - $u = new SearchUpdate( $id, $title, $text ); - array_push( $wgDeferredUpdateList, $u ); - - $u = new UserTalkUpdate( 1, $this->mTitle->getNamespace(), - $this->mTitle->getDBkey() ); - array_push( $wgDeferredUpdateList, $u ); - - if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { - $messageCache = $wgMemc->get( "$wgDBname:messages" ); - if (!$messageCache) { - $messageCache = wfLoadAllMessages(); - } - $messageCache[$this->mTitle->getDBkey()] = $text; - $wgMemc->set( "$wgDBname:messages", $messageCache, 86400 ); - } - } - } /* private */ function setOldSubtitle() { @@ -1172,11 +1080,22 @@ class Article { $mw =& MagicWord::get( MAG_SUBST ); $text = $mw->substituteCallback( $text, "wfReplaceSubstVar" ); +/* Experimental: + # Trim trailing whitespace + # MAG_END (__END__) tag allows for trailing + # whitespace to be deliberately included + $text = rtrim( $text ); + $mw =& MagicWord::get( MAG_END ); + $mw->matchAndRemove( $text ); +*/ return $text; } /* Caching functions */ - + + # checkLastModified returns true iff it has taken care of all + # output to the client that is necessary for this request. + # (that is, it has sent a cached version of the page) function tryFileCache() { static $called = false; if( $called ) { @@ -1186,8 +1105,8 @@ class Article { $called = true; if($this->isFileCacheable()) { $touched = $this->mTouched; - if( strpos( $this->mContent, "{{" ) !== false ) { - # Expire pages with variable replacements in an hour + if( $this->mTitle->getPrefixedDBkey() == wfMsg( "mainpage" ) ) { + # Expire the main page quicker $expire = wfUnix2Timestamp( time() - 3600 ); $touched = max( $expire, $touched ); } @@ -1196,17 +1115,9 @@ class Article { global $wgOut; wfDebug( " tryFileCache() - about to load\n" ); $cache->loadFromFileCache(); - $wgOut->reportTime(); # For profiling - exit; + return true; } else { wfDebug( " tryFileCache() - starting buffer\n" ); - if($cache->useGzip() && wfClientAcceptsGzip()) { - /* For some reason, adding this header line over in - CacheManager::saveToFileCache() fails on my test - setup at home, though it works on the live install. - Make double-sure... --brion */ - header( "Content-Encoding: gzip" ); - } ob_start( array(&$cache, 'saveToFileCache' ) ); } } else { @@ -1222,7 +1133,7 @@ class Article { and ($this->getID() != 0) and ($wgUser->getId() == 0) and (!$wgUser->getNewtalk()) - and ($this->mTitle->getNamespace != Namespace::getSpecial()) + and ($this->mTitle->getNamespace() != Namespace::getSpecial()) and ($action == "view") and (!isset($oldid)) and (!isset($diff)) @@ -1242,6 +1153,177 @@ class Article { return false; } } + + /* static */ function incViewCount( $id ) + { + $id = intval( $id ); + global $wgHitcounterUpdateFreq; + + if( $wgHitcounterUpdateFreq <= 1 ){ // + wfQuery("UPDATE cur SET cur_counter = cur_counter + 1 " . + "WHERE cur_id = $id", DB_WRITE); + return; + } + + # Not important enough to warrant an error page in case of failure + $oldignore = wfIgnoreSQLErrors( true ); + + wfQuery("INSERT INTO hitcounter (hc_id) VALUES ({$id})", DB_WRITE); + + $checkfreq = intval( $wgHitcounterUpdateFreq/25 + 1 ); + if( (rand() % $checkfreq != 0) or (wfLastErrno() != 0) ){ + # Most of the time (or on SQL errors), skip row count check + wfIgnoreSQLErrors( $oldignore ); + return; + } + + $res = wfQuery("SELECT COUNT(*) as n FROM hitcounter", DB_WRITE); + $row = wfFetchObject( $res ); + $rown = intval( $row->n ); + if( $rown >= $wgHitcounterUpdateFreq ){ + wfProfileIn( "Article::incViewCount-collect" ); + $old_user_abort = ignore_user_abort( true ); + + wfQuery("LOCK TABLES hitcounter WRITE", DB_WRITE); + wfQuery("CREATE TEMPORARY TABLE acchits TYPE=HEAP ". + "SELECT hc_id,COUNT(*) AS hc_n FROM hitcounter ". + "GROUP BY hc_id", DB_WRITE); + wfQuery("DELETE FROM hitcounter", DB_WRITE); + wfQuery("UNLOCK TABLES", DB_WRITE); + wfQuery("UPDATE cur,acchits SET cur_counter=cur_counter + hc_n ". + "WHERE cur_id = hc_id", DB_WRITE); + wfQuery("DROP TABLE acchits", DB_WRITE); + + ignore_user_abort( $old_user_abort ); + wfProfileOut( "Article::incViewCount-collect" ); + } + wfIgnoreSQLErrors( $oldignore ); + } + + # The onArticle*() functions are supposed to be a kind of hooks + # which should be called whenever any of the specified actions + # are done. + # + # This is a good place to put code to clear caches, for instance. + + /* static */ function onArticleCreate($title_obj,$text=''){ + global $wgEnablePersistentLC, $wgEnableParserCache, $wgUseSquid; + global $wgDeferredUpdateList, $wgDBname, $wgMemc; + global $wgMessageCache, $wgInternalServer; + # Do standard deferred updates after page edit. + $id = $title_obj->getArticleID(); + $title = $title_obj->getPrefixedDBkey(); + $shortTitle = $title_obj->getDBkey(); + + $adj = $this->mCountAdjustment; + + if ( 0 != $id ) { + $u = new LinksUpdate( $id, $title ); + array_push( $wgDeferredUpdateList, $u ); + $u = new SiteStatsUpdate( 0, 1, $adj ); + array_push( $wgDeferredUpdateList, $u ); + $u = new SearchUpdate( $id, $title, $text ); + array_push( $wgDeferredUpdateList, $u ); + + $u = new UserTalkUpdate( 1, $title_obj->getNamespace(), $shortTitle ); + array_push( $wgDeferredUpdateList, $u ); + + if ( $title_obj->getNamespace() == NS_MEDIAWIKI ) { + $wgMessageCache->replace( $shortTitle, $text ); + } + } + if ( $wgEnablePersistentLC ) { + LinkCache::linksccClearBrokenLinksTo( $title ); + } + if ( $wgEnableParserCache ) { + OutputPage::parsercacheClearBrokenLinksTo( $title ); + } + if ( $wgUseSquid ) { + $urlArr = Array( + $wgInternalServer.wfLocalUrl( $title_obj->getPrefixedURL()) + ); + wfPurgeSquidServers($urlArr); + /* this needs to be done after LinksUpdate */ + $u = new SquidUpdate($title_obj); + array_push( $wgDeferredUpdateList, $u ); + } + } + + /* static */ function onArticleDelete($title_obj,$text=''){ + global $wgEnablePersistentLC, $wgEnableParserCache, $wgUseSquid, $wgDeferredUpdateList; + global $wgDeferredUpdateList, $wgDBname, $wgMemc; + global $wgMessageCache, $wgInternalServer; + + $id = $title_obj->getArticleID(); + $title = $title_obj->getPrefixedDBkey(); + $shortTitle = $title_obj->getDBkey(); + + if ( $wgEnablePersistentLC ) { + LinkCache::linksccClearLinksTo( $id ); + } + if ( $wgEnableParserCache ) { + OutputPage::parsercacheClearLinksTo( $id ); + } + if ( $wgUseSquid ) { + $urlArr = Array( + $wgInternalServer.wfLocalUrl( $title_obj->getPrefixedURL()) + ); + wfPurgeSquidServers($urlArr); + + /* prepare the list of urls to purge */ + $sql = "SELECT l_from FROM links WHERE l_to={$id}" ; + $res = wfQuery ( $sql, DB_READ ) ; + while ( $BL = wfFetchObject ( $res ) ) + { + $t = Title::newFromDBkey( $BL->l_from) ; + $blurlArr[] = $wgInternalServer.wfLocalUrl( $t->getPrefixedURL() ); + } + wfFreeResult ( $res ) ; + $u = new SquidUpdate( $title_obj, $blurlArr ); + array_push( $wgDeferredUpdateList, $u ); + + } + } + + /* static */ function onArticleEdit($title_obj,$text=''){ + global $wgEnablePersistentLC, $wgEnableParserCache, $wgUseSquid; + global $wgDeferredUpdateList, $wgDBname, $wgMemc; + global $wgMessageCache, $wgInternalServer; + + $id = $title_obj->getArticleID(); + $title = $title_obj->getPrefixedDBkey(); + $shortTitle = $title_obj->getDBkey(); + + $adj = $this->mCountAdjustment; + + if ( 0 != $id ) { + $u = new LinksUpdate( $id, $title ); + array_push( $wgDeferredUpdateList, $u ); + $u = new SiteStatsUpdate( 0, 1, $adj ); + array_push( $wgDeferredUpdateList, $u ); + $u = new SearchUpdate( $id, $title, $text ); + array_push( $wgDeferredUpdateList, $u ); + + $u = new UserTalkUpdate( 1, $title_obj->getNamespace(), $shortTitle ); + array_push( $wgDeferredUpdateList, $u ); + + if ( $title_obj->getNamespace() == NS_MEDIAWIKI ) { + $wgMessageCache->replace( $shortTitle, $text ); + } + } + if ( $wgEnablePersistentLC ) { + LinkCache::linksccClearPage( $id ); + } + if ( $wgEnableParserCache ) { + OutputPage::parsercacheClearPage( $id ); + } + if ( $wgUseSquid ) { + $urlArr = Array( + $wgInternalServer.wfLocalUrl( $title_obj->getPrefixedURL()), + ); + wfPurgeSquidServers($urlArr); + } + } } function wfReplaceSubstVar( $matches ) {