From cecb985bee3bdd252e1b8dc0bd500b37cd52be01 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Wed, 16 May 2007 20:58:53 +0000 Subject: Aktualisierung auf MediaWiki 1.10.0 Plugins angepasst und verbessert kleine Korrekturen am Design --- includes/AjaxDispatcher.php | 23 +- includes/AjaxFunctions.php | 95 +- includes/AjaxResponse.php | 70 +- includes/Article.php | 463 +++++++--- includes/AuthPlugin.php | 8 +- includes/AutoLoader.php | 49 +- includes/BagOStuff.php | 41 +- includes/Block.php | 100 ++- includes/CacheDependency.php | 21 +- includes/CategoryPage.php | 35 +- includes/Categoryfinder.php | 73 +- includes/ChangesList.php | 78 +- includes/CoreParserFunctions.php | 23 +- includes/Credits.php | 1 - includes/Database.php | 295 ++++-- includes/DatabaseFunctions.php | 53 +- includes/DatabaseOracle.php | 788 ++++++++--------- includes/DatabasePostgres.php | 332 +++++-- includes/DateFormatter.php | 10 +- includes/DefaultSettings.php | 198 ++++- includes/Defines.php | 1 - includes/DifferenceEngine.php | 127 +-- includes/DjVuImage.php | 134 ++- includes/EditPage.php | 615 +++++++------ includes/Exception.php | 30 +- includes/Exif.php | 30 +- includes/Export.php | 38 +- includes/ExternalEdit.php | 4 +- includes/ExternalStore.php | 1 - includes/ExternalStoreDB.php | 2 - includes/ExternalStoreHttp.php | 1 - includes/FakeTitle.php | 3 +- includes/Feed.php | 18 +- includes/FileStore.php | 16 +- includes/GlobalFunctions.php | 197 ++++- includes/HTMLCacheUpdate.php | 9 +- includes/HTMLFileCache.php | 4 +- includes/HTMLForm.php | 4 +- includes/HistoryBlob.php | 98 +- includes/Hooks.php | 3 +- includes/IP.php | 279 +++++- includes/Image.php | 1279 +++++++++++---------------- includes/ImageFunctions.php | 2 +- includes/ImageGallery.php | 137 ++- includes/ImagePage.php | 256 +++--- includes/ImageQueryPage.php | 68 ++ includes/JobQueue.php | 125 ++- includes/Licenses.php | 12 +- includes/LinkBatch.php | 7 +- includes/LinkCache.php | 15 +- includes/LinkFilter.php | 46 +- includes/Linker.php | 322 +++---- includes/LinksUpdate.php | 16 +- includes/LoadBalancer.php | 13 +- includes/LogPage.php | 56 +- includes/MacBinary.php | 7 +- includes/MagicWord.php | 7 +- includes/Math.php | 8 +- includes/MediaTransformOutput.php | 166 ++++ includes/MemcachedSessions.php | 1 - includes/MessageCache.php | 10 +- includes/Metadata.php | 5 +- includes/MimeMagic.php | 39 +- includes/Namespace.php | 16 +- includes/ObjectCache.php | 6 +- includes/OutputHandler.php | 64 ++ includes/OutputPage.php | 122 ++- includes/PageHistory.php | 59 +- includes/PageQueryPage.php | 26 + includes/Pager.php | 57 +- includes/Parser.php | 522 ++++------- includes/ParserCache.php | 28 +- includes/ParserOptions.php | 119 +++ includes/ParserOutput.php | 133 +++ includes/PatrolLog.php | 83 ++ includes/Profiler.php | 11 +- includes/ProfilerSimple.php | 19 +- includes/ProfilerSimpleUDP.php | 11 +- includes/ProtectionForm.php | 183 +++- includes/ProxyTools.php | 50 +- includes/QueryPage.php | 223 +++-- includes/RawPage.php | 35 +- includes/RecentChange.php | 12 +- includes/Revision.php | 85 +- includes/Sanitizer.php | 184 ++-- includes/SearchEngine.php | 48 +- includes/SearchMySQL.php | 13 +- includes/SearchMySQL4.php | 12 +- includes/SearchOracle.php | 235 +++++ includes/SearchPostgres.php | 176 ++-- includes/SearchTsearch2.php | 20 +- includes/SearchUpdate.php | 16 +- includes/Setup.php | 4 +- includes/SiteConfiguration.php | 10 +- includes/SiteStats.php | 53 +- includes/Skin.php | 111 ++- includes/SkinTemplate.php | 114 +-- includes/SpecialAllmessages.php | 9 +- includes/SpecialAllpages.php | 61 +- includes/SpecialAncientpages.php | 10 +- includes/SpecialBlockip.php | 293 ++++-- includes/SpecialBlockme.php | 3 +- includes/SpecialBooksources.php | 9 +- includes/SpecialBrokenRedirects.php | 43 +- includes/SpecialCategories.php | 103 ++- includes/SpecialConfirmemail.php | 16 +- includes/SpecialContributions.php | 568 +++++------- includes/SpecialDeadendpages.php | 18 +- includes/SpecialDisambiguations.php | 129 ++- includes/SpecialDoubleRedirects.php | 30 +- includes/SpecialEmailuser.php | 23 +- includes/SpecialExport.php | 71 +- includes/SpecialFewestrevisions.php | 65 ++ includes/SpecialImagelist.php | 22 +- includes/SpecialImport.php | 123 +-- includes/SpecialIpblocklist.php | 61 +- includes/SpecialListredirects.php | 10 +- includes/SpecialListusers.php | 301 +++---- includes/SpecialLockdb.php | 10 +- includes/SpecialLog.php | 173 +++- includes/SpecialLonelypages.php | 11 +- includes/SpecialLongpages.php | 15 +- includes/SpecialMIMEsearch.php | 14 +- includes/SpecialMostcategories.php | 9 +- includes/SpecialMostimages.php | 29 +- includes/SpecialMostlinked.php | 13 +- includes/SpecialMostlinkedcategories.php | 10 +- includes/SpecialMostrevisions.php | 8 +- includes/SpecialMovepage.php | 35 +- includes/SpecialNewimages.php | 33 +- includes/SpecialNewpages.php | 31 +- includes/SpecialPage.php | 41 +- includes/SpecialPopularpages.php | 34 +- includes/SpecialPreferences.php | 49 +- includes/SpecialPrefixindex.php | 13 +- includes/SpecialProtectedpages.php | 260 ++++++ includes/SpecialRandompage.php | 142 ++- includes/SpecialRandomredirect.php | 47 +- includes/SpecialRecentchanges.php | 17 +- includes/SpecialRecentchangeslinked.php | 54 +- includes/SpecialResetpass.php | 9 +- includes/SpecialRevisiondelete.php | 9 +- includes/SpecialSearch.php | 22 +- includes/SpecialShortpages.php | 8 +- includes/SpecialSpecialpages.php | 5 +- includes/SpecialStatistics.php | 17 +- includes/SpecialUncategorizedcategories.php | 8 +- includes/SpecialUncategorizedimages.php | 26 +- includes/SpecialUncategorizedpages.php | 10 +- includes/SpecialUndelete.php | 204 +++-- includes/SpecialUnlockdb.php | 6 +- includes/SpecialUnusedcategories.php | 8 +- includes/SpecialUnusedimages.php | 39 +- includes/SpecialUnusedtemplates.php | 13 +- includes/SpecialUnwatchedpages.php | 14 +- includes/SpecialUpload.php | 151 ++-- includes/SpecialUploadMogile.php | 10 +- includes/SpecialUserlogin.php | 88 +- includes/SpecialUserlogout.php | 3 +- includes/SpecialUserrights.php | 89 +- includes/SpecialVersion.php | 28 +- includes/SpecialWantedcategories.php | 12 +- includes/SpecialWantedpages.php | 10 +- includes/SpecialWatchlist.php | 46 +- includes/SpecialWhatlinkshere.php | 170 ++-- includes/SpecialWithoutinterwiki.php | 56 ++ includes/SquidUpdate.php | 6 +- includes/StringUtils.php | 4 +- includes/StubObject.php | 7 +- includes/Title.php | 829 +++++++++-------- includes/User.php | 249 ++++-- includes/UserMailer.php | 42 +- includes/Utf8Case.php | 3 +- includes/WatchedItem.php | 29 +- includes/WebRequest.php | 46 +- includes/WebResponse.php | 14 +- includes/WebStart.php | 12 + includes/Wiki.php | 107 ++- includes/WikiError.php | 9 +- includes/Xml.php | 12 +- includes/XmlFunctions.php | 2 +- includes/ZhClient.php | 2 - includes/ZhConversion.php | 1 - includes/api/ApiBase.php | 9 +- includes/api/ApiFeedWatchlist.php | 6 +- includes/api/ApiFormatBase.php | 9 +- includes/api/ApiFormatJson.php | 8 +- includes/api/ApiFormatJson_json.php | 51 +- includes/api/ApiFormatPhp.php | 8 +- includes/api/ApiFormatWddx.php | 8 +- includes/api/ApiFormatXml.php | 8 +- includes/api/ApiFormatYaml.php | 8 +- includes/api/ApiFormatYaml_spyc.php | 13 +- includes/api/ApiHelp.php | 8 +- includes/api/ApiLogin.php | 6 +- includes/api/ApiMain.php | 9 +- includes/api/ApiOpenSearch.php | 8 +- includes/api/ApiPageSet.php | 16 +- includes/api/ApiQuery.php | 10 +- includes/api/ApiQueryAllpages.php | 8 +- includes/api/ApiQueryBacklinks.php | 10 +- includes/api/ApiQueryBase.php | 9 +- includes/api/ApiQueryInfo.php | 6 +- includes/api/ApiQueryLogEvents.php | 8 +- includes/api/ApiQueryRecentChanges.php | 10 +- includes/api/ApiQueryRevisions.php | 8 +- includes/api/ApiQuerySiteinfo.php | 8 +- includes/api/ApiQueryUserContributions.php | 8 +- includes/api/ApiQueryWatchlist.php | 6 +- includes/api/ApiResult.php | 8 +- includes/media/BMP.php | 31 + includes/media/Bitmap.php | 236 +++++ includes/media/DjVu.php | 206 +++++ includes/media/Generic.php | 298 +++++++ includes/media/SVG.php | 97 ++ includes/memcached-client.php | 2 +- includes/mime.info | 5 +- includes/mime.types | 1 + includes/normal/CleanUpTest.php | 36 +- includes/normal/Makefile | 36 +- includes/normal/README | 4 + includes/normal/RandomTest.php | 4 +- includes/normal/Utf8Test.php | 2 +- includes/normal/UtfNormal.php | 39 +- includes/normal/UtfNormalBench.php | 10 +- includes/normal/UtfNormalData.inc | 9 +- includes/normal/UtfNormalDataK.inc | 3 +- includes/normal/UtfNormalGenerate.php | 4 +- includes/normal/UtfNormalTest.php | 2 +- includes/normal/UtfNormalUtil.php | 2 +- includes/proxy_check.php | 1 - includes/templates/Userlogin.php | 9 +- includes/tidy.conf | 18 + 233 files changed, 10573 insertions(+), 6034 deletions(-) create mode 100644 includes/ImageQueryPage.php create mode 100644 includes/MediaTransformOutput.php create mode 100644 includes/OutputHandler.php create mode 100644 includes/PageQueryPage.php create mode 100644 includes/ParserOptions.php create mode 100644 includes/ParserOutput.php create mode 100644 includes/PatrolLog.php create mode 100644 includes/SearchOracle.php create mode 100644 includes/SpecialFewestrevisions.php create mode 100644 includes/SpecialProtectedpages.php create mode 100644 includes/SpecialWithoutinterwiki.php create mode 100644 includes/media/BMP.php create mode 100644 includes/media/Bitmap.php create mode 100644 includes/media/DjVu.php create mode 100644 includes/media/Generic.php create mode 100644 includes/media/SVG.php create mode 100644 includes/tidy.conf (limited to 'includes') diff --git a/includes/AjaxDispatcher.php b/includes/AjaxDispatcher.php index 39ec19f8..ca129029 100644 --- a/includes/AjaxDispatcher.php +++ b/includes/AjaxDispatcher.php @@ -1,7 +1,8 @@ mode = ""; @@ -28,14 +33,14 @@ class AjaxDispatcher { } if ($this->mode == "get") { - $this->func_name = $_GET["rs"]; + $this->func_name = isset( $_GET["rs"] ) ? $_GET["rs"] : ''; if (! empty($_GET["rsargs"])) { $this->args = $_GET["rsargs"]; } else { $this->args = array(); } } else { - $this->func_name = $_POST["rs"]; + $this->func_name = isset( $_POST["rs"] ) ? $_POST["rs"] : ''; if (! empty($_POST["rsargs"])) { $this->args = $_POST["rsargs"]; } else { @@ -47,7 +52,7 @@ class AjaxDispatcher { function performAction() { global $wgAjaxExportList, $wgOut; - + if ( empty( $this->mode ) ) { return; } @@ -59,7 +64,7 @@ class AjaxDispatcher { } else { try { $result = call_user_func_array($this->func_name, $this->args); - + if ( $result === false || $result === NULL ) { wfHttpError( 500, 'Internal Error', "{$this->func_name} returned no data" ); @@ -68,7 +73,7 @@ class AjaxDispatcher { if ( is_string( $result ) ) { $result= new AjaxResponse( $result ); } - + $result->sendHeaders(); $result->printText(); } @@ -82,7 +87,7 @@ class AjaxDispatcher { } } } - + wfProfileOut( __METHOD__ ); $wgOut = null; } diff --git a/includes/AjaxFunctions.php b/includes/AjaxFunctions.php index eee2a1a4..86f853db 100644 --- a/includes/AjaxFunctions.php +++ b/includes/AjaxFunctions.php @@ -1,7 +1,13 @@ ucfirst( @@ -81,7 +86,7 @@ function wfSajaxSearch( $term ) { if ( strlen( str_replace( '_', '', $term ) )<3 ) return; - $db =& wfGetDB( DB_SLAVE ); + $db = wfGetDB( DB_SLAVE ); $res = $db->select( 'page', 'page_title', array( 'page_namespace' => 0, "page_title LIKE '". $db->strencode( $term) ."%'" ), @@ -108,8 +113,8 @@ function wfSajaxSearch( $term ) { $subtitlemsg = ( Title::newFromText($term) ? 'searchsubtitle' : 'searchsubtitleinvalid' ); $subtitle = $wgOut->parse( wfMsg( $subtitlemsg, wfEscapeWikiText($term) ) ); #FIXME: parser is missing mTitle ! - $term = htmlspecialchars( $term ); - $html = '
' + $term = urlencode( $term ); + $html = '
' . wfMsg( 'hideresults' ) . '
' . '

'.wfMsg('search') . '

'. $subtitle . '

" . wfMsg( 'articletitles', $term ) . "

" . ''.$more; - + $response = new AjaxResponse( $html ); - + $response->setCacheDuration( 30*60 ); - + return $response; } @@ -152,14 +157,14 @@ function wfAjaxWatch($pageID = "", $watch = "") { if($watch) { if(!$watching) { - $dbw =& wfGetDB(DB_MASTER); + $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $article->doWatch(); $dbw->commit(); } } else { if($watching) { - $dbw =& wfGetDB(DB_MASTER); + $dbw = wfGetDB(DB_MASTER); $dbw->begin(); $article->doUnwatch(); $dbw->commit(); diff --git a/includes/AjaxResponse.php b/includes/AjaxResponse.php index a59c73bb..cb4af1b5 100644 --- a/includes/AjaxResponse.php +++ b/includes/AjaxResponse.php @@ -1,28 +1,32 @@ mCacheDuration = NULL; $this->mVary = NULL; - + $this->mDisabled = false; $this->mText = ''; $this->mResponseCode = '200 OK'; $this->mLastModified = false; $this->mContentType= 'text/html; charset=utf-8'; - + if ( $text ) { $this->addText( $text ); } @@ -39,15 +43,15 @@ class AjaxResponse { function setResponseCode( $code ) { $this->mResponseCode = $code; } - + function setContentType( $type ) { $this->mContentType = $type; } - + function disable() { $this->mDisabled = true; } - + function addText( $text ) { if ( ! $this->mDisabled && $text ) { $this->mText .= $text; @@ -59,62 +63,62 @@ class AjaxResponse { print $this->mText; } } - + function sendHeaders() { global $wgUseSquid, $wgUseESI; - + if ( $this->mResponseCode ) { $n = preg_replace( '/^ *(\d+)/', '\1', $this->mResponseCode ); header( "Status: " . $this->mResponseCode, true, (int)$n ); } - + header ("Content-Type: " . $this->mContentType ); - + if ( $this->mLastModified ) { header ("Last-Modified: " . $this->mLastModified ); } else { header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); } - + if ( $this->mCacheDuration ) { - + # If squid caches are configured, tell them to cache the response, # and tell the client to always check with the squid. Otherwise, # tell the client to use a cached copy, without a way to purge it. - + if( $wgUseSquid ) { - + # Expect explicite purge of the proxy cache, but require end user agents # to revalidate against the proxy on each visit. # Surrogate-Control controls our Squid, Cache-Control downstream caches - + if ( $wgUseESI ) { header( 'Surrogate-Control: max-age='.$this->mCacheDuration.', content="ESI/1.0"'); header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' ); } else { header( 'Cache-Control: s-maxage='.$this->mCacheDuration.', must-revalidate, max-age=0' ); } - + } else { - + # Let the client do the caching. Cache is not purged. header ("Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT"); header ("Cache-Control: s-max-age={$this->mCacheDuration},public,max-age={$this->mCacheDuration}"); } - + } else { # always expired, always modified header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header ("Pragma: no-cache"); // HTTP/1.0 } - + if ( $this->mVary ) { header ( "Vary: " . $this->mVary ); } } - + /** * checkLastModified tells the client to use the client-cached response if * possible. If sucessful, the AjaxResponse is disabled so that @@ -154,9 +158,9 @@ class AjaxResponse { $this->setResponseCode( "304 Not Modified" ); $this->disable(); $this->mLastModified = $lastmod; - + wfDebug( "$fname: CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp ; site $wgCacheEpoch\n", false ); - + return true; } else { wfDebug( "$fname: READY client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp ; site $wgCacheEpoch\n", false ); @@ -167,11 +171,11 @@ class AjaxResponse { $this->mLastModified = $lastmod; } } - + function loadFromMemcached( $mckey, $touched ) { global $wgMemc; if ( !$touched ) return false; - + $mcvalue = $wgMemc->get( $mckey ); if ( $mcvalue ) { # Check to see if the value has been invalidated @@ -183,20 +187,20 @@ class AjaxResponse { wfDebug( "$mckey has expired\n" ); } } - + return false; } - + function storeInMemcached( $mckey, $expiry = 86400 ) { global $wgMemc; - - $wgMemc->set( $mckey, + + $wgMemc->set( $mckey, array( 'timestamp' => wfTimestampNow(), 'value' => $this->mText ), $expiry ); - + return true; } } diff --git a/includes/Article.php b/includes/Article.php index 6b4f5270..0130ceba 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -1,7 +1,6 @@ mTitle =& $title; $this->mOldId = $oldId; $this->clear(); @@ -57,14 +55,14 @@ class Article { function setRedirectedFrom( $from ) { $this->mRedirectedFrom = $from; } - + /** * @return mixed false, Title of in-wiki target, or string with URL */ function followRedirect() { $text = $this->getContent(); $rt = Title::newFromRedirect( $text ); - + # process if title object is valid and not special:userlogout if( $rt ) { if( $rt->getInterwiki() != '' ) { @@ -73,7 +71,7 @@ class Article { // // This can be hard to reverse and may produce loops, // so they may be disabled in the site configuration. - + $source = $this->mTitle->getFullURL( 'redirect=no' ); return $rt->getFullURL( 'rdfrom=' . urlencode( $source ) ); } @@ -84,7 +82,7 @@ class Article { // the rest of the page we're on. // // This can be hard to reverse, so they may be disabled. - + if( $rt->isSpecial( 'Userlogout' ) ) { // rolleyes } else { @@ -94,7 +92,7 @@ class Article { return $rt; } } - + // No or invalid redirect return false; } @@ -247,7 +245,7 @@ class Article { * @param array $conditions * @private */ - function pageData( &$dbr, $conditions ) { + function pageData( $dbr, $conditions ) { $fields = array( 'page_id', 'page_namespace', @@ -273,7 +271,7 @@ class Article { * @param Database $dbr * @param Title $title */ - function pageDataFromTitle( &$dbr, $title ) { + function pageDataFromTitle( $dbr, $title ) { return $this->pageData( $dbr, array( 'page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey() ) ); @@ -283,7 +281,7 @@ class Article { * @param Database $dbr * @param int $id */ - function pageDataFromId( &$dbr, $id ) { + function pageDataFromId( $dbr, $id ) { return $this->pageData( $dbr, array( 'page_id' => $id ) ); } @@ -296,17 +294,18 @@ class Article { */ function loadPageData( $data = 'fromdb' ) { if ( $data === 'fromdb' ) { - $dbr =& $this->getDB(); + $dbr = $this->getDB(); $data = $this->pageDataFromId( $dbr, $this->getId() ); } - + $lc =& LinkCache::singleton(); if ( $data ) { $lc->addGoodLinkObj( $data->page_id, $this->mTitle ); $this->mTitle->mArticleID = $data->page_id; + + # Old-fashioned restrictions. $this->mTitle->loadRestrictions( $data->page_restrictions ); - $this->mTitle->mRestrictionsLoaded = true; $this->mCounter = $data->page_counter; $this->mTouched = wfTimestamp( TS_MW, $data->page_touched ); @@ -333,7 +332,7 @@ class Article { return $this->mContent; } - $dbr =& $this->getDB(); + $dbr = $this->getDB(); # Pre-fill content with error message so that if something # fails we'll have something telling us what we intended. @@ -405,9 +404,8 @@ class Article { * * @return Database */ - function &getDB() { - $ret =& wfGetDB( DB_MASTER ); - return $ret; + function getDB() { + return wfGetDB( DB_MASTER ); } /** @@ -455,7 +453,7 @@ class Article { if ( $id == 0 ) { $this->mCounter = 0; } else { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $this->mCounter = $dbr->selectField( 'page', 'page_counter', array( 'page_id' => $id ), 'Article::getCount', $this->getSelectOptions() ); } @@ -471,12 +469,12 @@ class Article { * @return bool */ function isCountable( $text ) { - global $wgUseCommaCount, $wgContentNamespaces; + global $wgUseCommaCount; $token = $wgUseCommaCount ? ',' : '[['; return - array_search( $this->mTitle->getNamespace(), $wgContentNamespaces ) !== false - && ! $this->isRedirect( $text ) + $this->mTitle->isContentPage() + && !$this->isRedirect( $text ) && in_string( $token, $text ); } @@ -573,7 +571,7 @@ class Article { # XXX: this is expensive; cache this info somewhere. $contribs = array(); - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $revTable = $dbr->tableName( 'revision' ); $userTable = $dbr->tableName( 'user' ); $user = $this->getUser(); @@ -613,7 +611,7 @@ class Article { $parserCache =& ParserCache::singleton(); $ns = $this->mTitle->getNamespace(); # shortcut - + # Get variables from query string $oldid = $this->getOldID(); @@ -627,16 +625,21 @@ class Article { $diff = $wgRequest->getVal( 'diff' ); $rcid = $wgRequest->getVal( 'rcid' ); $rdfrom = $wgRequest->getVal( 'rdfrom' ); + $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); $wgOut->setArticleFlag( true ); - if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) { + + # Discourage indexing of printable versions, but encourage following + if( $wgOut->isPrintable() ) { + $policy = 'noindex,follow'; + } elseif( isset( $wgNamespaceRobotPolicies[$ns] ) ) { + # Honour customised robot policies for this namespace $policy = $wgNamespaceRobotPolicies[$ns]; } else { - # The default policy. Dev note: make sure you change the documentation - # in DefaultSettings.php before changing it. + # Default to encourage indexing and following links $policy = 'index,follow'; } - $wgOut->setRobotpolicy( $policy ); + $wgOut->setRobotPolicy( $policy ); # If we got diff and oldid in the query, we want to see a # diff page instead of the article. @@ -647,8 +650,8 @@ class Article { $de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid ); // DifferenceEngine directly fetched the revision: $this->mRevIdFetched = $de->mNewid; - $de->showDiffPage(); - + $de->showDiffPage( $diffOnly ); + // Needed to get the page's current revision $this->loadPageData(); if( $diff == 0 || $diff == $this->mLatest ) { @@ -658,7 +661,7 @@ class Article { wfProfileOut( __METHOD__ ); return; } - + if ( empty( $oldid ) && $this->checkTouched() ) { $wgOut->setETag($parserCache->getETag($this, $wgUser)); @@ -713,11 +716,11 @@ class Article { $wasRedirected = true; } } - + $outputDone = false; + wfRunHooks( 'ArticleViewHeader', array( &$this ) ); if ( $pcache ) { if ( $wgOut->tryParserCache( $this, $wgUser ) ) { - wfRunHooks( 'ArticleViewHeader', array( &$this ) ); $outputDone = true; } } @@ -764,17 +767,12 @@ class Article { } } if( !$outputDone ) { - /** - * @fixme: this hook doesn't work most of the time, as it doesn't - * trigger when the parser cache is used. - */ - wfRunHooks( 'ArticleViewHeader', array( &$this ) ) ; $wgOut->setRevisionId( $this->getRevIdFetched() ); # wrap user css and user js in pre and don't parse # XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found if ( $ns == NS_USER && - preg_match('/\\/[\\w]+\\.(css|js)$/', $this->mTitle->getDBkey()) + preg_match('/\\/[\\w]+\\.(?:css|js)$/', $this->mTitle->getDBkey()) ) { $wgOut->addWikiText( wfMsg('clearyourcache')); $wgOut->addHTML( '
'.htmlspecialchars($this->mContent)."\n
" ); @@ -795,7 +793,7 @@ class Article { $wgOut->addParserOutputNoText( $parseout ); } else if ( $pcache ) { # Display content and save to parser cache - $wgOut->addPrimaryWikiText( $text, $this ); + $this->outputWikiText( $text ); } else { # Display content, don't attempt to save to parser cache # Don't show section-edit links on old revisions... this way lies madness. @@ -803,11 +801,21 @@ class Article { $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false ); } # Display content and don't save to parser cache - $wgOut->addPrimaryWikiText( $text, $this, false ); + # With timing hack -- TS 2006-07-26 + $time = -wfTime(); + $this->outputWikiText( $text, false ); + $time += wfTime(); + + # Timing hack + if ( $time > 3 ) { + wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time, + $this->mTitle->getPrefixedDBkey())); + } if( !$this->isCurrent() ) { $wgOut->parserOptions()->setEditSection( $oldEditSectionSetting ); } + } } /* title may have been set from the cache */ @@ -827,8 +835,9 @@ class Article { if ( $wgUseRCPatrol && !is_null( $rcid ) && $rcid != 0 && $wgUser->isAllowed( 'patrol' ) ) { $wgOut->addHTML( "' ); @@ -845,7 +854,7 @@ class Article { function addTrackbacks() { global $wgOut, $wgUser; - $dbr =& wfGetDB(DB_SLAVE); + $dbr = wfGetDB(DB_SLAVE); $tbs = $dbr->select( /* FROM */ 'trackbacks', /* SELECT */ array('tb_id', 'tb_title', 'tb_url', 'tb_ex', 'tb_name'), @@ -891,7 +900,7 @@ class Article { return; } - $db =& wfGetDB(DB_MASTER); + $db = wfGetDB(DB_MASTER); $db->delete('trackbacks', array('tb_id' => $wgRequest->getInt('tbid'))); $wgTitle->invalidateCache(); $wgOut->addWikiText(wfMsg('trackbackdeleteok')); @@ -910,7 +919,7 @@ class Article { function purge() { global $wgUser, $wgRequest, $wgOut; - if ( $wgUser->isLoggedIn() || $wgRequest->wasPosted() ) { + if ( $wgUser->isAllowed( 'purge' ) || $wgRequest->wasPosted() ) { if( wfRunHooks( 'ArticlePurge', array( &$this ) ) ) { $this->doPurge(); } @@ -928,7 +937,7 @@ class Article { $wgOut->addHTML( $msg ); } } - + /** * Perform the actions of a page purging */ @@ -957,11 +966,10 @@ class Article { * Best if all done inside a transaction. * * @param Database $dbw - * @param string $restrictions * @return int The newly created page_id key * @private */ - function insertOn( &$dbw, $restrictions = '' ) { + function insertOn( $dbw ) { wfProfileIn( __METHOD__ ); $page_id = $dbw->nextSequenceValue( 'page_page_id_seq' ); @@ -970,7 +978,7 @@ class Article { 'page_namespace' => $this->mTitle->getNamespace(), 'page_title' => $this->mTitle->getDBkey(), 'page_counter' => 0, - 'page_restrictions' => $restrictions, + 'page_restrictions' => '', 'page_is_redirect' => 0, # Will set this shortly... 'page_is_new' => 1, 'page_random' => wfRandom(), @@ -996,7 +1004,7 @@ class Article { * when different from the currently set value. * Giving 0 indicates the new page flag should * be set on. - * @param bool $lastRevIsRedirect If given, will optimize adding and + * @param bool $lastRevIsRedirect If given, will optimize adding and * removing rows in redirect table. * @return bool true on success, false on failure * @private @@ -1006,7 +1014,7 @@ class Article { $text = $revision->getText(); $rt = Title::newFromRedirect( $text ); - + $conditions = array( 'page_id' => $this->getId() ); if( !is_null( $lastRevision ) ) { # An extra check against threads stepping on each other @@ -1028,20 +1036,20 @@ class Article { if ($result) { // FIXME: Should the result from updateRedirectOn() be returned instead? - $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); + $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); } - + wfProfileOut( __METHOD__ ); return $result; } /** - * Add row to the redirect table if this is a redirect, remove otherwise. + * Add row to the redirect table if this is a redirect, remove otherwise. * * @param Database $dbw * @param $redirectTitle a title object pointing to the redirect target, - * or NULL if this is not a redirect - * @param bool $lastRevIsRedirect If given, will optimize adding and + * or NULL if this is not a redirect + * @param bool $lastRevIsRedirect If given, will optimize adding and * removing rows in redirect table. * @return bool true on success, false on failure * @private @@ -1067,7 +1075,7 @@ class Article { $dbw->replace( 'redirect', array( 'rd_from' ), $set, __METHOD__ ); } else { - // This is not a redirect, remove row from redirect table + // This is not a redirect, remove row from redirect table $where = array( 'rd_from' => $this->getId() ); $dbw->delete( 'redirect', $where, __METHOD__); } @@ -1075,7 +1083,7 @@ class Article { wfProfileOut( __METHOD__ ); return ( $dbw->affectedRows() != 0 ); } - + return true; } @@ -1119,14 +1127,14 @@ class Article { */ function replaceSection($section, $text, $summary = '', $edittime = NULL) { wfProfileIn( __METHOD__ ); - + if( $section == '' ) { // Whole-page edit; let the text through unmolested. } else { if( is_null( $edittime ) ) { $rev = Revision::newFromTitle( $this->mTitle ); } else { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); } if( is_null( $rev ) ) { @@ -1166,10 +1174,10 @@ class Article { if ( $comment && $summary != "" ) { $text = "== {$summary} ==\n\n".$text; } - + $this->doEdit( $text, $summary, $flags ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); if ($watchthis) { if (!$this->mTitle->userIsWatching()) { $dbw->begin(); @@ -1196,7 +1204,7 @@ class Article { $good = $this->doEdit( $text, $summary, $flags ); if ( $good ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); if ($watchthis) { if (!$this->mTitle->userIsWatching()) { $dbw->begin(); @@ -1219,7 +1227,7 @@ class Article { /** * Article::doEdit() * - * Change an existing article or create a new article. Updates RC and all necessary caches, + * Change an existing article or create a new article. Updates RC and all necessary caches, * optionally via the deferred update array. * * $wgUser must be set before calling this function. @@ -1241,9 +1249,9 @@ class Article { * Defer some of the updates until the end of index.php * EDIT_AUTOSUMMARY * Fill in blank summaries with generated text where possible - * - * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected. - * If EDIT_UPDATE is specified and the article doesn't exist, the function will return false. If + * + * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected. + * If EDIT_UPDATE is specified and the article doesn't exist, the function will return false. If * EDIT_NEW is specified and the article does exist, a duplicate key error will cause an exception * to be thrown from the Database. These two conditions are also possible with auto-detection due * to MediaWiki's performance-optimised locking strategy. @@ -1267,7 +1275,7 @@ class Article { if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text, &$summary, $flags & EDIT_MINOR, - null, null, &$flags ) ) ) + null, null, &$flags ) ) ) { wfDebug( __METHOD__ . ": ArticleSave hook aborted save!\n" ); wfProfileOut( __METHOD__ ); @@ -1288,9 +1296,9 @@ class Article { $text = $this->preSaveTransform( $text ); $newsize = strlen( $text ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $now = wfTimestampNow(); - + if ( $flags & EDIT_UPDATE ) { # Update article, but only if changed. @@ -1316,7 +1324,7 @@ class Article { wfProfileOut( __METHOD__ ); return false; } - + $revision = new Revision( array( 'page' => $this->getId(), 'comment' => $summary, @@ -1340,10 +1348,11 @@ class Article { $rcid = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $wgUser, $summary, $lastRevision, $this->getTimestamp(), $bot, '', $oldsize, $newsize, $revisionId ); - + # Mark as patrolled if the user can do so - if( $wgUser->isAllowed( 'autopatrol' ) ) { + if( $GLOBALS['wgUseRCPatrol'] && $wgUser->isAllowed( 'autopatrol' ) ) { RecentChange::markPatrolled( $rcid ); + PatrolLog::record( $rcid, true ); } } $wgUser->incEditCount(); @@ -1362,19 +1371,19 @@ class Article { } if ( $good ) { - # Invalidate cache of this article and all pages using this article + # Invalidate cache of this article and all pages using this article # as a template. Partly deferred. Article::onArticleEdit( $this->mTitle ); - + # Update links tables, site stats, etc. $changed = ( strcmp( $oldtext, $text ) != 0 ); $this->editUpdates( $text, $summary, $isminor, $now, $revisionId, $changed ); } } else { # Create new article - + # Set statistics members - # We work out if it's countable after PST to avoid counter drift + # We work out if it's countable after PST to avoid counter drift # when articles are created with {{subst:}} $this->mGoodAdjustment = (int)$this->isCountable( $text ); $this->mTotalAdjustment = 1; @@ -1403,8 +1412,9 @@ class Article { $rcid = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary, $bot, '', strlen( $text ), $revisionId ); # Mark as patrolled if the user can - if( $wgUser->isAllowed( 'autopatrol' ) ) { + if( $GLOBALS['wgUseRCPatrol'] && $wgUser->isAllowed( 'autopatrol' ) ) { RecentChange::markPatrolled( $rcid ); + PatrolLog::record( $rcid, true ); } } $wgUser->incEditCount(); @@ -1429,7 +1439,7 @@ class Article { array( &$this, &$wgUser, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags ) ); - + wfProfileOut( __METHOD__ ); return $good; } @@ -1457,7 +1467,7 @@ class Article { } $wgOut->redirect( $this->mTitle->getFullURL( $query ) . $sectionAnchor ); } - + /** * Mark this particular edit as patrolled */ @@ -1470,25 +1480,25 @@ class Article { $wgOut->errorPage( 'rcpatroldisabled', 'rcpatroldisabledtext' ); return; } - + # Check permissions if( !$wgUser->isAllowed( 'patrol' ) ) { $wgOut->permissionRequired( 'patrol' ); return; } - + # If we haven't been given an rc_id value, we can't do anything $rcid = $wgRequest->getVal( 'rcid' ); if( !$rcid ) { $wgOut->errorPage( 'markedaspatrollederror', 'markedaspatrollederrortext' ); return; } - + # Handle the 'MarkPatrolled' hook if( !wfRunHooks( 'MarkPatrolled', array( $rcid, &$wgUser, false ) ) ) { return; } - + $return = SpecialPage::getTitleFor( 'Recentchanges' ); # If it's left up to us, check that the user is allowed to patrol this edit # If the user has the "autopatrol" right, then we'll assume there are no @@ -1507,11 +1517,12 @@ class Article { return; } } - + # Mark the edit as patrolled RecentChange::markPatrolled( $rcid ); + PatrolLog::record( $rcid ); wfRunHooks( 'MarkPatrolledComplete', array( &$rcid, &$wgUser, false ) ); - + # Inform the user $wgOut->setPageTitle( wfMsg( 'markedaspatrolled' ) ); $wgOut->addWikiText( wfMsgNoTrans( 'markedaspatrolledtext' ) ); @@ -1534,7 +1545,7 @@ class Article { $wgOut->readOnlyPage(); return; } - + if( $this->doWatch() ) { $wgOut->setPagetitle( wfMsg( 'addedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); @@ -1546,7 +1557,7 @@ class Article { $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } - + /** * Add this page to $wgUser's watchlist * @return bool true on successful watch operation @@ -1556,13 +1567,13 @@ class Article { if( $wgUser->isAnon() ) { return false; } - + if (wfRunHooks('WatchArticle', array(&$wgUser, &$this))) { $wgUser->addWatch( $this->mTitle ); return wfRunHooks('WatchArticleComplete', array(&$wgUser, &$this)); } - + return false; } @@ -1581,7 +1592,7 @@ class Article { $wgOut->readOnlyPage(); return; } - + if( $this->doUnwatch() ) { $wgOut->setPagetitle( wfMsg( 'removedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); @@ -1593,7 +1604,7 @@ class Article { $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } - + /** * Stop watching a page * @return bool true on successful unwatch @@ -1609,7 +1620,7 @@ class Article { return wfRunHooks('UnwatchArticleComplete', array(&$wgUser, &$this)); } - + return false; } @@ -1618,7 +1629,7 @@ class Article { */ function protect() { $form = new ProtectionForm( $this ); - $form->show(); + $form->execute(); } /** @@ -1635,14 +1646,21 @@ class Article { * @param string $reason * @return bool true on success */ - function updateRestrictions( $limit = array(), $reason = '' ) { + function updateRestrictions( $limit = array(), $reason = '', $cascade = 0, $expiry = null ) { global $wgUser, $wgRestrictionTypes, $wgContLang; - + $id = $this->mTitle->getArticleID(); if( !$wgUser->isAllowed( 'protect' ) || wfReadOnly() || $id == 0 ) { return false; } + if (!$cascade) { + $cascade = false; + } + + // Take this opportunity to purge out expired restrictions + Title::purgeExpiredRestrictions(); + # FIXME: Same limitations as described in ProtectionForm.php (line 37); # we expect a single selection, but the schema allows otherwise. $current = array(); @@ -1651,48 +1669,89 @@ class Article { $current = Article::flattenRestrictions( $current ); $updated = Article::flattenRestrictions( $limit ); - + $changed = ( $current != $updated ); + $changed = $changed || ($this->mTitle->areRestrictionsCascading() != $cascade); + $changed = $changed || ($this->mTitle->mRestrictionsExpiry != $expiry); $protect = ( $updated != '' ); - + # If nothing's changed, do nothing if( $changed ) { + global $wgGroupPermissions; if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser, $limit, $reason ) ) ) { - $dbw =& wfGetDB( DB_MASTER ); - + $dbw = wfGetDB( DB_MASTER ); + + $encodedExpiry = Block::encodeExpiry($expiry, $dbw ); + + $expiry_description = ''; + if ( $encodedExpiry != 'infinity' ) { + $expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ) ).')'; + } + # Prepare a null revision to be added to the history $comment = $wgContLang->ucfirst( wfMsgForContent( $protect ? 'protectedarticle' : 'unprotectedarticle', $this->mTitle->getPrefixedText() ) ); + + foreach( $limit as $action => $restrictions ) { + # Check if the group level required to edit also can protect pages + # Otherwise, people who cannot normally protect can "protect" pages via transclusion + $cascade = ( $cascade && isset($wgGroupPermissions[$restrictions]['protect']) && $wgGroupPermissions[$restrictions]['protect'] ); + } + + $cascade_description = ''; + if ($cascade) { + $cascade_description = ' ['.wfMsg('protect-summary-cascade').']'; + } + if( $reason ) $comment .= ": $reason"; if( $protect ) $comment .= " [$updated]"; + if ( $expiry_description && $protect ) + $comment .= "$expiry_description"; + if ( $cascade ) + $comment .= "$cascade_description"; + $nullRevision = Revision::newNullRevision( $dbw, $id, $comment, true ); $nullRevId = $nullRevision->insertOn( $dbw ); - + + # Update restrictions table + foreach( $limit as $action => $restrictions ) { + if ($restrictions != '' ) { + $dbw->replace( 'page_restrictions', array(array('pr_page', 'pr_type')), + array( 'pr_page' => $id, 'pr_type' => $action + , 'pr_level' => $restrictions, 'pr_cascade' => $cascade ? 1 : 0 + , 'pr_expiry' => $encodedExpiry ), __METHOD__ ); + } else { + $dbw->delete( 'page_restrictions', array( 'pr_page' => $id, + 'pr_type' => $action ), __METHOD__ ); + } + } + # Update page record $dbw->update( 'page', array( /* SET */ 'page_touched' => $dbw->timestamp(), - 'page_restrictions' => $updated, + 'page_restrictions' => '', 'page_latest' => $nullRevId ), array( /* WHERE */ 'page_id' => $id ), 'Article::protect' ); wfRunHooks( 'ArticleProtectComplete', array( &$this, &$wgUser, $limit, $reason ) ); - + # Update the protection log $log = new LogPage( 'protect' ); + if( $protect ) { - $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$updated]" ) ); + $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$updated]$cascade_description$expiry_description" ) ); } else { $log->addEntry( 'unprotect', $this->mTitle, $reason ); } - + } # End hook } # End "changed" check - + return true; } @@ -1745,9 +1804,9 @@ class Article { } $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) ); - + # Better double-check that it hasn't been deleted yet! - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $conds = $this->mTitle->pageCond(); $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ ); if ( $latest === false ) { @@ -1769,7 +1828,7 @@ class Article { # and insert a warning if it does $maxRevisions = 20; $authors = $this->getLastNAuthors( $maxRevisions, $latest ); - + if( count( $authors ) > 1 && !$confirm ) { $skin=$wgUser->getSkin(); $wgOut->addHTML( '' . wfMsg( 'historywarning' ) . ' ' . $skin->historyLink() . '' ); @@ -1813,7 +1872,7 @@ class Article { $reason = wfMsgForContent( 'exblank' ); } - if( $length < 500 && $reason === '' ) { + if( $reason === '' ) { # comment field=255, let's grep the first 150 to have some user # space left global $wgContLang; @@ -1849,7 +1908,7 @@ class Article { // First try the slave // If that doesn't have the latest revision, try the master $continue = 2; - $db =& wfGetDB( DB_SLAVE ); + $db = wfGetDB( DB_SLAVE ); do { $res = $db->select( array( 'page', 'revision' ), array( 'rev_id', 'rev_user_text' ), @@ -1868,7 +1927,7 @@ class Article { } $row = $db->fetchObject( $res ); if ( $continue == 2 && $revLatest && $row->rev_id != $revLatest ) { - $db =& wfGetDB( DB_MASTER ); + $db = wfGetDB( DB_MASTER ); $continue--; } else { $continue = 0; @@ -1882,7 +1941,7 @@ class Article { wfProfileOut( __METHOD__ ); return $authors; } - + /** * Output deletion confirmation dialog */ @@ -1929,6 +1988,23 @@ class Article { \n" ); $wgOut->returnToMain( false ); + + $this->showLogExtract( $wgOut ); + } + + + /** + * Fetch deletion log + */ + function showLogExtract( &$out ) { + # Show relevant lines from the deletion log: + $out->addHTML( "

" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "

\n" ); + $logViewer = new LogViewer( + new LogReader( + new FauxRequest( + array( 'page' => $this->mTitle->getPrefixedText(), + 'type' => 'delete' ) ) ) ); + $logViewer->showList( $out ); } @@ -1969,7 +2045,7 @@ class Article { wfDebug( __METHOD__."\n" ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $ns = $this->mTitle->getNamespace(); $t = $this->mTitle->getDBkey(); $id = $this->mTitle->getArticleID(); @@ -2004,12 +2080,16 @@ class Article { 'ar_text_id' => 'rev_text_id', 'ar_text' => '\'\'', // Be explicit to appease 'ar_flags' => '\'\'', // MySQL's "strict mode"... + 'ar_len' => 'rev_len' ), array( 'page_id' => $id, 'page_id = rev_page' ), __METHOD__ ); + # Delete restrictions for it + $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ ); + # Now that it's safely backed up, delete it $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__); @@ -2078,7 +2158,7 @@ class Article { $wgOut->addWikiText( wfMsg( 'sessionfailure' ) ); return; } - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); # Enhanced rollback, marks edits rc_bot=1 $bot = $wgRequest->getBool( 'bot' ); @@ -2103,7 +2183,7 @@ class Article { if( $current->getComment() != '') { $wgOut->addHTML( wfMsg( 'editcomment', - htmlspecialchars( $current->getComment() ) ) ); + $wgUser->getSkin()->formatComment( $current->getComment() ) ) ); } return; } @@ -2189,7 +2269,7 @@ class Article { * Do standard deferred updates after page edit. * Update links tables, site stats, search index and message cache. * Every 1000th edit, prune the recent changes table. - * + * * @private * @param $text New text of the article * @param $summary Edit summary @@ -2222,7 +2302,7 @@ class Article { # Periodically flush old entries from the recentchanges table. global $wgRCMaxAge; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); $recentchanges = $dbw->tableName( 'recentchanges' ); $sql = "DELETE FROM $recentchanges WHERE rc_timestamp < '{$cutoff}'"; @@ -2269,13 +2349,13 @@ class Article { wfProfileOut( __METHOD__ ); } - + /** * Perform article updates on a special page creation. * * @param Revision $rev * - * @fixme This is a shitty interface function. Kill it and replace the + * @todo This is a shitty interface function. Kill it and replace the * other shitty functions like editUpdates and such so it's not needed * anymore. */ @@ -2299,8 +2379,8 @@ class Article { global $wgLang, $wgOut, $wgUser; if ( !wfRunHooks( 'DisplayOldSubtitle', array(&$this, &$oldid) ) ) { - return; - } + return; + } $revision = Revision::newFromId( $oldid ); @@ -2326,10 +2406,10 @@ class Article { $nextdiff = $current ? wfMsg( 'diff' ) : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=next&oldid='.$oldid ); - + $userlinks = $sk->userLink( $revision->getUser(), $revision->getUserText() ) . $sk->userToolLinks( $revision->getUser(), $revision->getUserText() ); - + $r = "\n\t\t\t\t
" . wfMsg( 'revision-info', $td, $userlinks ) . "
\n" . "\n\t\t\t\t
" . wfMsg( 'revision-nav', $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "
\n\t\t\t"; $wgOut->setSubtitle( $r ); @@ -2381,25 +2461,40 @@ class Article { * @return bool */ function isFileCacheable() { - global $wgUser, $wgUseFileCache, $wgShowIPinHeader, $wgRequest; + global $wgUser, $wgUseFileCache, $wgShowIPinHeader, $wgRequest, $wgLang, $wgContLang; $action = $wgRequest->getVal( 'action' ); $oldid = $wgRequest->getVal( 'oldid' ); $diff = $wgRequest->getVal( 'diff' ); $redirect = $wgRequest->getVal( 'redirect' ); $printable = $wgRequest->getVal( 'printable' ); + $page = $wgRequest->getVal( 'page' ); + + //check for non-standard user language; this covers uselang, + //and extensions for auto-detecting user language. + $ulang = $wgLang->getCode(); + $clang = $wgContLang->getCode(); - return $wgUseFileCache - and (!$wgShowIPinHeader) - and ($this->getID() != 0) - and ($wgUser->isAnon()) - and (!$wgUser->getNewtalk()) - and ($this->mTitle->getNamespace() != NS_SPECIAL ) - and (empty( $action ) || $action == 'view') - and (!isset($oldid)) - and (!isset($diff)) - and (!isset($redirect)) - and (!isset($printable)) - and (!$this->mRedirectedFrom); + $cacheable = $wgUseFileCache + && (!$wgShowIPinHeader) + && ($this->getID() != 0) + && ($wgUser->isAnon()) + && (!$wgUser->getNewtalk()) + && ($this->mTitle->getNamespace() != NS_SPECIAL ) + && (empty( $action ) || $action == 'view') + && (!isset($oldid)) + && (!isset($diff)) + && (!isset($redirect)) + && (!isset($printable)) + && !isset($page) + && (!$this->mRedirectedFrom) + && ($ulang === $clang); + + if ( $cacheable ) { + //extension may have reason to disable file caching on some pages. + $cacheable = wfRunHooks( 'IsFileCacheable', array( $this ) ); + } + + return $cacheable; } /** @@ -2446,7 +2541,7 @@ class Article { function quickEdit( $text, $comment = '', $minor = 0 ) { wfProfileIn( __METHOD__ ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $revision = new Revision( array( 'page' => $this->getId(), @@ -2471,7 +2566,7 @@ class Article { $id = intval( $id ); global $wgHitcounterUpdateFreq, $wgDBtype; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $pageTable = $dbw->tableName( 'page' ); $hitcounterTable = $dbw->tableName( 'hitcounter' ); $acchitsTable = $dbw->tableName( 'acchits' ); @@ -2555,7 +2650,7 @@ class Article { $title->touchLinks(); $title->purgeSquid(); - + # File cache if ( $wgUseFileCache ) { $cm = new HTMLFileCache( $title ); @@ -2617,7 +2712,7 @@ class Article { $wgOut->addHTML(wfMsg( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon' ) ); } } else { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $wl_clause = array( 'wl_title' => $page->getDBkey(), 'wl_namespace' => $page->getNamespace() ); @@ -2659,7 +2754,7 @@ class Article { return false; } - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $rev_clause = array( 'rev_page' => $id ); @@ -2693,7 +2788,7 @@ class Article { return array(); } - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( array( 'templatelinks' ), array( 'tl_namespace', 'tl_title' ), array( 'tl_from' => $id ), @@ -2708,7 +2803,7 @@ class Article { $dbr->freeResult( $res ); return $result; } - + /** * Return an auto-generated summary if the text provided is a redirect. * @@ -2785,6 +2880,84 @@ class Article { return $summary; } + + /** + * Add the primary page-view wikitext to the output buffer + * Saves the text into the parser cache if possible. + * Updates templatelinks if it is out of date. + * + * @param string $text + * @param bool $cache + */ + public function outputWikiText( $text, $cache = true ) { + global $wgParser, $wgUser, $wgOut; + + $popts = $wgOut->parserOptions(); + $popts->setTidy(true); + $parserOutput = $wgParser->parse( $text, $this->mTitle, + $popts, true, true, $this->getRevIdFetched() ); + $popts->setTidy(false); + if ( $cache && $this && $parserOutput->getCacheTime() != -1 ) { + $parserCache =& ParserCache::singleton(); + $parserCache->save( $parserOutput, $this, $wgUser ); + } + + if ( !wfReadOnly() && $this->mTitle->areRestrictionsCascading() ) { + // templatelinks table may have become out of sync, + // especially if using variable-based transclusions. + // For paranoia, check if things have changed and if + // so apply updates to the database. This will ensure + // that cascaded protections apply as soon as the changes + // are visible. + + # Get templates from templatelinks + $id = $this->mTitle->getArticleID(); + + $tlTemplates = array(); + + $dbr = wfGetDB( DB_SLAVE ); + $res = $dbr->select( array( 'templatelinks' ), + array( 'tl_namespace', 'tl_title' ), + array( 'tl_from' => $id ), + 'Article:getUsedTemplates' ); + + global $wgContLang; + + if ( false !== $res ) { + if ( $dbr->numRows( $res ) ) { + while ( $row = $dbr->fetchObject( $res ) ) { + $tlTemplates[] = $wgContLang->getNsText( $row->tl_namespace ) . ':' . $row->tl_title ; + } + } + } + + # Get templates from parser output. + $poTemplates_allns = $parserOutput->getTemplates(); + + $poTemplates = array (); + foreach ( $poTemplates_allns as $ns_templates ) { + $poTemplates = array_merge( $poTemplates, $ns_templates ); + } + + # Get the diff + $templates_diff = array_diff( $poTemplates, $tlTemplates ); + + if ( count( $templates_diff ) > 0 ) { + # Whee, link updates time. + $u = new LinksUpdate( $this->mTitle, $parserOutput ); + + $dbw = wfGetDb( DB_MASTER ); + $dbw->begin(); + + $u->doUpdate(); + + $dbw->commit(); + } + } + + $wgOut->addParserOutput( $parserOutput ); + } + } ?> diff --git a/includes/AuthPlugin.php b/includes/AuthPlugin.php index e33ef1bf..9395032f 100644 --- a/includes/AuthPlugin.php +++ b/includes/AuthPlugin.php @@ -1,6 +1,5 @@ # http://www.mediawiki.org/ @@ -33,7 +32,6 @@ * This interface is new, and might change a bit before 1.4.0 final is * done... * - * @package MediaWiki */ class AuthPlugin { /** @@ -187,12 +185,14 @@ class AuthPlugin { * Add a user to the external authentication database. * Return true if successful. * - * @param User $user + * @param User $user - only the name should be assumed valid at this point * @param string $password + * @param string $email + * @param string $realname * @return bool * @public */ - function addUser( $user, $password ) { + function addUser( $user, $password, $email='', $realname='' ) { return true; } diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 8de5608f..72a71c71 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -8,9 +8,11 @@ function __autoload($className) { global $wgAutoloadClasses; static $localClasses = array( + # Includes 'AjaxDispatcher' => 'includes/AjaxDispatcher.php', 'AjaxCachePolicy' => 'includes/AjaxFunctions.php', 'AjaxResponse' => 'includes/AjaxResponse.php', + 'AlphabeticPager' => 'includes/Pager.php', 'Article' => 'includes/Article.php', 'AuthPlugin' => 'includes/AuthPlugin.php', 'BagOStuff' => 'includes/BagOStuff.php', @@ -39,9 +41,8 @@ function __autoload($className) { 'Database' => 'includes/Database.php', 'DatabaseMysql' => 'includes/Database.php', 'ResultWrapper' => 'includes/Database.php', - 'OracleBlob' => 'includes/DatabaseOracle.php', - 'DatabaseOracle' => 'includes/DatabaseOracle.php', 'DatabasePostgres' => 'includes/DatabasePostgres.php', + 'DatabaseOracle' => 'includes/DatabaseOracle.php', 'DateFormatter' => 'includes/DateFormatter.php', 'DifferenceEngine' => 'includes/DifferenceEngine.php', '_DiffOp' => 'includes/DifferenceEngine.php', @@ -95,6 +96,7 @@ function __autoload($className) { 'HTMLCacheUpdateJob' => 'includes/HTMLCacheUpdate.php', 'Http' => 'includes/HttpFunctions.php', 'Image' => 'includes/Image.php', + 'ArchivedFile' => 'includes/Image.php', 'IP' => 'includes/IP.php', 'ThumbnailImage' => 'includes/Image.php', 'ImageGallery' => 'includes/ImageGallery.php', @@ -114,6 +116,10 @@ function __autoload($className) { 'MacBinary' => 'includes/MacBinary.php', 'MagicWord' => 'includes/MagicWord.php', 'MathRenderer' => 'includes/Math.php', + 'MediaTransformOutput' => 'includes/MediaTransformOutput.php', + 'ThumbnailImage' => 'includes/MediaTransformOutput.php', + 'MediaTransformError' => 'includes/MediaTransformOutput.php', + 'TransformParameterError' => 'includes/MediaTransformOutput.php', 'MessageCache' => 'includes/MessageCache.php', 'MimeMagic' => 'includes/MimeMagic.php', 'Namespace' => 'includes/Namespace.php', @@ -124,16 +130,18 @@ function __autoload($className) { 'ReverseChronologicalPager' => 'includes/Pager.php', 'TablePager' => 'includes/Pager.php', 'Parser' => 'includes/Parser.php', - 'ParserOutput' => 'includes/Parser.php', - 'ParserOptions' => 'includes/Parser.php', + 'ParserOutput' => 'includes/ParserOutput.php', + 'ParserOptions' => 'includes/ParserOptions.php', 'ParserCache' => 'includes/ParserCache.php', + 'PatrolLog' => 'includes/PatrolLog.php', 'ProfilerSimple' => 'includes/ProfilerSimple.php', 'ProfilerSimpleUDP' => 'includes/ProfilerSimpleUDP.php', 'Profiler' => 'includes/Profiler.php', 'ProxyTools' => 'includes/ProxyTools.php', 'ProtectionForm' => 'includes/ProtectionForm.php', 'QueryPage' => 'includes/QueryPage.php', - 'PageQueryPage' => 'includes/QueryPage.php', + 'PageQueryPage' => 'includes/PageQueryPage.php', + 'ImageQueryPage' => 'includes/ImageQueryPage.php', 'RawPage' => 'includes/RawPage.php', 'RecentChange' => 'includes/RecentChange.php', 'Revision' => 'includes/Revision.php', @@ -148,6 +156,7 @@ function __autoload($className) { 'SearchPostgres' => 'includes/SearchPostgres.php', 'SearchUpdate' => 'includes/SearchUpdate.php', 'SearchUpdateMyISAM' => 'includes/SearchUpdate.php', + 'SearchOracle' => 'includes/SearchOracle.php', 'SiteConfiguration' => 'includes/SiteConfiguration.php', 'SiteStats' => 'includes/SiteStats.php', 'SiteStatsUpdate' => 'includes/SiteStats.php', @@ -160,7 +169,6 @@ function __autoload($className) { 'IPBlockForm' => 'includes/SpecialBlockip.php', 'SpecialBookSources' => 'includes/SpecialBooksources.php', 'BrokenRedirectsPage' => 'includes/SpecialBrokenRedirects.php', - 'CategoriesPage' => 'includes/SpecialCategories.php', 'EmailConfirmation' => 'includes/SpecialConfirmemail.php', 'ContributionsPage' => 'includes/SpecialContributions.php', 'DeadendPagesPage' => 'includes/SpecialDeadendpages.php', @@ -173,7 +181,6 @@ function __autoload($className) { 'ImportStreamSource' => 'includes/SpecialImport.php', 'IPUnblockForm' => 'includes/SpecialIpblocklist.php', 'ListredirectsPage' => 'includes/SpecialListredirects.php', - 'ListUsersPage' => 'includes/SpecialListusers.php', 'DBLockForm' => 'includes/SpecialLockdb.php', 'LogReader' => 'includes/SpecialLog.php', 'LogViewer' => 'includes/SpecialLog.php', @@ -185,6 +192,7 @@ function __autoload($className) { 'MostlinkedPage' => 'includes/SpecialMostlinked.php', 'MostlinkedCategoriesPage' => 'includes/SpecialMostlinkedcategories.php', 'MostrevisionsPage' => 'includes/SpecialMostrevisions.php', + 'FewestrevisionsPage' => 'includes/SpecialFewestrevisions.php', 'MovePageForm' => 'includes/SpecialMovepage.php', 'NewbieContributionsPage' => 'includes/SpecialNewbieContributions.php', 'NewPagesPage' => 'includes/SpecialNewpages.php', @@ -194,6 +202,7 @@ function __autoload($className) { 'PopularPagesPage' => 'includes/SpecialPopularpages.php', 'PreferencesForm' => 'includes/SpecialPreferences.php', 'SpecialPrefixindex' => 'includes/SpecialPrefixindex.php', + 'PasswordResetForm' => 'includes/SpecialResetpass.php', 'RevisionDeleteForm' => 'includes/SpecialRevisiondelete.php', 'RevisionDeleter' => 'includes/SpecialRevisiondelete.php', 'SpecialSearch' => 'includes/SpecialSearch.php', @@ -215,6 +224,7 @@ function __autoload($className) { 'WantedCategoriesPage' => 'includes/SpecialWantedcategories.php', 'WantedPagesPage' => 'includes/SpecialWantedpages.php', 'WhatLinksHerePage' => 'includes/SpecialWhatlinkshere.php', + 'WithoutInterwikiPage' => 'includes/SpecialWithoutinterwiki.php', 'SquidUpdate' => 'includes/SquidUpdate.php', 'ReplacementArray' => 'includes/StringUtils.php', 'Replacer' => 'includes/StringUtils.php', @@ -237,13 +247,27 @@ function __autoload($className) { 'Xml' => 'includes/Xml.php', 'ZhClient' => 'includes/ZhClient.php', 'memcached' => 'includes/memcached-client.php', + + # Media + 'BitmapHandler' => 'includes/media/Bitmap.php', + 'BmpHandler' => 'includes/media/BMP.php', + 'DjVuHandler' => 'includes/media/DjVu.php', + 'MediaHandler' => 'includes/media/Generic.php', + 'ImageHandler' => 'includes/media/Generic.php', + 'SvgHandler' => 'includes/media/SVG.php', + + # Normal 'UtfNormal' => 'includes/normal/UtfNormal.php', + + # Templates 'UsercreateTemplate' => 'includes/templates/Userlogin.php', 'UserloginTemplate' => 'includes/templates/Userlogin.php', + + # Languages 'Language' => 'languages/Language.php', - 'PasswordResetForm' => 'includes/SpecialResetpass.php', + 'RandomPage' => 'includes/SpecialRandompage.php', - // API classes + # API 'ApiBase' => 'includes/api/ApiBase.php', 'ApiFormatFeedWrapper' => 'includes/api/ApiFormatBase.php', 'ApiFeedWatchlist' => 'includes/api/ApiFeedWatchlist.php', @@ -274,6 +298,7 @@ function __autoload($className) { 'ApiResult' => 'includes/api/ApiResult.php', ); + wfProfileIn( __METHOD__ ); if ( isset( $localClasses[$className] ) ) { $filename = $localClasses[$className]; } elseif ( isset( $wgAutoloadClasses[$className] ) ) { @@ -290,6 +315,7 @@ function __autoload($className) { } if ( !$filename ) { # Give up + wfProfileOut( __METHOD__ ); return; } } @@ -300,6 +326,7 @@ function __autoload($className) { $filename = "$IP/$filename"; } require( $filename ); + wfProfileOut( __METHOD__ ); } function wfLoadAllExtensions() { @@ -311,10 +338,10 @@ function wfLoadAllExtensions() { # guaranteed by entering special pages via SpecialPage members such as # executePath(), but here we have to take a more explicit measure. - require_once( 'SpecialPage.php' ); + require_once( dirname(__FILE__) . '/SpecialPage.php' ); foreach( $wgAutoloadClasses as $class => $file ) { - if ( ! class_exists( $class ) ) { + if( !( class_exists( $class ) || interface_exists( $class ) ) ) { require( $file ); } } diff --git a/includes/BagOStuff.php b/includes/BagOStuff.php index c720807d..2a04b9dd 100644 --- a/includes/BagOStuff.php +++ b/includes/BagOStuff.php @@ -19,7 +19,6 @@ # http://www.gnu.org/copyleft/gpl.html /** * - * @package MediaWiki */ /** @@ -29,15 +28,16 @@ * the PHP memcached client. * * backends for local hash array and SQL table included: - * $bag = new HashBagOStuff(); - * $bag = new MysqlBagOStuff($tablename); # connect to db first + * + * $bag = new HashBagOStuff(); + * $bag = new MysqlBagOStuff($tablename); # connect to db first + * * - * @package MediaWiki */ class BagOStuff { var $debugmode; - function BagOStuff() { + function __construct() { $this->set_debug( false ); } @@ -163,7 +163,6 @@ class BagOStuff { /** * Functional versions! * @todo document - * @package MediaWiki */ class HashBagOStuff extends BagOStuff { /* @@ -218,7 +217,6 @@ CREATE TABLE objectcache ( /** * @todo document * @abstract - * @package MediaWiki */ abstract class SqlBagOStuff extends BagOStuff { var $table; @@ -386,34 +384,32 @@ abstract class SqlBagOStuff extends BagOStuff { /** * @todo document - * @package MediaWiki */ class MediaWikiBagOStuff extends SqlBagOStuff { var $tableInitialised = false; function _doquery($sql) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->query($sql, 'MediaWikiBagOStuff::_doquery'); } function _doinsert($t, $v) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->insert($t, $v, 'MediaWikiBagOStuff::_doinsert', array( 'IGNORE' ) ); } function _fetchobject($result) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->fetchObject($result); } function _freeresult($result) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->freeResult($result); } function _dberror($result) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->lastError(); } function _maxdatetime() { - $dbw =& wfGetDB(DB_MASTER); if ( time() > 0x7fffffff ) { return $this->_fromunixtime( 1<<62 ); } else { @@ -421,24 +417,24 @@ class MediaWikiBagOStuff extends SqlBagOStuff { } } function _fromunixtime($ts) { - $dbw =& wfGetDB(DB_MASTER); + $dbw = wfGetDB(DB_MASTER); return $dbw->timestamp($ts); } function _strencode($s) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->strencode($s); } function _blobencode($s) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->encodeBlob($s); } function _blobdecode($s) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); return $dbw->decodeBlob($s); } function getTableName() { if ( !$this->tableInitialised ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); /* This is actually a hack, we should be able to use Language classes here... or not */ if (!$dbw) @@ -463,7 +459,6 @@ class MediaWikiBagOStuff extends SqlBagOStuff { * that Turck's serializer is faster, so a possible future extension would be * to use it for arrays but not for objects. * - * @package MediaWiki */ class TurckBagOStuff extends BagOStuff { function get($key) { @@ -498,9 +493,7 @@ class TurckBagOStuff extends BagOStuff { /** * This is a wrapper for APC's shared memory functions * - * @package MediaWiki */ - class APCBagOStuff extends BagOStuff { function get($key) { $val = apc_fetch($key); @@ -528,7 +521,6 @@ class APCBagOStuff extends BagOStuff { * This is basically identical to the Turck MMCache version, * mostly because eAccelerator is based on Turck MMCache. * - * @package MediaWiki */ class eAccelBagOStuff extends BagOStuff { function get($key) { @@ -560,6 +552,9 @@ class eAccelBagOStuff extends BagOStuff { } } +/** + * @todo document + */ class DBABagOStuff extends BagOStuff { var $mHandler, $mFile, $mReader, $mWriter, $mDisabled; diff --git a/includes/Block.php b/includes/Block.php index ff813ba3..94bfa5b4 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -1,7 +1,6 @@ mId = 0; + # Expand valid IPv6 addresses + $address = IP::sanitizeIP( $address ); $this->mAddress = $address; $this->mUser = $user; $this->mBy = $by; @@ -38,6 +39,7 @@ class Block $this->mCreateAccount = $createAccount; $this->mExpiry = self::decodeExpiry( $expiry ); $this->mEnableAutoblock = $enableAutoblock; + $this->mHideName = $hideName; $this->mForUpdate = false; $this->mFromMaster = false; @@ -58,7 +60,7 @@ class Block static function newFromID( $id ) { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->resultObject( $dbr->select( 'ipblocks', '*', array( 'ipb_id' => $id ), __METHOD__ ) ); $block = new Block; @@ -74,7 +76,7 @@ class Block $this->mAddress = $this->mReason = $this->mTimestamp = ''; $this->mId = $this->mAnonOnly = $this->mCreateAccount = $this->mEnableAutoblock = $this->mAuto = $this->mUser = - $this->mBy = 0; + $this->mBy = $this->mHideName = 0; $this->mByName = false; } @@ -85,14 +87,14 @@ class Block { global $wgAntiLockFlags; if ( $this->mForUpdate || $this->mFromMaster ) { - $db =& wfGetDB( DB_MASTER ); + $db = wfGetDB( DB_MASTER ); if ( !$this->mForUpdate || ($wgAntiLockFlags & ALF_NO_BLOCK_LOCK) ) { $options = array(); } else { $options = array( 'FOR UPDATE' ); } } else { - $db =& wfGetDB( DB_SLAVE ); + $db = wfGetDB( DB_SLAVE ); $options = array(); } return $db; @@ -147,7 +149,7 @@ class Block } # Try range block - if ( $this->loadRange( $address, $killExpired, $user == 0 ) ) { + if ( $this->loadRange( $address, $killExpired, $user ) ) { if ( $user && $this->mAnonOnly ) { $this->clear(); return false; @@ -176,7 +178,8 @@ class Block /** * Fill in member variables from a result wrapper */ - function loadFromResult( ResultWrapper $res, $killExpired = true ) { + function loadFromResult( ResultWrapper $res, $killExpired = true ) + { $ret = false; if ( 0 != $res->numRows() ) { # Get first block @@ -211,7 +214,7 @@ class Block * Search the database for any range blocks matching the given address, and * load the row if one is found. */ - function loadRange( $address, $killExpired = true ) + function loadRange( $address, $killExpired = true, $user = 0 ) { $iaddr = IP::toHex( $address ); if ( $iaddr === false ) { @@ -230,6 +233,10 @@ class Block "ipb_range_start <= '$iaddr'", "ipb_range_end >= '$iaddr'" ); + + if ( $user ) { + $conds['ipb_anon_only'] = 0; + } $res = $db->resultObject( $db->select( 'ipblocks', '*', $conds, __METHOD__, $options ) ); $success = $this->loadFromResult( $res, $killExpired ); @@ -255,6 +262,7 @@ class Block $this->mAnonOnly = $row->ipb_anon_only; $this->mCreateAccount = $row->ipb_create_account; $this->mEnableAutoblock = $row->ipb_enable_autoblock; + $this->mHideName = $row->ipb_deleted; $this->mId = $row->ipb_id; $this->mExpiry = self::decodeExpiry( $row->ipb_expiry ); if ( isset( $row->user_name ) ) { @@ -286,7 +294,7 @@ class Block $block = new Block(); if ( $flags & Block::EB_FOR_UPDATE ) { - $db =& wfGetDB( DB_MASTER ); + $db = wfGetDB( DB_MASTER ); if ( $wgAntiLockFlags & ALF_NO_BLOCK_LOCK ) { $options = ''; } else { @@ -294,7 +302,7 @@ class Block } $block->forUpdate( true ); } else { - $db =& wfGetDB( DB_SLAVE ); + $db = wfGetDB( DB_SLAVE ); $options = ''; } if ( $flags & Block::EB_RANGE_ONLY ) { @@ -341,7 +349,7 @@ class Block throw new MWException( "Block::delete() now requires that the mId member be filled\n" ); } - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'ipblocks', array( 'ipb_id' => $this->mId ), __METHOD__ ); return $dbw->affectedRows() > 0; } @@ -353,8 +361,7 @@ class Block function insert() { wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" ); - $dbw =& wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw = wfGetDB( DB_MASTER ); # Unset ipb_anon_only for user blocks, makes no sense if ( $this->mUser ) { @@ -385,6 +392,7 @@ class Block 'ipb_expiry' => self::encodeExpiry( $this->mExpiry, $dbw ), 'ipb_range_start' => $this->mRangeStart, 'ipb_range_end' => $this->mRangeEnd, + 'ipb_deleted' => $this->mHideName ), 'Block::insert', array( 'IGNORE' ) ); $affected = $dbw->affectedRows(); @@ -418,20 +426,20 @@ class Block } else { #Limit is 1, so no loop needed. $retroblockip = $row->rc_ip; - return $this->doAutoblock($retroblockip); + return $this->doAutoblock( $retroblockip, true ); } } } /** * Autoblocks the given IP, referring to this Block. - * @param $autoblockip The IP to autoblock. + * @param string $autoblockip The IP to autoblock. + * @param bool $justInserted The main block was just inserted * @return bool Whether or not an autoblock was inserted. */ - function doAutoblock( $autoblockip ) { + function doAutoblock( $autoblockip, $justInserted = false ) { # Check if this IP address is already blocked - $dbw =& wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw = wfGetDB( DB_MASTER ); # If autoblocks are disabled, go away. if ( !$this->mEnableAutoblock ) { @@ -480,7 +488,9 @@ class Block return; } # Just update the timestamp - $ipblock->updateTimestamp(); + if ( !$justInserted ) { + $ipblock->updateTimestamp(); + } return; } else { $ipblock = new Block; @@ -495,6 +505,8 @@ class Block $ipblock->mTimestamp = wfTimestampNow(); $ipblock->mAuto = 1; $ipblock->mCreateAccount = $this->mCreateAccount; + # Continue suppressing the name if needed + $ipblock->mHideName = $this->mHideName; # If the user is already blocked with an expiry date, we don't # want to pile on top of that! @@ -544,7 +556,7 @@ class Block $this->mTimestamp = wfTimestamp(); $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'ipblocks', array( /* SET */ 'ipb_timestamp' => $dbw->timestamp($this->mTimestamp), @@ -628,16 +640,36 @@ class Block global $wgAutoblockExpiry; return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry ); } - - static function normaliseRange( $range ) - { + + /** + * Gets rid of uneeded numbers in quad-dotted/octet IP strings + * For example, 127.111.113.151/24 -> 127.111.113.0/24 + */ + static function normaliseRange( $range ) { $parts = explode( '/', $range ); if ( count( $parts ) == 2 ) { - $shift = 32 - $parts[1]; - $ipint = IP::toUnsigned( $parts[0] ); - $ipint = $ipint >> $shift << $shift; - $newip = long2ip( $ipint ); - $range = "$newip/{$parts[1]}"; + // IPv6 + if ( IP::isIPv6($range) && $parts[1] >= 64 && $parts[1] <= 128 ) { + $bits = $parts[1]; + $ipint = IP::toUnsigned6( $parts[0] ); + # Native 32 bit functions WONT work here!!! + # Convert to a padded binary number + $network = wfBaseConvert( $ipint, 10, 2, 128 ); + # Truncate the last (128-$bits) bits and replace them with zeros + $network = str_pad( substr( $network, 0, $bits ), 128, 0, STR_PAD_RIGHT ); + # Convert back to an integer + $network = wfBaseConvert( $network, 2, 10 ); + # Reform octet address + $newip = IP::toOctet( $network ); + $range = "$newip/{$parts[1]}"; + } // IPv4 + else if ( IP::isIPv4($range) && $parts[1] >= 16 && $parts[1] <= 32 ) { + $shift = 32 - $parts[1]; + $ipint = IP::toUnsigned( $parts[0] ); + $ipint = $ipint >> $shift << $shift; + $newip = long2ip( $ipint ); + $range = "$newip/{$parts[1]}"; + } } return $range; } @@ -646,7 +678,7 @@ class Block * Purge expired blocks from the ipblocks table */ static function purgeExpired() { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'ipblocks', array( 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), __METHOD__ ); } @@ -658,7 +690,7 @@ class Block /* static $infinity; if ( !isset( $infinity ) ) { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $infinity = $dbr->bigTimestamp(); } return $infinity; diff --git a/includes/CacheDependency.php b/includes/CacheDependency.php index 4bb3d328..bb5c5437 100644 --- a/includes/CacheDependency.php +++ b/includes/CacheDependency.php @@ -4,6 +4,7 @@ * This class stores an arbitrary value along with its dependencies. * Users should typically only use DependencyWrapper::getFromCache(), rather * than instantiating one of these objects directly. + * @addtogroup Cache */ class DependencyWrapper { var $value; @@ -95,6 +96,9 @@ class DependencyWrapper { } } +/** + * @addtogroup Cache + */ abstract class CacheDependency { /** * Returns true if the dependency is expired, false otherwise @@ -107,6 +111,9 @@ abstract class CacheDependency { function loadDependencyValues() {} } +/** + * @addtogroup Cache + */ class FileDependency extends CacheDependency { var $filename, $timestamp; @@ -163,6 +170,9 @@ class FileDependency extends CacheDependency { } } +/** + * @addtogroup Cache + */ class TitleDependency extends CacheDependency { var $titleObj; var $ns, $dbk; @@ -219,6 +229,9 @@ class TitleDependency extends CacheDependency { } } +/** + * @addtogroup Cache + */ class TitleListDependency extends CacheDependency { var $linkBatch; var $timestamps; @@ -244,7 +257,7 @@ class TitleListDependency extends CacheDependency { # Do the query if ( count( $timestamps ) ) { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $where = $this->getLinkBatch()->constructSet( 'page', $dbr ); $res = $dbr->select( 'page', array( 'page_namespace', 'page_title', 'page_touched' ), @@ -299,6 +312,9 @@ class TitleListDependency extends CacheDependency { } } +/** + * @addtogroup Cache + */ class GlobalDependency extends CacheDependency { var $name, $value; @@ -312,6 +328,9 @@ class GlobalDependency extends CacheDependency { } } +/** + * @addtogroup Cache + */ class ConstantDependency extends CacheDependency { var $name, $value; diff --git a/includes/CategoryPage.php b/includes/CategoryPage.php index 0086a2f9..356f9ea2 100644 --- a/includes/CategoryPage.php +++ b/includes/CategoryPage.php @@ -3,17 +3,23 @@ * Special handling for category description pages * Modelled after ImagePage.php * - * @package MediaWiki */ if( !defined( 'MEDIAWIKI' ) ) die( 1 ); /** - * @package MediaWiki */ class CategoryPage extends Article { function view() { + global $wgRequest, $wgUser; + + $diff = $wgRequest->getVal( 'diff' ); + $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); + + if ( isset( $diff ) && $diffOnly ) + return Article::view(); + if(!wfRunHooks('CategoryPageView', array(&$this))) return; if ( NS_CATEGORY == $this->mTitle->getNamespace() ) { @@ -175,7 +181,7 @@ class CategoryViewer { } function doCategoryQuery() { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); if( $this->from != '' ) { $pageCondition = 'cl_sortkey >= ' . $dbr->addQuotes( $this->from ); $this->flip = false; @@ -196,6 +202,7 @@ class CategoryViewer { #+ $pageCondition, __METHOD__, array( 'ORDER BY' => $this->flip ? 'cl_sortkey DESC' : 'cl_sortkey', + 'USE INDEX' => 'cl_sortkey', 'LIMIT' => $this->limit + 1 ) ); $count = 0; @@ -234,11 +241,12 @@ class CategoryViewer { function getSubcategorySection() { # Don't show subcategories section if there are none. $r = ''; - if( count( $this->children ) > 0 ) { + $c = count( $this->children ); + if( $c > 0 ) { # Showing subcategories $r .= "
\n"; $r .= '

' . wfMsg( 'subcategories' ) . "

\n"; - $r .= wfMsgExt( 'subcategorycount', array( 'parse' ), count( $this->children) ); + $r .= wfMsgExt( 'subcategorycount', array( 'parse' ), $c ); $r .= $this->formatList( $this->children, $this->children_start_char ); $r .= "\n
"; } @@ -247,11 +255,16 @@ class CategoryViewer { function getPagesSection() { $ti = htmlspecialchars( $this->title->getText() ); - $r = "
\n"; - $r .= '

' . wfMsg( 'category_header', $ti ) . "

\n"; - $r .= wfMsgExt( 'categoryarticlecount', array( 'parse' ), count( $this->articles) ); - $r .= $this->formatList( $this->articles, $this->articles_start_char ); - $r .= "\n
"; + # Don't show articles section if there are none. + $r = ''; + $c = count( $this->articles ); + if( $c > 0 ) { + $r = "
\n"; + $r .= '

' . wfMsg( 'category_header', $ti ) . "

\n"; + $r .= wfMsgExt( 'categoryarticlecount', array( 'parse' ), $c ); + $r .= $this->formatList( $this->articles, $this->articles_start_char ); + $r .= "\n
"; + } return $r; } @@ -391,7 +404,7 @@ class CategoryViewer { */ function pagingLinks( $title, $first, $last, $limit, $query = array() ) { global $wgUser, $wgLang; - $sk =& $this->getSkin(); + $sk = $this->getSkin(); $limitText = $wgLang->formatNum( $limit ); $prevLink = htmlspecialchars( wfMsg( 'prevn', $limitText ) ); diff --git a/includes/Categoryfinder.php b/includes/Categoryfinder.php index a8cdf3ce..7faae935 100644 --- a/includes/Categoryfinder.php +++ b/includes/Categoryfinder.php @@ -1,26 +1,27 @@ seed ( - array ( 12345 ) , - array ( "Category 1","Category 2" ) , - "AND" - ) ; - $a = $cf->run() ; - print implode ( "," , $a ) ; - -*/ - +/** + * The "Categoryfinder" class takes a list of articles, creates an internal + * representation of all their parent categories (as well as parents of + * parents etc.). From this representation, it determines which of these + * articles are in one or all of a given subset of categories. + * + * Example use : + * + * # Determines whether the article with the page_id 12345 is in both + * # "Category 1" and "Category 2" or their subcategories, respectively + * + * $cf = new Categoryfinder ; + * $cf->seed ( + * array ( 12345 ) , + * array ( "Category 1","Category 2" ) , + * "AND" + * ) ; + * $a = $cf->run() ; + * print implode ( "," , $a ) ; + * + * + */ class Categoryfinder { var $articles = array () ; # The original article IDs passed to the seed function @@ -34,8 +35,8 @@ class Categoryfinder { /** * Constructor (currently empty). - */ - function Categoryfinder () { + */ + function __construct() { } /** @@ -61,10 +62,10 @@ class Categoryfinder { /** * Iterates through the parent tree starting with the seed values, * then checks the articles if they match the conditions - @return array of page_ids (those given to seed() that match the conditions) - */ + * @return array of page_ids (those given to seed() that match the conditions) + */ function run () { - $this->dbr =& wfGetDB( DB_SLAVE ); + $this->dbr = wfGetDB( DB_SLAVE ); while ( count ( $this->next ) > 0 ) { $this->scan_next_layer () ; } @@ -83,20 +84,20 @@ class Categoryfinder { /** * This functions recurses through the parent representation, trying to match the conditions - @param $id The article/category to check - @param $conds The array of categories to match - @return bool Does this match the conditions? - */ + * @param $id The article/category to check + * @param $conds The array of categories to match + * @return bool Does this match the conditions? + */ function check ( $id , &$conds ) { # Shortcut (runtime paranoia): No contitions=all matched if ( count ( $conds ) == 0 ) return true ; - + if ( !isset ( $this->parents[$id] ) ) return false ; # iterate through the parents foreach ( $this->parents[$id] AS $p ) { $pname = $p->cl_to ; - + # Is this a condition? if ( isset ( $conds[$pname] ) ) { # This key is in the category list! @@ -113,7 +114,7 @@ class Categoryfinder { } } } - + # Not done yet, try sub-parents if ( !isset ( $this->name2id[$pname] ) ) { # No sub-parent @@ -130,10 +131,10 @@ class Categoryfinder { /** * Scans a "parent layer" of the articles/categories in $this->next - */ + */ function scan_next_layer () { $fname = "Categoryfinder::scan_next_layer" ; - + # Find all parents of the article currently in $this->next $layer = array () ; $res = $this->dbr->select( @@ -161,7 +162,7 @@ class Categoryfinder { $this->dbr->freeResult( $res ) ; $this->next = array() ; - + # Find the IDs of all category pages in $layer, if they exist if ( count ( $layer ) > 0 ) { $res = $this->dbr->select( diff --git a/includes/ChangesList.php b/includes/ChangesList.php index a2c1a265..bc141579 100644 --- a/includes/ChangesList.php +++ b/includes/ChangesList.php @@ -1,15 +1,7 @@ mAttribs = $rc->mAttribs; $rc2->mExtra = $rc->mExtra; @@ -27,14 +18,17 @@ class RCCacheEntry extends RecentChange } ; /** - * @package MediaWiki + * Class to show various lists of changes: + * - what links here + * - related changes + * - recent changes */ class ChangesList { # Called by history lists and recent changes # /** @todo document */ - function ChangesList( &$skin ) { + function __construct( &$skin ) { $this->skin =& $skin; $this->preCacheMessages(); } @@ -47,7 +41,7 @@ class ChangesList { * @return ChangesList derivative */ public static function newFromUser( &$user ) { - $sk =& $user->getSkin(); + $sk = $user->getSkin(); $list = NULL; if( wfRunHooks( 'FetchChangesList', array( &$user, &$sk, &$list ) ) ) { return $user->getOption( 'usenewrc' ) ? new EnhancedChangesList( $sk ) : new OldChangesList( $sk ); @@ -64,7 +58,7 @@ class ChangesList { // Precache various messages if( !isset( $this->message ) ) { foreach( explode(' ', 'cur diff hist minoreditletter newpageletter last '. - 'blocklink changes history boteditletter' ) as $msg ) { + 'blocklink history boteditletter' ) as $msg ) { $this->message[$msg] = wfMsgExt( $msg, array( 'escape') ); } } @@ -212,6 +206,23 @@ class ChangesList { global $wgUseRCPatrol, $wgUser; return( $wgUseRCPatrol && $wgUser->isAllowed( 'patrol' ) ); } + + /** + * Returns the string which indicates the number of watching users + */ + function numberofWatchingusers( $count ) { + global $wgLang; + static $cache = array(); + if ( $count > 0 ) { + if ( !isset( $cache[$count] ) ) { + $cache[$count] = wfMsgExt('number_of_watching_users_RCview', + array('parsemag', 'escape'), $wgLang->formatNum($count)); + } + return $cache[$count]; + } else { + return ''; + } + } } @@ -229,6 +240,7 @@ class OldChangesList extends ChangesList { wfProfileIn( $fname ); # Extract DB fields into local scope + // FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. extract( $rc->mAttribs ); # Should patrol-related stuff be shown? @@ -273,9 +285,7 @@ class OldChangesList extends ChangesList { $this->insertUserRelatedLinks($s,$rc); $this->insertComment($s, $rc); - if($rc->numberofWatchingusers > 0) { - $s .= ' ' . wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rc->numberofWatchingusers)); - } + $s .= rtrim(' ' . $this->numberofWatchingusers($rc->numberofWatchingusers)); $s .= "\n"; @@ -301,6 +311,7 @@ class EnhancedChangesList extends ChangesList { $rc = RCCacheEntry::newFromParent( $baseRC ); # Extract fields from DB into the function scope (rc_xxxx variables) + // FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. extract( $rc->mAttribs ); $curIdEq = 'curid=' . $rc_cur_id; @@ -405,7 +416,7 @@ class EnhancedChangesList extends ChangesList { * Enhanced RC group */ function recentChangesBlockGroup( $block ) { - global $wgContLang, $wgRCShowChangedSize; + global $wgLang, $wgContLang, $wgRCShowChangedSize; $r = ''; # Collate list of users @@ -467,22 +478,32 @@ class EnhancedChangesList extends ChangesList { $currentRevision = $block[0]->mAttribs['rc_this_oldid']; if( $block[0]->mAttribs['rc_type'] != RC_LOG ) { # Changes - $r .= ' ('.count($block).' '; + + $n = count($block); + static $nchanges = array(); + if ( !isset( $nchanges[$n] ) ) { + $nchanges[$n] = wfMsgExt( 'nchanges', array( 'parsemag', 'escape'), + $wgLang->formatNum( $n ) ); + } + + $r .= ' ('; if( $isnew ) { - $r .= $this->message['changes']; + $r .= $nchanges[$n]; } else { $r .= $this->skin->makeKnownLinkObj( $block[0]->getTitle(), - $this->message['changes'], $curIdEq."&diff=$currentRevision&oldid=$oldid" ); + $nchanges[$n], $curIdEq."&diff=$currentRevision&oldid=$oldid" ); } + $r .= ') . . '; + # Character difference $chardiff = $rcObj->getCharacterDifference( $block[ count( $block ) - 1 ]->mAttribs['rc_old_len'], $block[0]->mAttribs['rc_new_len'] ); if( $chardiff == '' ) { - $r .= '; '; + $r .= ' ('; } else { - $r .= '; ' . $chardiff . ' '; + $r .= ' ' . $chardiff. ' . . ('; } @@ -494,16 +515,14 @@ class EnhancedChangesList extends ChangesList { $r .= $users; - if($block[0]->numberofWatchingusers > 0) { - global $wgContLang; - $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($block[0]->numberofWatchingusers)); - } + $r .= $this->numberofWatchingusers($block[0]->numberofWatchingusers); $r .= "
\n"; # Sub-entries $r .= '