Index: trunk/phase3/RELEASE-NOTES =================================================================== --- trunk/phase3/RELEASE-NOTES (revision 22614) +++ trunk/phase3/RELEASE-NOTES (revision 22615) @@ -1,237 +1,238 @@ = MediaWiki release notes = Security reminder: MediaWiki does not require PHP's register_globals setting since version 1.2.0. If you have it on, turn it *off* if you can. == MediaWiki 1.11 == THIS IS NOT A RELEASE YET. MediaWiki is now using a "continuous integration" development model with quarterly snapshot releases. The latest development code is always kept "ready to run", and in fact runs our own sites on Wikipedia. Release branches will continue to receive security updates for about a year from first release, but nonessential bugfixes and feature developments will be made on the development trunk and appear in the next quarterly release. Those wishing to use the latest code instead of a branch release can obtain it from source control: http://www.mediawiki.org/wiki/Download_from_SVN == Configuration changes since 1.10 == * $wgThumbUpright - Adjust width of upright images when parameter 'upright' is used == New features since 1.10 == * (bug 8868) Separate "blocked" message for autoblocks * Adding expiry of block to block messages * Bulk mail options ($wgEnotifImpersonal, $wgEnotifUseJobQ) for large sites * Links to redirect pages in categories are wrapped in * Introduced 'ImageOpenShowImageInlineBefore' hook; see docs/hooks.txt for more information * (bug 9628) Show warnings about slave lag on Special:Contributions, Special:Watchlist * (bug 8818) Expose "wpDestFile" as parameter $1 to "uploaddisabledtext" * Introducing new image keyword 'upright' and corresponding variable $wgThumbUpright. This allows better proportional view of upright images related to landscape images on a page without nailing the width of upright images to a fix value which makes views for anon unproportional and user preferences useless * (bug 6072) Introducing 'border' keyword to the [[Image:]] syntax * Introducing 'frameless' keyword to [[Image:]] syntax which respects the user preferences for image width like 'thumb' but without a frame. * (bug 7960) Link to "what links here" for each "what links here" entry * Added support for configuration of an arbitrary number of commons-style file repositories. * Added a Content-Disposition header to thumb.php output * Improved thumb.php error handling * Display file history on local image description pages of shared images +* Added $wgArticleRobotPolicies == Bugfixes since 1.10 == * (bug 9712) Use Arabic comma in date/time formats for Arabic and Farsi * (bug 9670) Follow redirects when render edit section links to transcluded templates. * (bug 6204) Fix incorrect unindentation with $wgMaxTocLevel * (bug 3431) Suppress "next page" link in Special:Search at end of results * Don't show unblock form if the user doesn't have permission to use it (cosmetic change, no vulnerabilities existed) * Subtitle success message when unblocking a block ID instead of a pseudo link like [[User:#123|#123]] * Use the standard HTTP fetch functions when retrieving remote wiki pages through transwiki, so we can take advantage of cURL goodies if available * Disable custom user javascript in Special:Preferences, to avoid the risk of a compromised script sniffing passwords etc. * (bug 9854, 3770) Clip overflow text in gallery boxes for visual cleanliness instead of letting it flow outside the box or trigger ugly scroll bars. * Tooltips for print version and permalink * Links to the MediaWiki namespace for system messages having their default values are no longer shown as nonexistent (e.g., in red) * Special:Ipblocklist differentiates between empty list and no search results. * (bug 5375) profiling does not respect read-only mode. * (bug 7070) monobook/user.gif has antialias artifacts * (bug 9123) Safer way when applying $wgLocalTZoffset * (bug 9896) Documentation for $wgSquidServers and X-FORWARDED-FOR * (bug 9417) Uploading new versions of images when using Postgres no longer throws warnings. * (bug 9908) Using tsearch2 with Postgres 8.1 no longer gives an error. * (bug 1438) Fix for diff table layout on very wide lines. Diff style rules have been broken out to common/diff.css, and the dupes removed from the default skin files. Skins can still override the default rules. * (bug 1229) Balance columns in diff display evenly * Right-align diff line numbers in RTL language display * (bug 9332) Fix instructions in tests/README * (bug 9813) Reject usernames containing '#' to avoid silent truncation of fragments during the normalisation process * (bug 7989) RSS feeds content now use black text when using white background. * (bug 9971) Typo in a french language message. * (bug 9973) Changed size was shown in advanced recentchanges collapsible items with $wgRCShowChangedSized = false. * Fix PHP strict standards warning in enhanced recent changes. * (bug 5850) Added hexadecimal html entities comments for $digitTransformTable entries. * (bug 7432) Change language name for Aromanian (roa-rup) * (bug 908) Unexistent special pages now generate a red link. * (bug 7899) Added \hline and \vline to the list of allowed TeX commands * (bug 7993) support mathematical symbol classes * (bug 10007) Allow Block IP to work with Postgrs again. * Add Google Wireless Transcoder to the Unicode editing blacklist == MediaWiki API changes since 1.10 == (For ongoing development discussion, see http://www.mediawiki.org/wiki/API) * New properties: links, templates, images, langlinks, categories, external links * Breaking Change: imagelinks renamed into imageusage (il->iu) * Bug fix: incorrect generator behavior in some cases * JSON format allows an optional callback function to wrap the result. * Login module disabled until a more secure solution can be implemented * (bug 9938) Querying by revision identifier returns the most recent revision for the corresponding page, rather than the requested revision * (bug 8772) Filter page revision queries by user * (bug 9927) User contributions queries do not accept IP addresses * Watchlist feed now reports a proper feed item when the user is not logged in * Watchlist feed date bug fixed - automatically shows one last day * Watchlist feed now allows to specify number of hours to monitor * list=allpages now returns a list instead of a map in json format * Breaking Change: in json, revisions are now returned as a list, not as a map. * Add: prop=info can show page is new flag, current page length, and visit counter. * Change: Query watchlist now shows flags only when explicitly requested with wlparam=flags rc_this_oldid (textid) is no longer accessible from query watchlist * action=usercontribs: additional filtering by ucshow=; selection of needed fields with ucprop=; the textid (rev_text_id) is no longer being exposed * breaking change: backlinks, embeddedin & imageusage now return lists in json instead of a map, and do not return anything when titles do not exist. (bug 9970) * added query parameter indexpageids to list the page ids of all returned page items (bug 9121) == Maintenance script changes since 1.10 == * Add support for wgMaxTocLevel option in parserTests * (bug 6823) dumpHTML: explicitly disable article view counter == Languages updated since 1.10 == * Arabic (ar) * Catalan (ca) * Danish (da) * German (de) * Greek (el) * Spanish (es) * Farsi (fa) * Finnish (fi) * Võro (fiu-vro) * French (fr) * Hakka (hak) * Hebrew (he) * Indonesian (id) * Italian (it) * Japanese (ja) * Georgian (ka) * Kabyle (kab) * Kazakh (kk) * Kurdish (ku) * Lithuanian (lt) * Burmese (my) * Norwegian (no) * Polish (pl) * Russian (ru) * Slovak (sk) * Somali (so) * Sundanese (su) * Swedish (sv) * Old Chinese / Late Middle Chinese (zh-classical) * Chinese (PRC) (zh-cn) * Chinese (Taiwan) (zh-tw) * Cantonese (zh-yue) == Compatibility == MediaWiki 1.11 requires PHP 5 (5.1 recommended). PHP 4 is no longer supported. PHP 5.0.x fails on 64-bit systems due to serious bugs with array processing: http://bugs.php.net/bug.php?id=34879 Upgrade affected systems to PHP 5.1 or higher. MySQL 3.23.x is no longer supported; some older hosts may need to upgrade. At this time we still recommend 4.0, but 4.1/5.0 will work fine in most cases. == Upgrading == 1.11 has several database changes since 1.10, and will not work without schema updates. If upgrading from before 1.7, you may want to run refreshLinks.php to ensure new database fields are filled with data. If you are upgrading from MediaWiki 1.4.x or earlier, some major database changes are made, and there is a slightly higher chance that things could break. Don't forget to always back up your database before upgrading! See the file UPGRADE for more detailed upgrade instructions. === Caveats === Some output, particularly involving user-supplied inline HTML, may not produce 100% valid or well-formed XHTML output. Testers are welcome to set $wgMimeType = "application/xhtml+xml"; to test for remaining problem cases, but this is not recommended on live sites. (This must be set for MathML to display properly in Mozilla.) For notes on 1.10.x and older releases, see HISTORY. === Online documentation === Documentation for both end-users and site administrators is currently being built up on MediaWiki.org, and is covered under the GNU Free Documentation License (except for pages that explicitly state that their contents are in the public domain) : http://www.mediawiki.org/wiki/Documentation === Mailing list === A MediaWiki-l mailing list has been set up distinct from the Wikipedia wikitech-l list: http://lists.wikimedia.org/mailman/listinfo/mediawiki-l A low-traffic announcements-only list is also available: http://lists.wikimedia.org/mailman/listinfo/mediawiki-announce It's highly recommended that you sign up for one of these lists if you're going to run a public MediaWiki, so you can be notified of security fixes. === IRC help === There's usually someone online in #mediawiki on irc.freenode.net Index: trunk/phase3/includes/Article.php =================================================================== --- trunk/phase3/includes/Article.php (revision 22614) +++ trunk/phase3/includes/Article.php (revision 22615) @@ -1,2970 +1,2972 @@ mTitle =& $title; $this->mOldId = $oldId; $this->clear(); } /** * Tell the page view functions that this view was redirected * from another page on the wiki. * @param $from Title object. */ 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() != '' ) { if( $rt->isLocal() ) { // Offsite wikis need an HTTP redirect. // // 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 ) ); } } else { if( $rt->getNamespace() == NS_SPECIAL ) { // Gotta handle redirects to special pages differently: // Fill the HTTP response "Location" header and ignore // 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 { return $rt->getFullURL(); } } return $rt; } } // No or invalid redirect return false; } /** * get the title object of the article */ function getTitle() { return $this->mTitle; } /** * Clear the object * @private */ function clear() { $this->mDataLoaded = false; $this->mContentLoaded = false; $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded $this->mRedirectedFrom = null; # Title object if set $this->mUserText = $this->mTimestamp = $this->mComment = ''; $this->mGoodAdjustment = $this->mTotalAdjustment = 0; $this->mTouched = '19700101000000'; $this->mForUpdate = false; $this->mIsRedirect = false; $this->mRevIdFetched = 0; $this->mRedirectUrl = false; $this->mLatest = false; } /** * Note that getContent/loadContent do not follow redirects anymore. * If you need to fetch redirectable content easily, try * the shortcut in Article::followContent() * FIXME * @todo There are still side-effects in this! * In general, you should use the Revision class, not Article, * to fetch text for purposes other than page views. * * @return Return the text of this revision */ function getContent() { global $wgUser, $wgOut; wfProfileIn( __METHOD__ ); if ( 0 == $this->getID() ) { wfProfileOut( __METHOD__ ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { $ret = wfMsgWeirdKey ( $this->mTitle->getText() ) ; } else { $ret = wfMsg( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon' ); } return "
$ret
"; } else { $this->loadContent(); wfProfileOut( __METHOD__ ); return $this->mContent; } } /** * This function returns the text of a section, specified by a number ($section). * A section is text under a heading like == Heading == or \Heading\, or * the first section before any such heading (section 0). * * If a section contains subsections, these are also returned. * * @param $text String: text to look in * @param $section Integer: section number * @return string text of the requested section * @deprecated */ function getSection($text,$section) { global $wgParser; return $wgParser->getSection( $text, $section ); } /** * @return int The oldid of the article that is to be shown, 0 for the * current revision */ function getOldID() { if ( is_null( $this->mOldId ) ) { $this->mOldId = $this->getOldIDFromRequest(); } return $this->mOldId; } /** * Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect * * @return int The old id for the request */ function getOldIDFromRequest() { global $wgRequest; $this->mRedirectUrl = false; $oldid = $wgRequest->getVal( 'oldid' ); if ( isset( $oldid ) ) { $oldid = intval( $oldid ); if ( $wgRequest->getVal( 'direction' ) == 'next' ) { $nextid = $this->mTitle->getNextRevisionID( $oldid ); if ( $nextid ) { $oldid = $nextid; } else { $this->mRedirectUrl = $this->mTitle->getFullURL( 'redirect=no' ); } } elseif ( $wgRequest->getVal( 'direction' ) == 'prev' ) { $previd = $this->mTitle->getPreviousRevisionID( $oldid ); if ( $previd ) { $oldid = $previd; } else { # TODO } } # unused: # $lastid = $oldid; } if ( !$oldid ) { $oldid = 0; } return $oldid; } /** * Load the revision (including text) into this object */ function loadContent() { if ( $this->mContentLoaded ) return; # Query variables :P $oldid = $this->getOldID(); # Pre-fill content with error message so that if something # fails we'll have something telling us what we intended. $this->mOldId = $oldid; $this->fetchContent( $oldid ); } /** * Fetch a page record with the given conditions * @param Database $dbr * @param array $conditions * @private */ function pageData( $dbr, $conditions ) { $fields = array( 'page_id', 'page_namespace', 'page_title', 'page_restrictions', 'page_counter', 'page_is_redirect', 'page_is_new', 'page_random', 'page_touched', 'page_latest', 'page_len' ) ; wfRunHooks( 'ArticlePageDataBefore', array( &$this , &$fields ) ) ; $row = $dbr->selectRow( 'page', $fields, $conditions, 'Article::pageData' ); wfRunHooks( 'ArticlePageDataAfter', array( &$this , &$row ) ) ; return $row ; } /** * @param Database $dbr * @param Title $title */ function pageDataFromTitle( $dbr, $title ) { return $this->pageData( $dbr, array( 'page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey() ) ); } /** * @param Database $dbr * @param int $id */ function pageDataFromId( $dbr, $id ) { return $this->pageData( $dbr, array( 'page_id' => $id ) ); } /** * Set the general counter, title etc data loaded from * some source. * * @param object $data * @private */ function loadPageData( $data = 'fromdb' ) { if ( $data === 'fromdb' ) { $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->mCounter = $data->page_counter; $this->mTouched = wfTimestamp( TS_MW, $data->page_touched ); $this->mIsRedirect = $data->page_is_redirect; $this->mLatest = $data->page_latest; } else { if ( is_object( $this->mTitle ) ) { $lc->addBadLinkObj( $this->mTitle ); } $this->mTitle->mArticleID = 0; } $this->mDataLoaded = true; } /** * Get text of an article from database * Does *NOT* follow redirects. * @param int $oldid 0 for whatever the latest revision is * @return string */ function fetchContent( $oldid = 0 ) { if ( $this->mContentLoaded ) { return $this->mContent; } $dbr = $this->getDB(); # 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( $oldid ) { $t .= ',oldid='.$oldid; } $this->mContent = wfMsg( 'missingarticle', $t ) ; if( $oldid ) { $revision = Revision::newFromId( $oldid ); if( is_null( $revision ) ) { wfDebug( __METHOD__." failed to retrieve specified revision, id $oldid\n" ); return false; } $data = $this->pageDataFromId( $dbr, $revision->getPage() ); if( !$data ) { wfDebug( __METHOD__." failed to get page data linked to revision id $oldid\n" ); return false; } $this->mTitle = Title::makeTitle( $data->page_namespace, $data->page_title ); $this->loadPageData( $data ); } else { if( !$this->mDataLoaded ) { $data = $this->pageDataFromTitle( $dbr, $this->mTitle ); if( !$data ) { wfDebug( __METHOD__." failed to find page data for title " . $this->mTitle->getPrefixedText() . "\n" ); return false; } $this->loadPageData( $data ); } $revision = Revision::newFromId( $this->mLatest ); if( is_null( $revision ) ) { wfDebug( __METHOD__." failed to retrieve current page, rev_id {$data->page_latest}\n" ); return false; } } // FIXME: Horrible, horrible! This content-loading interface just plain sucks. // We should instead work with the Revision object when we need it... $this->mContent = $revision->userCan( Revision::DELETED_TEXT ) ? $revision->getRawText() : ""; //$this->mContent = $revision->getText(); $this->mUser = $revision->getUser(); $this->mUserText = $revision->getUserText(); $this->mComment = $revision->getComment(); $this->mTimestamp = wfTimestamp( TS_MW, $revision->getTimestamp() ); $this->mRevIdFetched = $revision->getID(); $this->mContentLoaded = true; $this->mRevision =& $revision; wfRunHooks( 'ArticleAfterFetchContent', array( &$this, &$this->mContent ) ) ; return $this->mContent; } /** * Read/write accessor to select FOR UPDATE * * @param $x Mixed: FIXME */ function forUpdate( $x = NULL ) { return wfSetVar( $this->mForUpdate, $x ); } /** * Get the database which should be used for reads * * @return Database */ function getDB() { return wfGetDB( DB_MASTER ); } /** * Get options for all SELECT statements * * @param $options Array: an optional options array which'll be appended to * the default * @return Array: options */ function getSelectOptions( $options = '' ) { if ( $this->mForUpdate ) { if ( is_array( $options ) ) { $options[] = 'FOR UPDATE'; } else { $options = 'FOR UPDATE'; } } return $options; } /** * @return int Page ID */ function getID() { if( $this->mTitle ) { return $this->mTitle->getArticleID(); } else { return 0; } } /** * @return bool Whether or not the page exists in the database */ function exists() { return $this->getId() != 0; } /** * @return int The view count for the page */ function getCount() { if ( -1 == $this->mCounter ) { $id = $this->getID(); if ( $id == 0 ) { $this->mCounter = 0; } else { $dbr = wfGetDB( DB_SLAVE ); $this->mCounter = $dbr->selectField( 'page', 'page_counter', array( 'page_id' => $id ), 'Article::getCount', $this->getSelectOptions() ); } } return $this->mCounter; } /** * Determine whether a page would be suitable for being counted as an * article in the site_stats table based on the title & its content * * @param $text String: text to analyze * @return bool */ function isCountable( $text ) { global $wgUseCommaCount; $token = $wgUseCommaCount ? ',' : '[['; return $this->mTitle->isContentPage() && !$this->isRedirect( $text ) && in_string( $token, $text ); } /** * Tests if the article text represents a redirect * * @param $text String: FIXME * @return bool */ function isRedirect( $text = false ) { if ( $text === false ) { $this->loadContent(); $titleObj = Title::newFromRedirect( $this->fetchContent() ); } else { $titleObj = Title::newFromRedirect( $text ); } return $titleObj !== NULL; } /** * Returns true if the currently-referenced revision is the current edit * to this page (and it exists). * @return bool */ function isCurrent() { # If no oldid, this is the current version. if ($this->getOldID() == 0) return true; return $this->exists() && isset( $this->mRevision ) && $this->mRevision->isCurrent(); } /** * Loads everything except the text * This isn't necessary for all uses, so it's only done if needed. * @private */ function loadLastEdit() { if ( -1 != $this->mUser ) return; # New or non-existent articles have no user information $id = $this->getID(); if ( 0 == $id ) return; $this->mLastRevision = Revision::loadFromPageId( $this->getDB(), $id ); if( !is_null( $this->mLastRevision ) ) { $this->mUser = $this->mLastRevision->getUser(); $this->mUserText = $this->mLastRevision->getUserText(); $this->mTimestamp = $this->mLastRevision->getTimestamp(); $this->mComment = $this->mLastRevision->getComment(); $this->mMinorEdit = $this->mLastRevision->isMinor(); $this->mRevIdFetched = $this->mLastRevision->getID(); } } function getTimestamp() { // Check if the field has been filled by ParserCache::get() if ( !$this->mTimestamp ) { $this->loadLastEdit(); } return wfTimestamp(TS_MW, $this->mTimestamp); } function getUser() { $this->loadLastEdit(); return $this->mUser; } function getUserText() { $this->loadLastEdit(); return $this->mUserText; } function getComment() { $this->loadLastEdit(); return $this->mComment; } function getMinorEdit() { $this->loadLastEdit(); return $this->mMinorEdit; } function getRevIdFetched() { $this->loadLastEdit(); return $this->mRevIdFetched; } /** * @todo Document, fixme $offset never used. * @param $limit Integer: default 0. * @param $offset Integer: default 0. */ function getContributors($limit = 0, $offset = 0) { # XXX: this is expensive; cache this info somewhere. $contribs = array(); $dbr = wfGetDB( DB_SLAVE ); $revTable = $dbr->tableName( 'revision' ); $userTable = $dbr->tableName( 'user' ); $user = $this->getUser(); $pageId = $this->getId(); $sql = "SELECT rev_user, rev_user_text, user_real_name, MAX(rev_timestamp) as timestamp FROM $revTable LEFT JOIN $userTable ON rev_user = user_id WHERE rev_page = $pageId AND rev_user != $user GROUP BY rev_user, rev_user_text, user_real_name ORDER BY timestamp DESC"; if ($limit > 0) { $sql .= ' LIMIT '.$limit; } $sql .= ' '. $this->getSelectOptions(); $res = $dbr->query($sql, __METHOD__); while ( $line = $dbr->fetchObject( $res ) ) { $contribs[] = array($line->rev_user, $line->rev_user_text, $line->user_real_name); } $dbr->freeResult($res); return $contribs; } /** * This is the default action of the script: just view the page of * the given title. */ function view() { global $wgUser, $wgOut, $wgRequest, $wgContLang; global $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol, $wgParser; - global $wgUseTrackbacks, $wgNamespaceRobotPolicies; + global $wgUseTrackbacks, $wgNamespaceRobotPolicies, $wgArticleRobotPolicies; $sk = $wgUser->getSkin(); wfProfileIn( __METHOD__ ); $parserCache =& ParserCache::singleton(); $ns = $this->mTitle->getNamespace(); # shortcut # Get variables from query string $oldid = $this->getOldID(); # getOldID may want us to redirect somewhere else if ( $this->mRedirectUrl ) { $wgOut->redirect( $this->mRedirectUrl ); wfProfileOut( __METHOD__ ); return; } $diff = $wgRequest->getVal( 'diff' ); $rcid = $wgRequest->getVal( 'rcid' ); $rdfrom = $wgRequest->getVal( 'rdfrom' ); $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); $wgOut->setArticleFlag( true ); # Discourage indexing of printable versions, but encourage following if( $wgOut->isPrintable() ) { $policy = 'noindex,follow'; + } elseif ( isset( $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()] ) ) { + $policy = $wgArticleRobotPolicies[$this->mTitle->getPrefixedText()]; } elseif( isset( $wgNamespaceRobotPolicies[$ns] ) ) { # Honour customised robot policies for this namespace $policy = $wgNamespaceRobotPolicies[$ns]; } else { # Default to encourage indexing and following links $policy = 'index,follow'; } $wgOut->setRobotPolicy( $policy ); # If we got diff and oldid in the query, we want to see a # diff page instead of the article. if ( !is_null( $diff ) ) { $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); $de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid ); // DifferenceEngine directly fetched the revision: $this->mRevIdFetched = $de->mNewid; $de->showDiffPage( $diffOnly ); // Needed to get the page's current revision $this->loadPageData(); if( $diff == 0 || $diff == $this->mLatest ) { # Run view updates for current revision only $this->viewUpdates(); } wfProfileOut( __METHOD__ ); return; } if ( empty( $oldid ) && $this->checkTouched() ) { $wgOut->setETag($parserCache->getETag($this, $wgUser)); if( $wgOut->checkLastModified( $this->mTouched ) ){ wfProfileOut( __METHOD__ ); return; } else if ( $this->tryFileCache() ) { # tell wgOut that output is taken care of $wgOut->disable(); $this->viewUpdates(); wfProfileOut( __METHOD__ ); return; } } # Should the parser cache be used? $pcache = $wgEnableParserCache && intval( $wgUser->getOption( 'stubthreshold' ) ) == 0 && $this->exists() && empty( $oldid ); wfDebug( 'Article::view using parser cache: ' . ($pcache ? 'yes' : 'no' ) . "\n" ); if ( $wgUser->getOption( 'stubthreshold' ) ) { wfIncrStats( 'pcache_miss_stub' ); } $wasRedirected = false; if ( isset( $this->mRedirectedFrom ) ) { // This is an internally redirected page view. // We'll need a backlink to the source page for navigation. if ( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) { $sk = $wgUser->getSkin(); $redir = $sk->makeKnownLinkObj( $this->mRedirectedFrom, '', 'redirect=no' ); $s = wfMsg( 'redirectedfrom', $redir ); $wgOut->setSubtitle( $s ); // Set the fragment if one was specified in the redirect if ( strval( $this->mTitle->getFragment() ) != '' ) { $fragment = Xml::escapeJsString( $this->mTitle->getFragmentForURL() ); $wgOut->addInlineScript( "redirectToFragment(\"$fragment\");" ); } $wasRedirected = true; } } elseif ( !empty( $rdfrom ) ) { // This is an externally redirected view, from some other wiki. // If it was reported from a trusted site, supply a backlink. global $wgRedirectSources; if( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) { $sk = $wgUser->getSkin(); $redir = $sk->makeExternalLink( $rdfrom, $rdfrom ); $s = wfMsg( 'redirectedfrom', $redir ); $wgOut->setSubtitle( $s ); $wasRedirected = true; } } $outputDone = false; wfRunHooks( 'ArticleViewHeader', array( &$this ) ); if ( $pcache ) { if ( $wgOut->tryParserCache( $this, $wgUser ) ) { // Ensure that UI elements requiring revision ID have // the correct version information. $wgOut->setRevisionId( $this->mLatest ); $outputDone = true; } } if ( !$outputDone ) { $text = $this->getContent(); if ( $text === false ) { # Failed to load, replace text with error message $t = $this->mTitle->getPrefixedText(); if( $oldid ) { $t .= ',oldid='.$oldid; $text = wfMsg( 'missingarticle', $t ); } else { $text = wfMsg( 'noarticletext', $t ); } } # Another whitelist check in case oldid is altering the title if ( !$this->mTitle->userCanRead() ) { $wgOut->loginToUse(); $wgOut->output(); exit; } # We're looking at an old revision if ( !empty( $oldid ) ) { $wgOut->setRobotpolicy( 'noindex,nofollow' ); if( is_null( $this->mRevision ) ) { // FIXME: This would be a nice place to load the 'no such page' text. } else { $this->setOldSubtitle( isset($this->mOldId) ? $this->mOldId : $oldid ); if( $this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) { if( !$this->mRevision->userCan( Revision::DELETED_TEXT ) ) { $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) ); $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); return; } else { $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) ); // and we are allowed to see... } } } } } if( !$outputDone ) { $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()) ) { $wgOut->addWikiText( wfMsg('clearyourcache')); $wgOut->addHTML( '
'.htmlspecialchars($this->mContent)."\n
" ); } else if ( $rt = Title::newFromRedirect( $text ) ) { # Display redirect $imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr'; $imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png'; # Don't overwrite the subtitle if this was an old revision if( !$wasRedirected && $this->isCurrent() ) { $wgOut->setSubtitle( wfMsgHtml( 'redirectpagesub' ) ); } $link = $sk->makeLinkObj( $rt, $rt->getFullText() ); $wgOut->addHTML( '#REDIRECT ' . ''.$link.'' ); $parseout = $wgParser->parse($text, $this->mTitle, ParserOptions::newFromUser($wgUser)); $wgOut->addParserOutputNoText( $parseout ); } else if ( $pcache ) { # Display content and save to parser cache $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. if( !$this->isCurrent() ) { $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false ); } # Display content and don't save to parser cache # 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 */ $t = $wgOut->getPageTitle(); if( empty( $t ) ) { $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); } # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page if( $ns == NS_USER_TALK && User::isIP( $this->mTitle->getText() ) ) { $wgOut->addWikiText( wfMsg('anontalkpagetext') ); } # If we have been passed an &rcid= parameter, we want to give the user a # chance to mark this new article as patrolled. if ( $wgUseRCPatrol && !is_null( $rcid ) && $rcid != 0 && $wgUser->isAllowed( 'patrol' ) ) { $wgOut->addHTML( "' ); } # Trackbacks if ($wgUseTrackbacks) $this->addTrackbacks(); $this->viewUpdates(); wfProfileOut( __METHOD__ ); } function addTrackbacks() { global $wgOut, $wgUser; $dbr = wfGetDB(DB_SLAVE); $tbs = $dbr->select( /* FROM */ 'trackbacks', /* SELECT */ array('tb_id', 'tb_title', 'tb_url', 'tb_ex', 'tb_name'), /* WHERE */ array('tb_page' => $this->getID()) ); if (!$dbr->numrows($tbs)) return; $tbtext = ""; while ($o = $dbr->fetchObject($tbs)) { $rmvtxt = ""; if ($wgUser->isAllowed( 'trackback' )) { $delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid=" . $o->tb_id . "&token=" . $wgUser->editToken()); $rmvtxt = wfMsg('trackbackremove', $delurl); } $tbtext .= wfMsg(strlen($o->tb_ex) ? 'trackbackexcerpt' : 'trackback', $o->tb_title, $o->tb_url, $o->tb_ex, $o->tb_name, $rmvtxt); } $wgOut->addWikitext(wfMsg('trackbackbox', $tbtext)); } function deletetrackback() { global $wgUser, $wgRequest, $wgOut, $wgTitle; if (!$wgUser->matchEditToken($wgRequest->getVal('token'))) { $wgOut->addWikitext(wfMsg('sessionfailure')); return; } if ((!$wgUser->isAllowed('delete'))) { $wgOut->permissionRequired( 'delete' ); return; } if (wfReadOnly()) { $wgOut->readOnlyPage(); return; } $db = wfGetDB(DB_MASTER); $db->delete('trackbacks', array('tb_id' => $wgRequest->getInt('tbid'))); $wgTitle->invalidateCache(); $wgOut->addWikiText(wfMsg('trackbackdeleteok')); } function render() { global $wgOut; $wgOut->setArticleBodyOnly(true); $this->view(); } /** * Handle action=purge */ function purge() { global $wgUser, $wgRequest, $wgOut; if ( $wgUser->isAllowed( 'purge' ) || $wgRequest->wasPosted() ) { if( wfRunHooks( 'ArticlePurge', array( &$this ) ) ) { $this->doPurge(); } } else { $msg = $wgOut->parse( wfMsg( 'confirm_purge' ) ); $action = $this->mTitle->escapeLocalURL( 'action=purge' ); $button = htmlspecialchars( wfMsg( 'confirm_purge_button' ) ); $msg = str_replace( '$1', "
\n" . "\n" . "
\n", $msg ); $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->addHTML( $msg ); } } /** * Perform the actions of a page purging */ function doPurge() { global $wgUseSquid; // Invalidate the cache $this->mTitle->invalidateCache(); if ( $wgUseSquid ) { // Commit the transaction before the purge is sent $dbw = wfGetDB( DB_MASTER ); $dbw->immediateCommit(); // Send purge $update = SquidUpdate::newSimplePurge( $this->mTitle ); $update->doUpdate(); } $this->view(); } /** * Insert a new empty page record for this article. * This *must* be followed up by creating a revision * and running $this->updateToLatest( $rev_id ); * or else the record will be left in a funky state. * Best if all done inside a transaction. * * @param Database $dbw * @return int The newly created page_id key * @private */ function insertOn( $dbw ) { wfProfileIn( __METHOD__ ); $page_id = $dbw->nextSequenceValue( 'page_page_id_seq' ); $dbw->insert( 'page', array( 'page_id' => $page_id, 'page_namespace' => $this->mTitle->getNamespace(), 'page_title' => $this->mTitle->getDBkey(), 'page_counter' => 0, 'page_restrictions' => '', 'page_is_redirect' => 0, # Will set this shortly... 'page_is_new' => 1, 'page_random' => wfRandom(), 'page_touched' => $dbw->timestamp(), 'page_latest' => 0, # Fill this in shortly... 'page_len' => 0, # Fill this in shortly... ), __METHOD__ ); $newid = $dbw->insertId(); $this->mTitle->resetArticleId( $newid ); wfProfileOut( __METHOD__ ); return $newid; } /** * Update the page record to point to a newly saved revision. * * @param Database $dbw * @param Revision $revision For ID number, and text used to set length and redirect status fields * @param int $lastRevision If given, will not overwrite the page field * 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 * removing rows in redirect table. * @return bool true on success, false on failure * @private */ function updateRevisionOn( &$dbw, $revision, $lastRevision = null, $lastRevIsRedirect = null ) { wfProfileIn( __METHOD__ ); $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 $conditions['page_latest'] = $lastRevision; } $dbw->update( 'page', array( /* SET */ 'page_latest' => $revision->getId(), 'page_touched' => $dbw->timestamp(), 'page_is_new' => ($lastRevision === 0) ? 1 : 0, 'page_is_redirect' => $rt !== NULL ? 1 : 0, 'page_len' => strlen( $text ), ), $conditions, __METHOD__ ); $result = $dbw->affectedRows() != 0; if ($result) { // FIXME: Should the result from updateRedirectOn() be returned instead? $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); } wfProfileOut( __METHOD__ ); return $result; } /** * 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 * removing rows in redirect table. * @return bool true on success, false on failure * @private */ function updateRedirectOn( &$dbw, $redirectTitle, $lastRevIsRedirect = null ) { // Always update redirects (target link might have changed) // Update/Insert if we don't know if the last revision was a redirect or not // Delete if changing from redirect to non-redirect $isRedirect = !is_null($redirectTitle); if ($isRedirect || is_null($lastRevIsRedirect) || $lastRevIsRedirect !== $isRedirect) { wfProfileIn( __METHOD__ ); if ($isRedirect) { // This title is a redirect, Add/Update row in the redirect table $set = array( /* SET */ 'rd_namespace' => $redirectTitle->getNamespace(), 'rd_title' => $redirectTitle->getDBkey(), 'rd_from' => $this->getId(), ); $dbw->replace( 'redirect', array( 'rd_from' ), $set, __METHOD__ ); } else { // This is not a redirect, remove row from redirect table $where = array( 'rd_from' => $this->getId() ); $dbw->delete( 'redirect', $where, __METHOD__); } wfProfileOut( __METHOD__ ); return ( $dbw->affectedRows() != 0 ); } return true; } /** * If the given revision is newer than the currently set page_latest, * update the page record. Otherwise, do nothing. * * @param Database $dbw * @param Revision $revision */ function updateIfNewerOn( &$dbw, $revision ) { wfProfileIn( __METHOD__ ); $row = $dbw->selectRow( array( 'revision', 'page' ), array( 'rev_id', 'rev_timestamp', 'page_is_redirect' ), array( 'page_id' => $this->getId(), 'page_latest=rev_id' ), __METHOD__ ); if( $row ) { if( wfTimestamp(TS_MW, $row->rev_timestamp) >= $revision->getTimestamp() ) { wfProfileOut( __METHOD__ ); return false; } $prev = $row->rev_id; $lastRevIsRedirect = (bool)$row->page_is_redirect; } else { # No or missing previous revision; mark the page as new $prev = 0; $lastRevIsRedirect = null; } $ret = $this->updateRevisionOn( $dbw, $revision, $prev, $lastRevIsRedirect ); wfProfileOut( __METHOD__ ); return $ret; } /** * @return string Complete article text, or null if error */ 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 ); $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); } if( is_null( $rev ) ) { wfDebug( "Article::replaceSection asked for bogus section (page: " . $this->getId() . "; section: $section; edittime: $edittime)\n" ); return null; } $oldtext = $rev->getText(); if( $section == 'new' ) { # Inserting a new section $subject = $summary ? "== {$summary} ==\n\n" : ''; $text = strlen( trim( $oldtext ) ) > 0 ? "{$oldtext}\n\n{$subject}{$text}" : "{$subject}{$text}"; } else { # Replacing an existing section; roll out the big guns global $wgParser; $text = $wgParser->replaceSection( $oldtext, $section, $text ); } } wfProfileOut( __METHOD__ ); return $text; } /** * @deprecated use Article::doEdit() */ function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false, $comment=false ) { $flags = EDIT_NEW | EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ( $isminor ? EDIT_MINOR : 0 ) | ( $suppressRC ? EDIT_SUPPRESS_RC : 0 ); # If this is a comment, add the summary as headline if ( $comment && $summary != "" ) { $text = "== {$summary} ==\n\n".$text; } $this->doEdit( $text, $summary, $flags ); $dbw = wfGetDB( DB_MASTER ); if ($watchthis) { if (!$this->mTitle->userIsWatching()) { $dbw->begin(); $this->doWatch(); $dbw->commit(); } } else { if ( $this->mTitle->userIsWatching() ) { $dbw->begin(); $this->doUnwatch(); $dbw->commit(); } } $this->doRedirect( $this->isRedirect( $text ) ); } /** * @deprecated use Article::doEdit() */ function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) { $flags = EDIT_UPDATE | EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ( $minor ? EDIT_MINOR : 0 ) | ( $forceBot ? EDIT_FORCE_BOT : 0 ); $good = $this->doEdit( $text, $summary, $flags ); if ( $good ) { $dbw = wfGetDB( DB_MASTER ); if ($watchthis) { if (!$this->mTitle->userIsWatching()) { $dbw->begin(); $this->doWatch(); $dbw->commit(); } } else { if ( $this->mTitle->userIsWatching() ) { $dbw->begin(); $this->doUnwatch(); $dbw->commit(); } } $this->doRedirect( $this->isRedirect( $text ), $sectionanchor ); } return $good; } /** * Article::doEdit() * * 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. * * @param string $text New text * @param string $summary Edit summary * @param integer $flags bitfield: * EDIT_NEW * Article is known or assumed to be non-existent, create a new one * EDIT_UPDATE * Article is known or assumed to be pre-existing, update it * EDIT_MINOR * Mark this edit minor, if the user is allowed to do so * EDIT_SUPPRESS_RC * Do not log the change in recentchanges * EDIT_FORCE_BOT * Mark the edit a "bot" edit regardless of user rights * EDIT_DEFER_UPDATES * 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 * 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. * * @return bool success */ function doEdit( $text, $summary, $flags = 0 ) { global $wgUser, $wgDBtransactions; wfProfileIn( __METHOD__ ); $good = true; if ( !($flags & EDIT_NEW) && !($flags & EDIT_UPDATE) ) { $aid = $this->mTitle->getArticleID( GAID_FOR_UPDATE ); if ( $aid ) { $flags |= EDIT_UPDATE; } else { $flags |= EDIT_NEW; } } if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text, &$summary, $flags & EDIT_MINOR, null, null, &$flags ) ) ) { wfDebug( __METHOD__ . ": ArticleSave hook aborted save!\n" ); wfProfileOut( __METHOD__ ); return false; } # Silently ignore EDIT_MINOR if not allowed $isminor = ( $flags & EDIT_MINOR ) && $wgUser->isAllowed('minoredit'); $bot = $wgUser->isAllowed( 'bot' ) || ( $flags & EDIT_FORCE_BOT ); $oldtext = $this->getContent(); $oldsize = strlen( $oldtext ); # Provide autosummaries if one is not provided. if ($flags & EDIT_AUTOSUMMARY && $summary == '') $summary = $this->getAutosummary( $oldtext, $text, $flags ); $text = $this->preSaveTransform( $text ); $newsize = strlen( $text ); $dbw = wfGetDB( DB_MASTER ); $now = wfTimestampNow(); if ( $flags & EDIT_UPDATE ) { # Update article, but only if changed. # Make sure the revision is either completely inserted or not inserted at all if( !$wgDBtransactions ) { $userAbort = ignore_user_abort( true ); } $lastRevision = 0; $revisionId = 0; if ( 0 != strcmp( $text, $oldtext ) ) { $this->mGoodAdjustment = (int)$this->isCountable( $text ) - (int)$this->isCountable( $oldtext ); $this->mTotalAdjustment = 0; $lastRevision = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $this->getId() ) ); if ( !$lastRevision ) { # Article gone missing wfDebug( __METHOD__.": EDIT_UPDATE specified but article doesn't exist\n" ); wfProfileOut( __METHOD__ ); return false; } $revision = new Revision( array( 'page' => $this->getId(), 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text ) ); $dbw->begin(); $revisionId = $revision->insertOn( $dbw ); # Update page $ok = $this->updateRevisionOn( $dbw, $revision, $lastRevision ); if( !$ok ) { /* Belated edit conflict! Run away!! */ $good = false; $dbw->rollback(); } else { # Update recentchanges if( !( $flags & EDIT_SUPPRESS_RC ) ) { $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( $GLOBALS['wgUseRCPatrol'] && $wgUser->isAllowed( 'autopatrol' ) ) { RecentChange::markPatrolled( $rcid ); PatrolLog::record( $rcid, true ); } } $wgUser->incEditCount(); $dbw->commit(); } } else { // Keep the same revision ID, but do some updates on it $revisionId = $this->getRevIdFetched(); // Update page_touched, this is usually implicit in the page update // Other cache updates are done in onArticleEdit() $this->mTitle->invalidateCache(); } if( !$wgDBtransactions ) { ignore_user_abort( $userAbort ); } if ( $good ) { # 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 # when articles are created with {{subst:}} $this->mGoodAdjustment = (int)$this->isCountable( $text ); $this->mTotalAdjustment = 1; $dbw->begin(); # Add the page record; stake our claim on this title! # This will fail with a database query exception if the article already exists $newid = $this->insertOn( $dbw ); # Save the revision text... $revision = new Revision( array( 'page' => $newid, 'comment' => $summary, 'minor_edit' => $isminor, 'text' => $text ) ); $revisionId = $revision->insertOn( $dbw ); $this->mTitle->resetArticleID( $newid ); # Update the page record with revision data $this->updateRevisionOn( $dbw, $revision, 0 ); if( !( $flags & EDIT_SUPPRESS_RC ) ) { $rcid = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary, $bot, '', strlen( $text ), $revisionId ); # Mark as patrolled if the user can if( $GLOBALS['wgUseRCPatrol'] && $wgUser->isAllowed( 'autopatrol' ) ) { RecentChange::markPatrolled( $rcid ); PatrolLog::record( $rcid, true ); } } $wgUser->incEditCount(); $dbw->commit(); # Update links, etc. $this->editUpdates( $text, $summary, $isminor, $now, $revisionId, true ); # Clear caches Article::onArticleCreate( $this->mTitle ); wfRunHooks( 'ArticleInsertComplete', array( &$this, &$wgUser, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags ) ); } if ( $good && !( $flags & EDIT_DEFER_UPDATES ) ) { wfDoUpdates(); } wfRunHooks( 'ArticleSaveComplete', array( &$this, &$wgUser, $text, $summary, $flags & EDIT_MINOR, null, null, &$flags ) ); wfProfileOut( __METHOD__ ); return $good; } /** * @deprecated wrapper for doRedirect */ function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid ) { $this->doRedirect( $this->isRedirect( $text ), $sectionanchor ); } /** * Output a redirect back to the article. * This is typically used after an edit. * * @param boolean $noRedir Add redirect=no * @param string $sectionAnchor section to redirect to, including "#" */ function doRedirect( $noRedir = false, $sectionAnchor = '' ) { global $wgOut; if ( $noRedir ) { $query = 'redirect=no'; } else { $query = ''; } $wgOut->redirect( $this->mTitle->getFullURL( $query ) . $sectionAnchor ); } /** * Mark this particular edit as patrolled */ function markpatrolled() { global $wgOut, $wgRequest, $wgUseRCPatrol, $wgUser; $wgOut->setRobotPolicy( 'noindex,nofollow' ); # Check RC patrol config. option if( !$wgUseRCPatrol ) { $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 # other conditions stopping them doing so if( !$wgUser->isAllowed( 'autopatrol' ) ) { $rc = RecentChange::newFromId( $rcid ); # Graceful error handling, as we've done before here... # (If the recent change doesn't exist, then it doesn't matter whether # the user is allowed to patrol it or not; nothing is going to happen if( is_object( $rc ) && $wgUser->getName() == $rc->getAttribute( 'rc_user_text' ) ) { # The user made this edit, and can't patrol it # Tell them so, and then back off $wgOut->setPageTitle( wfMsg( 'markedaspatrollederror' ) ); $wgOut->addWikiText( wfMsgNoTrans( 'markedaspatrollederror-noautopatrol' ) ); $wgOut->returnToMain( false, $return ); 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' ) ); $wgOut->returnToMain( false, $return ); } /** * User-interface handler for the "watch" action */ function watch() { global $wgUser, $wgOut; if ( $wgUser->isAnon() ) { $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' ); return; } if ( wfReadOnly() ) { $wgOut->readOnlyPage(); return; } if( $this->doWatch() ) { $wgOut->setPagetitle( wfMsg( 'addedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $link = wfEscapeWikiText( $this->mTitle->getPrefixedText() ); $text = wfMsg( 'addedwatchtext', $link ); $wgOut->addWikiText( $text ); } $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } /** * Add this page to $wgUser's watchlist * @return bool true on successful watch operation */ function doWatch() { global $wgUser; if( $wgUser->isAnon() ) { return false; } if (wfRunHooks('WatchArticle', array(&$wgUser, &$this))) { $wgUser->addWatch( $this->mTitle ); return wfRunHooks('WatchArticleComplete', array(&$wgUser, &$this)); } return false; } /** * User interface handler for the "unwatch" action. */ function unwatch() { global $wgUser, $wgOut; if ( $wgUser->isAnon() ) { $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' ); return; } if ( wfReadOnly() ) { $wgOut->readOnlyPage(); return; } if( $this->doUnwatch() ) { $wgOut->setPagetitle( wfMsg( 'removedwatch' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $link = wfEscapeWikiText( $this->mTitle->getPrefixedText() ); $text = wfMsg( 'removedwatchtext', $link ); $wgOut->addWikiText( $text ); } $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); } /** * Stop watching a page * @return bool true on successful unwatch */ function doUnwatch() { global $wgUser; if( $wgUser->isAnon() ) { return false; } if (wfRunHooks('UnwatchArticle', array(&$wgUser, &$this))) { $wgUser->removeWatch( $this->mTitle ); return wfRunHooks('UnwatchArticleComplete', array(&$wgUser, &$this)); } return false; } /** * action=protect handler */ function protect() { $form = new ProtectionForm( $this ); $form->execute(); } /** * action=unprotect handler (alias) */ function unprotect() { $this->protect(); } /** * Update the article's restriction field, and leave a log entry. * * @param array $limit set of restriction keys * @param string $reason * @return bool true on success */ 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(); foreach( $wgRestrictionTypes as $action ) $current[$action] = implode( '', $this->mTitle->getRestrictions( $action ) ); $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 ); $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' => '', '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]$cascade_description$expiry_description" ) ); } else { $log->addEntry( 'unprotect', $this->mTitle, $reason ); } } # End hook } # End "changed" check return true; } /** * Take an array of page restrictions and flatten it to a string * suitable for insertion into the page_restrictions field. * @param array $limit * @return string * @private */ function flattenRestrictions( $limit ) { if( !is_array( $limit ) ) { throw new MWException( 'Article::flattenRestrictions given non-array restriction set' ); } $bits = array(); ksort( $limit ); foreach( $limit as $action => $restrictions ) { if( $restrictions != '' ) { $bits[] = "$action=$restrictions"; } } return implode( ':', $bits ); } /* * UI entry point for page deletion */ function delete() { global $wgUser, $wgOut, $wgRequest; $confirm = $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); $reason = $wgRequest->getText( 'wpReason' ); # This code desperately needs to be totally rewritten # Check permissions if( $wgUser->isAllowed( 'delete' ) ) { if( $wgUser->isBlocked( !$confirm ) ) { $wgOut->blockedPage(); return; } } else { $wgOut->permissionRequired( 'delete' ); return; } if( wfReadOnly() ) { $wgOut->readOnlyPage(); return; } $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) ); # Better double-check that it hasn't been deleted yet! $dbw = wfGetDB( DB_MASTER ); $conds = $this->mTitle->pageCond(); $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ ); if ( $latest === false ) { $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); return; } if( $confirm ) { $this->doDelete( $reason ); if( $wgRequest->getCheck( 'wpWatch' ) ) { $this->doWatch(); } elseif( $this->mTitle->userIsWatching() ) { $this->doUnwatch(); } return; } # determine whether this page has earlier revisions # 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() . '' ); } # If a single user is responsible for all revisions, find out who they are if ( count( $authors ) == $maxRevisions ) { // Query bailed out, too many revisions to find out if they're all the same $authorOfAll = false; } else { $authorOfAll = reset( $authors ); foreach ( $authors as $author ) { if ( $authorOfAll != $author ) { $authorOfAll = false; break; } } } # Fetch article text $rev = Revision::newFromTitle( $this->mTitle ); if( !is_null( $rev ) ) { # if this is a mini-text, we can paste part of it into the deletion reason $text = $rev->getText(); #if this is empty, an earlier revision may contain "useful" text $blanked = false; if( $text == '' ) { $prev = $rev->getPrevious(); if( $prev ) { $text = $prev->getText(); $blanked = true; } } $length = strlen( $text ); # this should not happen, since it is not possible to store an empty, new # page. Let's insert a standard text in case it does, though if( $length == 0 && $reason === '' ) { $reason = wfMsgForContent( 'exblank' ); } if( $reason === '' ) { # comment field=255, let's grep the first 150 to have some user # space left global $wgContLang; $text = $wgContLang->truncate( $text, 150, '...' ); # let's strip out newlines $text = preg_replace( "/[\n\r]/", '', $text ); if( !$blanked ) { if( $authorOfAll === false ) { $reason = wfMsgForContent( 'excontent', $text ); } else { $reason = wfMsgForContent( 'excontentauthor', $text, $authorOfAll ); } } else { $reason = wfMsgForContent( 'exbeforeblank', $text ); } } } return $this->confirmDelete( '', $reason ); } /** * Get the last N authors * @param int $num Number of revisions to get * @param string $revLatest The latest rev_id, selected from the master (optional) * @return array Array of authors, duplicates not removed */ function getLastNAuthors( $num, $revLatest = 0 ) { wfProfileIn( __METHOD__ ); // First try the slave // If that doesn't have the latest revision, try the master $continue = 2; $db = wfGetDB( DB_SLAVE ); do { $res = $db->select( array( 'page', 'revision' ), array( 'rev_id', 'rev_user_text' ), array( 'page_namespace' => $this->mTitle->getNamespace(), 'page_title' => $this->mTitle->getDBkey(), 'rev_page = page_id' ), __METHOD__, $this->getSelectOptions( array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => $num ) ) ); if ( !$res ) { wfProfileOut( __METHOD__ ); return array(); } $row = $db->fetchObject( $res ); if ( $continue == 2 && $revLatest && $row->rev_id != $revLatest ) { $db = wfGetDB( DB_MASTER ); $continue--; } else { $continue = 0; } } while ( $continue ); $authors = array( $row->rev_user_text ); while ( $row = $db->fetchObject( $res ) ) { $authors[] = $row->rev_user_text; } wfProfileOut( __METHOD__ ); return $authors; } /** * Output deletion confirmation dialog */ function confirmDelete( $par, $reason ) { global $wgOut, $wgUser; wfDebug( "Article::confirmDelete\n" ); $sub = htmlspecialchars( $this->mTitle->getPrefixedText() ); $wgOut->setSubtitle( wfMsg( 'deletesub', $sub ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->addWikiText( wfMsg( 'confirmdeletetext' ) ); $formaction = $this->mTitle->escapeLocalURL( 'action=delete' . $par ); $confirm = htmlspecialchars( wfMsg( 'deletepage' ) ); $delcom = htmlspecialchars( wfMsg( 'deletecomment' ) ); $token = htmlspecialchars( $wgUser->editToken() ); $watch = Xml::checkLabel( wfMsg( 'watchthis' ), 'wpWatch', 'wpWatch', $wgUser->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching(), array( 'tabindex' => '2' ) ); $wgOut->addHTML( "
  $watch
 
\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 ); } /** * Perform a deletion and output success or failure messages */ function doDelete( $reason ) { global $wgOut, $wgUser; wfDebug( __METHOD__."\n" ); if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) { if ( $this->doDeleteArticle( $reason ) ) { $deleted = wfEscapeWikiText( $this->mTitle->getPrefixedText() ); $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $loglink = '[[Special:Log/delete|' . wfMsg( 'deletionlog' ) . ']]'; $text = wfMsg( 'deletedtext', $deleted, $loglink ); $wgOut->addWikiText( $text ); $wgOut->returnToMain( false ); wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason)); } else { $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); } } } /** * Back-end article deletion * Deletes the article with database consistency, writes logs, purges caches * Returns success */ function doDeleteArticle( $reason ) { global $wgUseSquid, $wgDeferredUpdateList; global $wgUseTrackbacks; wfDebug( __METHOD__."\n" ); $dbw = wfGetDB( DB_MASTER ); $ns = $this->mTitle->getNamespace(); $t = $this->mTitle->getDBkey(); $id = $this->mTitle->getArticleID(); if ( $t == '' || $id == 0 ) { return false; } $u = new SiteStatsUpdate( 0, 1, -(int)$this->isCountable( $this->getContent() ), -1 ); array_push( $wgDeferredUpdateList, $u ); // For now, shunt the revision data into the archive table. // Text is *not* removed from the text table; bulk storage // is left intact to avoid breaking block-compression or // immutable storage schemes. // // For backwards compatibility, note that some older archive // table entries will have ar_text and ar_flags fields still. // // In the future, we may keep revisions and mark them with // the rev_deleted field, which is reserved for this purpose. $dbw->insertSelect( 'archive', array( 'page', 'revision' ), array( 'ar_namespace' => 'page_namespace', 'ar_title' => 'page_title', 'ar_comment' => 'rev_comment', 'ar_user' => 'rev_user', 'ar_user_text' => 'rev_user_text', 'ar_timestamp' => 'rev_timestamp', 'ar_minor_edit' => 'rev_minor_edit', 'ar_rev_id' => 'rev_id', '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__); # If using cascading deletes, we can skip some explicit deletes if ( !$dbw->cascadingDeletes() ) { $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ ); if ($wgUseTrackbacks) $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ ); # Delete outgoing links $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) ); $dbw->delete( 'imagelinks', array( 'il_from' => $id ) ); $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) ); $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) ); $dbw->delete( 'externallinks', array( 'el_from' => $id ) ); $dbw->delete( 'langlinks', array( 'll_from' => $id ) ); $dbw->delete( 'redirect', array( 'rd_from' => $id ) ); } # If using cleanup triggers, we can skip some manual deletes if ( !$dbw->cleanupTriggers() ) { # Clean up recentchanges entries... $dbw->delete( 'recentchanges', array( 'rc_namespace' => $ns, 'rc_title' => $t ), __METHOD__ ); } # Clear caches Article::onArticleDelete( $this->mTitle ); # Log the deletion $log = new LogPage( 'delete' ); $log->addEntry( 'delete', $this->mTitle, $reason ); # Clear the cached article id so the interface doesn't act like we exist $this->mTitle->resetArticleID( 0 ); $this->mTitle->mArticleID = 0; return true; } /** * Revert a modification */ function rollback() { global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; if( $wgUser->isAllowed( 'rollback' ) ) { if( $wgUser->isBlocked() ) { $wgOut->blockedPage(); return; } } else { $wgOut->permissionRequired( 'rollback' ); return; } if ( wfReadOnly() ) { $wgOut->readOnlyPage( $this->getContent() ); return; } if( !$wgUser->matchEditToken( $wgRequest->getVal( 'token' ), array( $this->mTitle->getPrefixedText(), $wgRequest->getVal( 'from' ) ) ) ) { $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); $wgOut->addWikiText( wfMsg( 'sessionfailure' ) ); return; } $dbw = wfGetDB( DB_MASTER ); # Enhanced rollback, marks edits rc_bot=1 $bot = $wgRequest->getBool( 'bot' ); # Replace all this user's current edits with the next one down # Get the last editor $current = Revision::newFromTitle( $this->mTitle ); if( is_null( $current ) ) { # Something wrong... no page? $wgOut->addHTML( wfMsg( 'notanarticle' ) ); return; } $from = str_replace( '_', ' ', $wgRequest->getVal( 'from' ) ); if( $from != $current->getUserText() ) { $wgOut->setPageTitle( wfMsg('rollbackfailed') ); $wgOut->addWikiText( wfMsg( 'alreadyrolled', htmlspecialchars( $this->mTitle->getPrefixedText()), htmlspecialchars( $from ), htmlspecialchars( $current->getUserText() ) ) ); if( $current->getComment() != '') { $wgOut->addHTML( wfMsg( 'editcomment', $wgUser->getSkin()->formatComment( $current->getComment() ) ) ); } return; } # Get the last edit not by this guy $user = intval( $current->getUser() ); $user_text = $dbw->addQuotes( $current->getUserText() ); $s = $dbw->selectRow( 'revision', array( 'rev_id', 'rev_timestamp' ), array( 'rev_page' => $current->getPage(), "rev_user <> {$user} OR rev_user_text <> {$user_text}" ), __METHOD__, array( 'USE INDEX' => 'page_timestamp', 'ORDER BY' => 'rev_timestamp DESC' ) ); if( $s === false ) { # Something wrong $wgOut->setPageTitle(wfMsg('rollbackfailed')); $wgOut->addHTML( wfMsg( 'cantrollback' ) ); return; } $set = array(); if ( $bot ) { # Mark all reverted edits as bot $set['rc_bot'] = 1; } if ( $wgUseRCPatrol ) { # Mark all reverted edits as patrolled $set['rc_patrolled'] = 1; } if ( $set ) { $dbw->update( 'recentchanges', $set, array( /* WHERE */ 'rc_cur_id' => $current->getPage(), 'rc_user_text' => $current->getUserText(), "rc_timestamp > '{$s->rev_timestamp}'", ), __METHOD__ ); } # Get the edit summary $target = Revision::newFromId( $s->rev_id ); $newComment = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); $newComment = $wgRequest->getText( 'summary', $newComment ); # Save it! $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->addHTML( '

' . htmlspecialchars( $newComment ) . "

\n
\n" ); $this->updateArticle( $target->getText(), $newComment, 1, $this->mTitle->userIsWatching(), $bot ); $wgOut->returnToMain( false ); } /** * Do standard deferred updates after page view * @private */ function viewUpdates() { global $wgDeferredUpdateList; if ( 0 != $this->getID() ) { global $wgDisableCounters; if( !$wgDisableCounters ) { Article::incViewCount( $this->getID() ); $u = new SiteStatsUpdate( 1, 0, 0 ); array_push( $wgDeferredUpdateList, $u ); } } # Update newtalk / watchlist notification status global $wgUser; $wgUser->clearNotification( $this->mTitle ); } /** * 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 * @param $minoredit Minor edit * @param $timestamp_of_pagechange Timestamp associated with the page change * @param $newid rev_id value of the new revision * @param $changed Whether or not the content actually changed */ function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true ) { global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser; wfProfileIn( __METHOD__ ); # Parse the text $options = new ParserOptions; $options->setTidy(true); $poutput = $wgParser->parse( $text, $this->mTitle, $options, true, true, $newid ); # Save it to the parser cache $parserCache =& ParserCache::singleton(); $parserCache->save( $poutput, $this, $wgUser ); # Update the links tables $u = new LinksUpdate( $this->mTitle, $poutput ); $u->doUpdate(); if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) { wfSeedRandom(); if ( 0 == mt_rand( 0, 999 ) ) { # Periodically flush old entries from the recentchanges table. global $wgRCMaxAge; $dbw = wfGetDB( DB_MASTER ); $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); $recentchanges = $dbw->tableName( 'recentchanges' ); $sql = "DELETE FROM $recentchanges WHERE rc_timestamp < '{$cutoff}'"; $dbw->query( $sql ); } } $id = $this->getID(); $title = $this->mTitle->getPrefixedDBkey(); $shortTitle = $this->mTitle->getDBkey(); if ( 0 == $id ) { wfProfileOut( __METHOD__ ); return; } $u = new SiteStatsUpdate( 0, 1, $this->mGoodAdjustment, $this->mTotalAdjustment ); array_push( $wgDeferredUpdateList, $u ); $u = new SearchUpdate( $id, $title, $text ); array_push( $wgDeferredUpdateList, $u ); # If this is another user's talk page, update newtalk # Don't do this if $changed = false otherwise some idiot can null-edit a # load of user talk pages and piss people off, nor if it's a minor edit # by a properly-flagged bot. if( $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getTitleKey() && $changed && !($minoredit && $wgUser->isAllowed('nominornewtalk') ) ) { if (wfRunHooks('ArticleEditUpdateNewTalk', array(&$this)) ) { $other = User::newFromName( $shortTitle ); if( is_null( $other ) && User::isIP( $shortTitle ) ) { // An anonymous user $other = new User(); $other->setName( $shortTitle ); } if( $other ) { $other->setNewtalk( true ); } } } if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { $wgMessageCache->replace( $shortTitle, $text ); } wfProfileOut( __METHOD__ ); } /** * Perform article updates on a special page creation. * * @param Revision $rev * * @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. */ function createUpdates( $rev ) { $this->mGoodAdjustment = $this->isCountable( $rev->getText() ); $this->mTotalAdjustment = 1; $this->editUpdates( $rev->getText(), $rev->getComment(), $rev->isMinor(), wfTimestamp(), $rev->getId(), true ); } /** * Generate the navigation links when browsing through an article revisions * It shows the information as: * Revision as of \; view current revision * \<- Previous version | Next Version -\> * * @private * @param string $oldid Revision ID of this article revision */ function setOldSubtitle( $oldid=0 ) { global $wgLang, $wgOut, $wgUser; if ( !wfRunHooks( 'DisplayOldSubtitle', array(&$this, &$oldid) ) ) { return; } $revision = Revision::newFromId( $oldid ); $current = ( $oldid == $this->mLatest ); $td = $wgLang->timeanddate( $this->mTimestamp, true ); $sk = $wgUser->getSkin(); $lnk = $current ? wfMsg( 'currentrevisionlink' ) : $lnk = $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'currentrevisionlink' ) ); $curdiff = $current ? wfMsg( 'diff' ) : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=cur&oldid='.$oldid ); $prev = $this->mTitle->getPreviousRevisionID( $oldid ) ; $prevlink = $prev ? $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'previousrevision' ), 'direction=prev&oldid='.$oldid ) : wfMsg( 'previousrevision' ); $prevdiff = $prev ? $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=prev&oldid='.$oldid ) : wfMsg( 'diff' ); $nextlink = $current ? wfMsg( 'nextrevision' ) : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'nextrevision' ), 'direction=next&oldid='.$oldid ); $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 ); } /** * This function is called right before saving the wikitext, * so we can do things like signatures and links-in-context. * * @param string $text */ function preSaveTransform( $text ) { global $wgParser, $wgUser; return $wgParser->preSaveTransform( $text, $this->mTitle, $wgUser, ParserOptions::newFromUser( $wgUser ) ); } /* Caching functions */ /** * checkLastModified returns true if 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 ) { wfDebug( "Article::tryFileCache(): called twice!?\n" ); return; } $called = true; if($this->isFileCacheable()) { $touched = $this->mTouched; $cache = new HTMLFileCache( $this->mTitle ); if($cache->isFileCacheGood( $touched )) { wfDebug( "Article::tryFileCache(): about to load file\n" ); $cache->loadFromFileCache(); return true; } else { wfDebug( "Article::tryFileCache(): starting buffer\n" ); ob_start( array(&$cache, 'saveToFileCache' ) ); } } else { wfDebug( "Article::tryFileCache(): not cacheable\n" ); } } /** * Check if the page can be cached * @return bool */ function isFileCacheable() { 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(); $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; } /** * Loads page_touched and returns a value indicating if it should be used * */ function checkTouched() { if( !$this->mDataLoaded ) { $this->loadPageData(); } return !$this->mIsRedirect; } /** * Get the page_touched field */ function getTouched() { # Ensure that page data has been loaded if( !$this->mDataLoaded ) { $this->loadPageData(); } return $this->mTouched; } /** * Get the page_latest field */ function getLatest() { if ( !$this->mDataLoaded ) { $this->loadPageData(); } return $this->mLatest; } /** * Edit an article without doing all that other stuff * The article must already exist; link tables etc * are not updated, caches are not flushed. * * @param string $text text submitted * @param string $comment comment submitted * @param bool $minor whereas it's a minor modification */ function quickEdit( $text, $comment = '', $minor = 0 ) { wfProfileIn( __METHOD__ ); $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $revision = new Revision( array( 'page' => $this->getId(), 'text' => $text, 'comment' => $comment, 'minor_edit' => $minor ? 1 : 0, ) ); $revision->insertOn( $dbw ); $this->updateRevisionOn( $dbw, $revision ); $dbw->commit(); wfProfileOut( __METHOD__ ); } /** * Used to increment the view counter * * @static * @param integer $id article id */ function incViewCount( $id ) { $id = intval( $id ); global $wgHitcounterUpdateFreq, $wgDBtype; $dbw = wfGetDB( DB_MASTER ); $pageTable = $dbw->tableName( 'page' ); $hitcounterTable = $dbw->tableName( 'hitcounter' ); $acchitsTable = $dbw->tableName( 'acchits' ); if( $wgHitcounterUpdateFreq <= 1 ) { $dbw->query( "UPDATE $pageTable SET page_counter = page_counter + 1 WHERE page_id = $id" ); return; } # Not important enough to warrant an error page in case of failure $oldignore = $dbw->ignoreErrors( true ); $dbw->query( "INSERT INTO $hitcounterTable (hc_id) VALUES ({$id})" ); $checkfreq = intval( $wgHitcounterUpdateFreq/25 + 1 ); if( (rand() % $checkfreq != 0) or ($dbw->lastErrno() != 0) ){ # Most of the time (or on SQL errors), skip row count check $dbw->ignoreErrors( $oldignore ); return; } $res = $dbw->query("SELECT COUNT(*) as n FROM $hitcounterTable"); $row = $dbw->fetchObject( $res ); $rown = intval( $row->n ); if( $rown >= $wgHitcounterUpdateFreq ){ wfProfileIn( 'Article::incViewCount-collect' ); $old_user_abort = ignore_user_abort( true ); if ($wgDBtype == 'mysql') $dbw->query("LOCK TABLES $hitcounterTable WRITE"); $tabletype = $wgDBtype == 'mysql' ? "ENGINE=HEAP " : ''; $dbw->query("CREATE TEMPORARY TABLE $acchitsTable $tabletype AS ". "SELECT hc_id,COUNT(*) AS hc_n FROM $hitcounterTable ". 'GROUP BY hc_id'); $dbw->query("DELETE FROM $hitcounterTable"); if ($wgDBtype == 'mysql') { $dbw->query('UNLOCK TABLES'); $dbw->query("UPDATE $pageTable,$acchitsTable SET page_counter=page_counter + hc_n ". 'WHERE page_id = hc_id'); } else { $dbw->query("UPDATE $pageTable SET page_counter=page_counter + hc_n ". "FROM $acchitsTable WHERE page_id = hc_id"); } $dbw->query("DROP TABLE $acchitsTable"); ignore_user_abort( $old_user_abort ); wfProfileOut( 'Article::incViewCount-collect' ); } $dbw->ignoreErrors( $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. * * This is called on page move and undelete, as well as edit * @static * @param $title_obj a title object */ static function onArticleCreate($title) { # The talk page isn't in the regular link tables, so we need to update manually: if ( $title->isTalkPage() ) { $other = $title->getSubjectPage(); } else { $other = $title->getTalkPage(); } $other->invalidateCache(); $other->purgeSquid(); $title->touchLinks(); $title->purgeSquid(); } static function onArticleDelete( $title ) { global $wgUseFileCache, $wgMessageCache; $title->touchLinks(); $title->purgeSquid(); # File cache if ( $wgUseFileCache ) { $cm = new HTMLFileCache( $title ); @unlink( $cm->fileCacheName() ); } if( $title->getNamespace() == NS_MEDIAWIKI) { $wgMessageCache->replace( $title->getDBkey(), false ); } } /** * Purge caches on page update etc */ static function onArticleEdit( $title ) { global $wgDeferredUpdateList, $wgUseFileCache; // Invalidate caches of articles which include this page $update = new HTMLCacheUpdate( $title, 'templatelinks' ); $wgDeferredUpdateList[] = $update; # Purge squid for this page only $title->purgeSquid(); # Clear file cache if ( $wgUseFileCache ) { $cm = new HTMLFileCache( $title ); @unlink( $cm->fileCacheName() ); } } /**#@-*/ /** * Info about this page * Called for ?action=info when $wgAllowPageInfo is on. * * @public */ function info() { global $wgLang, $wgOut, $wgAllowPageInfo, $wgUser; if ( !$wgAllowPageInfo ) { $wgOut->showErrorPage( 'nosuchaction', 'nosuchactiontext' ); return; } $page = $this->mTitle->getSubjectPage(); $wgOut->setPagetitle( $page->getPrefixedText() ); $wgOut->setSubtitle( wfMsg( 'infosubtitle' )); # first, see if the page exists at all. $exists = $page->getArticleId() != 0; if( !$exists ) { if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { $wgOut->addHTML(wfMsgWeirdKey ( $this->mTitle->getText() ) ); } else { $wgOut->addHTML(wfMsg( $wgUser->isLoggedIn() ? 'noarticletext' : 'noarticletextanon' ) ); } } else { $dbr = wfGetDB( DB_SLAVE ); $wl_clause = array( 'wl_title' => $page->getDBkey(), 'wl_namespace' => $page->getNamespace() ); $numwatchers = $dbr->selectField( 'watchlist', 'COUNT(*)', $wl_clause, __METHOD__, $this->getSelectOptions() ); $pageInfo = $this->pageCountInfo( $page ); $talkInfo = $this->pageCountInfo( $page->getTalkPage() ); $wgOut->addHTML( "' ); } } /** * Return the total number of edits and number of unique editors * on a given page. If page does not exist, returns false. * * @param Title $title * @return array * @private */ function pageCountInfo( $title ) { $id = $title->getArticleId(); if( $id == 0 ) { return false; } $dbr = wfGetDB( DB_SLAVE ); $rev_clause = array( 'rev_page' => $id ); $edits = $dbr->selectField( 'revision', 'COUNT(rev_page)', $rev_clause, __METHOD__, $this->getSelectOptions() ); $authors = $dbr->selectField( 'revision', 'COUNT(DISTINCT rev_user_text)', $rev_clause, __METHOD__, $this->getSelectOptions() ); return array( 'edits' => $edits, 'authors' => $authors ); } /** * Return a list of templates used by this article. * Uses the templatelinks table * * @return array Array of Title objects */ function getUsedTemplates() { $result = array(); $id = $this->mTitle->getArticleID(); if( $id == 0 ) { return array(); } $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( array( 'templatelinks' ), array( 'tl_namespace', 'tl_title' ), array( 'tl_from' => $id ), 'Article:getUsedTemplates' ); if ( false !== $res ) { if ( $dbr->numRows( $res ) ) { while ( $row = $dbr->fetchObject( $res ) ) { $result[] = Title::makeTitle( $row->tl_namespace, $row->tl_title ); } } } $dbr->freeResult( $res ); return $result; } /** * Return an auto-generated summary if the text provided is a redirect. * * @param string $text The wikitext to check * @return string '' or an appropriate summary */ public static function getRedirectAutosummary( $text ) { $rt = Title::newFromRedirect( $text ); if( is_object( $rt ) ) return wfMsgForContent( 'autoredircomment', $rt->getFullText() ); else return ''; } /** * Return an auto-generated summary if the new text is much shorter than * the old text. * * @param string $oldtext The previous text of the page * @param string $text The submitted text of the page * @return string An appropriate autosummary, or an empty string. */ public static function getBlankingAutosummary( $oldtext, $text ) { if ($oldtext!='' && $text=='') { return wfMsgForContent('autosumm-blank'); } elseif (strlen($oldtext) > 10 * strlen($text) && strlen($text) < 500) { #Removing more than 90% of the article global $wgContLang; $truncatedtext = $wgContLang->truncate($text, max(0, 200 - strlen(wfMsgForContent('autosumm-replace'))), '...'); return wfMsgForContent('autosumm-replace', $truncatedtext); } else { return ''; } } /** * Return an applicable autosummary if one exists for the given edit. * @param string $oldtext The previous text of the page. * @param string $newtext The submitted text of the page. * @param bitmask $flags A bitmask of flags submitted for the edit. * @return string An appropriate autosummary, or an empty string. */ public static function getAutosummary( $oldtext, $newtext, $flags ) { # This code is UGLY UGLY UGLY. # Somebody PLEASE come up with a more elegant way to do it. #Redirect autosummaries $summary = self::getRedirectAutosummary( $newtext ); if ($summary) return $summary; #Blanking autosummaries if (!($flags & EDIT_NEW)) $summary = self::getBlankingAutosummary( $oldtext, $newtext ); if ($summary) return $summary; #New page autosummaries if ($flags & EDIT_NEW && strlen($newtext)) { #If they're making a new article, give its text, truncated, in the summary. global $wgContLang; $truncatedtext = $wgContLang->truncate( str_replace("\n", ' ', $newtext), max( 0, 200 - strlen( wfMsgForContent( 'autosumm-new') ) ), '...' ); $summary = wfMsgForContent( 'autosumm-new', $truncatedtext ); } if ($summary) return $summary; 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 ); } } ?> Index: trunk/phase3/includes/DefaultSettings.php =================================================================== --- trunk/phase3/includes/DefaultSettings.php (revision 22614) +++ trunk/phase3/includes/DefaultSettings.php (revision 22615) @@ -1,2633 +1,2643 @@ Causes problems with HTML escaping, don't use * % Enabled by default, minor problems with path to query rewrite rules, see below * + Enabled by default, but doesn't work with path to query rewrite rules, corrupted by apache * ? Enabled by default, but doesn't work with path to PATH_INFO rewrites * * All three of these punctuation problems can be avoided by using an alias, instead of a * rewrite rule of either variety. * * The problem with % is that when using a path to query rewrite rule, URLs are * double-unescaped: once by Apache's path conversion code, and again by PHP. So * %253F, for example, becomes "?". Our code does not double-escape to compensate * for this, indeed double escaping would break if the double-escaped title was * passed in the query string rather than the path. This is a minor security issue * because articles can be created such that they are hard to view or edit. * * In some rare cases you may wish to remove + for compatibility with old links. * * Theoretically 0x80-0x9F of ISO 8859-1 should be disallowed, but * this breaks interlanguage links */ $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+"; /** * The external URL protocols */ $wgUrlProtocols = array( 'http://', 'https://', 'ftp://', 'irc://', 'gopher://', 'telnet://', // Well if we're going to support the above.. -ævar 'nntp://', // @bug 3808 RFC 1738 'worldwind://', 'mailto:', 'news:' ); /** internal name of virus scanner. This servers as a key to the $wgAntivirusSetup array. * Set this to NULL to disable virus scanning. If not null, every file uploaded will be scanned for viruses. * @global string $wgAntivirus */ $wgAntivirus= NULL; /** Configuration for different virus scanners. This an associative array of associative arrays: * it contains on setup array per known scanner type. The entry is selected by $wgAntivirus, i.e. * valid values for $wgAntivirus are the keys defined in this array. * * The configuration array for each scanner contains the following keys: "command", "codemap", "messagepattern"; * * "command" is the full command to call the virus scanner - %f will be replaced with the name of the * file to scan. If not present, the filename will be appended to the command. Note that this must be * overwritten if the scanner is not in the system path; in that case, plase set * $wgAntivirusSetup[$wgAntivirus]['command'] to the desired command with full path. * * "codemap" is a mapping of exit code to return codes of the detectVirus function in SpecialUpload. * An exit code mapped to AV_SCAN_FAILED causes the function to consider the scan to be failed. This will pass * the file if $wgAntivirusRequired is not set. * An exit code mapped to AV_SCAN_ABORTED causes the function to consider the file to have an usupported format, * which is probably imune to virusses. This causes the file to pass. * An exit code mapped to AV_NO_VIRUS will cause the file to pass, meaning no virus was found. * All other codes (like AV_VIRUS_FOUND) will cause the function to report a virus. * You may use "*" as a key in the array to catch all exit codes not mapped otherwise. * * "messagepattern" is a perl regular expression to extract the meaningful part of the scanners * output. The relevant part should be matched as group one (\1). * If not defined or the pattern does not match, the full message is shown to the user. * * @global array $wgAntivirusSetup */ $wgAntivirusSetup= array( #setup for clamav 'clamav' => array ( 'command' => "clamscan --no-summary ", 'codemap'=> array ( "0"=> AV_NO_VIRUS, #no virus "1"=> AV_VIRUS_FOUND, #virus found "52"=> AV_SCAN_ABORTED, #unsupported file format (probably imune) "*"=> AV_SCAN_FAILED, #else scan failed ), 'messagepattern'=> '/.*?:(.*)/sim', ), #setup for f-prot 'f-prot' => array ( 'command' => "f-prot ", 'codemap'=> array ( "0"=> AV_NO_VIRUS, #no virus "3"=> AV_VIRUS_FOUND, #virus found "6"=> AV_VIRUS_FOUND, #virus found "*"=> AV_SCAN_FAILED, #else scan failed ), 'messagepattern'=> '/.*?Infection:(.*)$/m', ), ); /** Determines if a failed virus scan (AV_SCAN_FAILED) will cause the file to be rejected. * @global boolean $wgAntivirusRequired */ $wgAntivirusRequired= true; /** Determines if the mime type of uploaded files should be checked * @global boolean $wgVerifyMimeType */ $wgVerifyMimeType= true; /** Sets the mime type definition file to use by MimeMagic.php. * @global string $wgMimeTypeFile */ $wgMimeTypeFile= "includes/mime.types"; #$wgMimeTypeFile= "/etc/mime.types"; #$wgMimeTypeFile= NULL; #use built-in defaults only. /** Sets the mime type info file to use by MimeMagic.php. * @global string $wgMimeInfoFile */ $wgMimeInfoFile= "includes/mime.info"; #$wgMimeInfoFile= NULL; #use built-in defaults only. /** Switch for loading the FileInfo extension by PECL at runtime. * This should be used only if fileinfo is installed as a shared object * or a dynamic libary * @global string $wgLoadFileinfoExtension */ $wgLoadFileinfoExtension= false; /** Sets an external mime detector program. The command must print only * the mime type to standard output. * The name of the file to process will be appended to the command given here. * If not set or NULL, mime_content_type will be used if available. */ $wgMimeDetectorCommand= NULL; # use internal mime_content_type function, available since php 4.3.0 #$wgMimeDetectorCommand= "file -bi"; #use external mime detector (Linux) /** Switch for trivial mime detection. Used by thumb.php to disable all fance * things, because only a few types of images are needed and file extensions * can be trusted. */ $wgTrivialMimeDetection= false; /** * To set 'pretty' URL paths for actions other than * plain page views, add to this array. For instance: * 'edit' => "$wgScriptPath/edit/$1" * * There must be an appropriate script or rewrite rule * in place to handle these URLs. */ $wgActionPaths = array(); /** * If you operate multiple wikis, you can define a shared upload path here. * Uploads to this wiki will NOT be put there - they will be put into * $wgUploadDirectory. * If $wgUseSharedUploads is set, the wiki will look in the shared repository if * no file of the given name is found in the local repository (for [[Image:..]], * [[Media:..]] links). Thumbnails will also be looked for and generated in this * directory. * * Note that these configuration settings can now be defined on a per- * repository basis for an arbitrary number of file repositories, using the * $wgForeignFileRepos variable. */ $wgUseSharedUploads = false; /** Full path on the web server where shared uploads can be found */ $wgSharedUploadPath = "http://commons.wikimedia.org/shared/images"; /** Fetch commons image description pages and display them on the local wiki? */ $wgFetchCommonsDescriptions = false; /** Path on the file system where shared uploads can be found. */ $wgSharedUploadDirectory = "/var/www/wiki3/images"; /** DB name with metadata about shared directory. Set this to false if the uploads do not come from a wiki. */ $wgSharedUploadDBname = false; /** Optional table prefix used in database. */ $wgSharedUploadDBprefix = ''; /** Cache shared metadata in memcached. Don't do this if the commons wiki is in a different memcached domain */ $wgCacheSharedUploads = true; /** Allow for upload to be copied from an URL. Requires Special:Upload?source=web */ $wgAllowCopyUploads = false; /** * Max size for uploads, in bytes. Currently only works for uploads from URL * via CURL (see $wgAllowCopyUploads). The only way to impose limits on * normal uploads is currently to edit php.ini. */ $wgMaxUploadSize = 1024*1024*100; # 100MB /** * Point the upload navigation link to an external URL * Useful if you want to use a shared repository by default * without disabling local uploads (use $wgEnableUploads = false for that) * e.g. $wgUploadNavigationUrl = 'http://commons.wikimedia.org/wiki/Special:Upload'; */ $wgUploadNavigationUrl = false; /** * Give a path here to use thumb.php for thumbnail generation on client request, instead of * generating them on render and outputting a static URL. This is necessary if some of your * apache servers don't have read/write access to the thumbnail path. * * Example: * $wgThumbnailScriptPath = "{$wgScriptPath}/thumb.php"; */ $wgThumbnailScriptPath = false; $wgSharedThumbnailScriptPath = false; /** * Set the following to false especially if you have a set of files that need to * be accessible by all wikis, and you do not want to use the hash (path/a/aa/) * directory layout. */ $wgHashedSharedUploadDirectory = true; /** * Base URL for a repository wiki. Leave this blank if uploads are just stored * in a shared directory and not meant to be accessible through a separate wiki. * Otherwise the image description pages on the local wiki will link to the * image description page on this wiki. * * Please specify the namespace, as in the example below. */ $wgRepositoryBaseUrl="http://commons.wikimedia.org/wiki/Image:"; # # Email settings # /** * Site admin email address * Default to wikiadmin@SERVER_NAME * @global string $wgEmergencyContact */ $wgEmergencyContact = 'wikiadmin@' . $wgServerName; /** * Password reminder email address * The address we should use as sender when a user is requesting his password * Default to apache@SERVER_NAME * @global string $wgPasswordSender */ $wgPasswordSender = 'MediaWiki Mail '; /** * dummy address which should be accepted during mail send action * It might be necessay to adapt the address or to set it equal * to the $wgEmergencyContact address */ #$wgNoReplyAddress = $wgEmergencyContact; $wgNoReplyAddress = 'reply@not.possible'; /** * Set to true to enable the e-mail basic features: * Password reminders, etc. If sending e-mail on your * server doesn't work, you might want to disable this. * @global bool $wgEnableEmail */ $wgEnableEmail = true; /** * Set to true to enable user-to-user e-mail. * This can potentially be abused, as it's hard to track. * @global bool $wgEnableUserEmail */ $wgEnableUserEmail = true; /** * Minimum time, in hours, which must elapse between password reminder * emails for a given account. This is to prevent abuse by mail flooding. */ $wgPasswordReminderResendTime = 24; /** * SMTP Mode * For using a direct (authenticated) SMTP server connection. * Default to false or fill an array : * * "host" => 'SMTP domain', * "IDHost" => 'domain for MessageID', * "port" => "25", * "auth" => true/false, * "username" => user, * "password" => password * * * @global mixed $wgSMTP */ $wgSMTP = false; /**#@+ * Database settings */ /** database host name or ip address */ $wgDBserver = 'localhost'; /** database port number */ $wgDBport = ''; /** name of the database */ $wgDBname = 'wikidb'; /** */ $wgDBconnection = ''; /** Database username */ $wgDBuser = 'wikiuser'; /** Database type */ $wgDBtype = "mysql"; /** Search type * Leave as null to select the default search engine for the * selected database type (eg SearchMySQL4), or set to a class * name to override to a custom search engine. */ $wgSearchType = null; /** Table name prefix */ $wgDBprefix = ''; /** MySQL table options to use during installation or update */ $wgDBTableOptions = 'TYPE=InnoDB'; /**#@-*/ /** Live high performance sites should disable this - some checks acquire giant mysql locks */ $wgCheckDBSchema = true; /** * Shared database for multiple wikis. Presently used for storing a user table * for single sign-on. The server for this database must be the same as for the * main database. * EXPERIMENTAL */ $wgSharedDB = null; # Database load balancer # This is a two-dimensional array, an array of server info structures # Fields are: # host: Host name # dbname: Default database name # user: DB user # password: DB password # type: "mysql" or "postgres" # load: ratio of DB_SLAVE load, must be >=0, the sum of all loads must be >0 # groupLoads: array of load ratios, the key is the query group name. A query may belong # to several groups, the most specific group defined here is used. # # flags: bit field # DBO_DEFAULT -- turns on DBO_TRX only if !$wgCommandLineMode (recommended) # DBO_DEBUG -- equivalent of $wgDebugDumpSql # DBO_TRX -- wrap entire request in a transaction # DBO_IGNORE -- ignore errors (not useful in LocalSettings.php) # DBO_NOBUFFER -- turn off buffering (not useful in LocalSettings.php) # # max lag: (optional) Maximum replication lag before a slave will taken out of rotation # max threads: (optional) Maximum number of running threads # # These and any other user-defined properties will be assigned to the mLBInfo member # variable of the Database object. # # Leave at false to use the single-server variables above $wgDBservers = false; /** How long to wait for a slave to catch up to the master */ $wgMasterWaitTimeout = 10; /** File to log database errors to */ $wgDBerrorLog = false; /** When to give an error message */ $wgDBClusterTimeout = 10; /** * wgDBminWordLen : * MySQL 3.x : used to discard words that MySQL will not return any results for * shorter values configure mysql directly. * MySQL 4.x : ignore it and configure mySQL * See: http://dev.mysql.com/doc/mysql/en/Fulltext_Fine-tuning.html */ $wgDBminWordLen = 4; /** Set to true if using InnoDB tables */ $wgDBtransactions = false; /** Set to true for compatibility with extensions that might be checking. * MySQL 3.23.x is no longer supported. */ $wgDBmysql4 = true; /** * Set to true to engage MySQL 4.1/5.0 charset-related features; * for now will just cause sending of 'SET NAMES=utf8' on connect. * * WARNING: THIS IS EXPERIMENTAL! * * May break if you're not using the table defs from mysql5/tables.sql. * May break if you're upgrading an existing wiki if set differently. * Broken symptoms likely to include incorrect behavior with page titles, * usernames, comments etc containing non-ASCII characters. * Might also cause failures on the object cache and other things. * * Even correct usage may cause failures with Unicode supplementary * characters (those not in the Basic Multilingual Plane) unless MySQL * has enhanced their Unicode support. */ $wgDBmysql5 = false; /** * Other wikis on this site, can be administered from a single developer * account. * Array numeric key => database name */ $wgLocalDatabases = array(); /** * Object cache settings * See Defines.php for types */ $wgMainCacheType = CACHE_NONE; $wgMessageCacheType = CACHE_ANYTHING; $wgParserCacheType = CACHE_ANYTHING; $wgParserCacheExpireTime = 86400; $wgSessionsInMemcached = false; $wgLinkCacheMemcached = false; # Not fully tested /** * Memcached-specific settings * See docs/memcached.txt */ $wgUseMemCached = false; $wgMemCachedDebug = false; # Will be set to false in Setup.php, if the server isn't working $wgMemCachedServers = array( '127.0.0.1:11000' ); $wgMemCachedDebug = false; $wgMemCachedPersistent = false; /** * Directory for local copy of message cache, for use in addition to memcached */ $wgLocalMessageCache = false; /** * Defines format of local cache * true - Serialized object * false - PHP source file (Warning - security risk) */ $wgLocalMessageCacheSerialized = true; /** * Directory for compiled constant message array databases * WARNING: turning anything on will just break things, aaaaaah!!!! */ $wgCachedMessageArrays = false; # Language settings # /** Site language code, should be one of ./languages/Language(.*).php */ $wgLanguageCode = 'en'; /** * Some languages need different word forms, usually for different cases. * Used in Language::convertGrammar(). */ $wgGrammarForms = array(); #$wgGrammarForms['en']['genitive']['car'] = 'car\'s'; /** Treat language links as magic connectors, not inline links */ $wgInterwikiMagic = true; /** Hide interlanguage links from the sidebar */ $wgHideInterlanguageLinks = false; /** We speak UTF-8 all the time now, unless some oddities happen */ $wgInputEncoding = 'UTF-8'; $wgOutputEncoding = 'UTF-8'; $wgEditEncoding = ''; # Set this to eg 'ISO-8859-1' to perform character set # conversion when loading old revisions not marked with # "utf-8" flag. Use this when converting wiki to UTF-8 # without the burdensome mass conversion of old text data. # # NOTE! This DOES NOT touch any fields other than old_text. # Titles, comments, user names, etc still must be converted # en masse in the database before continuing as a UTF-8 wiki. $wgLegacyEncoding = false; /** * If set to true, the MediaWiki 1.4 to 1.5 schema conversion will * create stub reference rows in the text table instead of copying * the full text of all current entries from 'cur' to 'text'. * * This will speed up the conversion step for large sites, but * requires that the cur table be kept around for those revisions * to remain viewable. * * maintenance/migrateCurStubs.php can be used to complete the * migration in the background once the wiki is back online. * * This option affects the updaters *only*. Any present cur stub * revisions will be readable at runtime regardless of this setting. */ $wgLegacySchemaConversion = false; $wgMimeType = 'text/html'; $wgJsMimeType = 'text/javascript'; $wgDocType = '-//W3C//DTD XHTML 1.0 Transitional//EN'; $wgDTD = 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'; $wgXhtmlDefaultNamespace = 'http://www.w3.org/1999/xhtml'; # Permit other namespaces in addition to the w3.org default. # Use the prefix for the key and the namespace for the value. For # example: # $wgXhtmlNamespaces['svg'] = 'http://www.w3.org/2000/svg'; # Normally we wouldn't have to define this in the root # element, but IE needs it there in some circumstances. $wgXhtmlNamespaces = array(); /** Enable to allow rewriting dates in page text. * DOES NOT FORMAT CORRECTLY FOR MOST LANGUAGES */ $wgUseDynamicDates = false; /** Enable dates like 'May 12' instead of '12 May', this only takes effect if * the interface is set to English */ $wgAmericanDates = false; /** * For Hindi and Arabic use local numerals instead of Western style (0-9) * numerals in interface. */ $wgTranslateNumerals = true; /** * Translation using MediaWiki: namespace. * This will increase load times by 25-60% unless memcached is installed. * Interface messages will be loaded from the database. */ $wgUseDatabaseMessages = true; /** * Expiry time for the message cache key */ $wgMsgCacheExpiry = 86400; /** * Maximum entry size in the message cache, in bytes */ $wgMaxMsgCacheEntrySize = 10000; # Whether to enable language variant conversion. $wgDisableLangConversion = false; # Default variant code, if false, the default will be the language code $wgDefaultLanguageVariant = false; /** * Show a bar of language selection links in the user login and user * registration forms; edit the "loginlanguagelinks" message to * customise these */ $wgLoginLanguageSelector = false; # Whether to use zhdaemon to perform Chinese text processing # zhdaemon is under developement, so normally you don't want to # use it unless for testing $wgUseZhdaemon = false; $wgZhdaemonHost="localhost"; $wgZhdaemonPort=2004; /** Normally you can ignore this and it will be something like $wgMetaNamespace . "_talk". In some languages, you may want to set this manually for grammatical reasons. It is currently only respected by those languages where it might be relevant and where no automatic grammar converter exists. */ $wgMetaNamespaceTalk = false; # Miscellaneous configuration settings # $wgLocalInterwiki = 'w'; $wgInterwikiExpiry = 10800; # Expiry time for cache of interwiki table /** Interwiki caching settings. $wgInterwikiCache specifies path to constant database file This cdb database is generated by dumpInterwiki from maintenance and has such key formats: dbname:key - a simple key (e.g. enwiki:meta) _sitename:key - site-scope key (e.g. wiktionary:meta) __global:key - global-scope key (e.g. __global:meta) __sites:dbname - site mapping (e.g. __sites:enwiki) Sites mapping just specifies site name, other keys provide "local url" data layout. $wgInterwikiScopes specify number of domains to check for messages: 1 - Just wiki(db)-level 2 - wiki and global levels 3 - site levels $wgInterwikiFallbackSite - if unable to resolve from cache */ $wgInterwikiCache = false; $wgInterwikiScopes = 3; $wgInterwikiFallbackSite = 'wiki'; /** * If local interwikis are set up which allow redirects, * set this regexp to restrict URLs which will be displayed * as 'redirected from' links. * * It might look something like this: * $wgRedirectSources = '!^https?://[a-z-]+\.wikipedia\.org/!'; * * Leave at false to avoid displaying any incoming redirect markers. * This does not affect intra-wiki redirects, which don't change * the URL. */ $wgRedirectSources = false; $wgShowIPinHeader = true; # For non-logged in users $wgMaxNameChars = 255; # Maximum number of bytes in username $wgMaxArticleSize = 2048; # Maximum article size in kilobytes $wgExtraSubtitle = ''; $wgSiteSupportPage = ''; # A page where you users can receive donations /*** * If this lock file exists, the wiki will be forced into read-only mode. * Its contents will be shown to users as part of the read-only warning * message. */ $wgReadOnlyFile = false; /// defaults to "{$wgUploadDirectory}/lock_yBgMBwiR"; /** * The debug log file should be not be publicly accessible if it is used, as it * may contain private data. */ $wgDebugLogFile = ''; /**#@+ * @global bool */ $wgDebugRedirects = false; $wgDebugRawPage = false; # Avoid overlapping debug entries by leaving out CSS $wgDebugComments = false; $wgReadOnly = null; $wgLogQueries = false; /** * Write SQL queries to the debug log */ $wgDebugDumpSql = false; /** * Set to an array of log group keys to filenames. * If set, wfDebugLog() output for that group will go to that file instead * of the regular $wgDebugLogFile. Useful for enabling selective logging * in production. */ $wgDebugLogGroups = array(); /** * Whether to show "we're sorry, but there has been a database error" pages. * Displaying errors aids in debugging, but may display information useful * to an attacker. */ $wgShowSQLErrors = false; /** * If true, some error messages will be colorized when running scripts on the * command line; this can aid picking important things out when debugging. * Ignored when running on Windows or when output is redirected to a file. */ $wgColorErrors = true; /** * If set to true, uncaught exceptions will print a complete stack trace * to output. This should only be used for debugging, as it may reveal * private information in function parameters due to PHP's backtrace * formatting. */ $wgShowExceptionDetails = false; /** * disable experimental dmoz-like category browsing. Output things like: * Encyclopedia > Music > Style of Music > Jazz */ $wgUseCategoryBrowser = false; /** * Keep parsed pages in a cache (objectcache table, turck, or memcached) * to speed up output of the same page viewed by another user with the * same options. * * This can provide a significant speedup for medium to large pages, * so you probably want to keep it on. */ $wgEnableParserCache = true; /** * If on, the sidebar navigation links are cached for users with the * current language set. This can save a touch of load on a busy site * by shaving off extra message lookups. * * However it is also fragile: changing the site configuration, or * having a variable $wgArticlePath, can produce broken links that * don't update as expected. */ $wgEnableSidebarCache = false; /** * Under which condition should a page in the main namespace be counted * as a valid article? If $wgUseCommaCount is set to true, it will be * counted if it contains at least one comma. If it is set to false * (default), it will only be counted if it contains at least one [[wiki * link]]. See http://meta.wikimedia.org/wiki/Help:Article_count * * Retroactively changing this variable will not affect * the existing count (cf. maintenance/recount.sql). */ $wgUseCommaCount = false; /**#@-*/ /** * wgHitcounterUpdateFreq sets how often page counters should be updated, higher * values are easier on the database. A value of 1 causes the counters to be * updated on every hit, any higher value n cause them to update *on average* * every n hits. Should be set to either 1 or something largish, eg 1000, for * maximum efficiency. */ $wgHitcounterUpdateFreq = 1; # Basic user rights and block settings $wgSysopUserBans = true; # Allow sysops to ban logged-in users $wgSysopRangeBans = true; # Allow sysops to ban IP ranges $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire $wgBlockAllowsUTEdit = false; # Blocks allow users to edit their own user talk page # Pages anonymous user may see as an array, e.g.: # array ( "Main Page", "Special:Userlogin", "Wikipedia:Help"); # NOTE: This will only work if $wgGroupPermissions['*']['read'] # is false -- see below. Otherwise, ALL pages are accessible, # regardless of this setting. # Also note that this will only protect _pages in the wiki_. # Uploaded files will remain readable. Make your upload # directory name unguessable, or use .htaccess to protect it. $wgWhitelistRead = false; /** * Should editors be required to have a validated e-mail * address before being allowed to edit? */ $wgEmailConfirmToEdit=false; /** * Permission keys given to users in each group. * All users are implicitly in the '*' group including anonymous visitors; * logged-in users are all implicitly in the 'user' group. These will be * combined with the permissions of all groups that a given user is listed * in in the user_groups table. * * Functionality to make pages inaccessible has not been extensively tested * for security. Use at your own risk! * * This replaces wgWhitelistAccount and wgWhitelistEdit */ $wgGroupPermissions = array(); // Implicit group for all visitors $wgGroupPermissions['*' ]['createaccount'] = true; $wgGroupPermissions['*' ]['read'] = true; $wgGroupPermissions['*' ]['edit'] = true; $wgGroupPermissions['*' ]['createpage'] = true; $wgGroupPermissions['*' ]['createtalk'] = true; // Implicit group for all logged-in accounts $wgGroupPermissions['user' ]['move'] = true; $wgGroupPermissions['user' ]['read'] = true; $wgGroupPermissions['user' ]['edit'] = true; $wgGroupPermissions['user' ]['createpage'] = true; $wgGroupPermissions['user' ]['createtalk'] = true; $wgGroupPermissions['user' ]['upload'] = true; $wgGroupPermissions['user' ]['reupload'] = true; $wgGroupPermissions['user' ]['reupload-shared'] = true; $wgGroupPermissions['user' ]['minoredit'] = true; $wgGroupPermissions['user' ]['purge'] = true; // can use ?action=purge without clicking "ok" // Implicit group for accounts that pass $wgAutoConfirmAge $wgGroupPermissions['autoconfirmed']['autoconfirmed'] = true; // Implicit group for accounts with confirmed email addresses // This has little use when email address confirmation is off $wgGroupPermissions['emailconfirmed']['emailconfirmed'] = true; // Users with bot privilege can have their edits hidden // from various log pages by default $wgGroupPermissions['bot' ]['bot'] = true; $wgGroupPermissions['bot' ]['autoconfirmed'] = true; $wgGroupPermissions['bot' ]['nominornewtalk'] = true; $wgGroupPermissions['bot' ]['autopatrol'] = true; // Most extra permission abilities go to this group $wgGroupPermissions['sysop']['block'] = true; $wgGroupPermissions['sysop']['createaccount'] = true; $wgGroupPermissions['sysop']['delete'] = true; $wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text $wgGroupPermissions['sysop']['editinterface'] = true; $wgGroupPermissions['sysop']['import'] = true; $wgGroupPermissions['sysop']['importupload'] = true; $wgGroupPermissions['sysop']['move'] = true; $wgGroupPermissions['sysop']['patrol'] = true; $wgGroupPermissions['sysop']['autopatrol'] = true; $wgGroupPermissions['sysop']['protect'] = true; $wgGroupPermissions['sysop']['proxyunbannable'] = true; $wgGroupPermissions['sysop']['rollback'] = true; $wgGroupPermissions['sysop']['trackback'] = true; $wgGroupPermissions['sysop']['upload'] = true; $wgGroupPermissions['sysop']['reupload'] = true; $wgGroupPermissions['sysop']['reupload-shared'] = true; $wgGroupPermissions['sysop']['unwatchedpages'] = true; $wgGroupPermissions['sysop']['autoconfirmed'] = true; $wgGroupPermissions['sysop']['upload_by_url'] = true; $wgGroupPermissions['sysop']['ipblock-exempt'] = true; // Permission to change users' group assignments $wgGroupPermissions['bureaucrat']['userrights'] = true; // Experimental permissions, not ready for production use //$wgGroupPermissions['sysop']['deleterevision'] = true; //$wgGroupPermissions['bureaucrat']['hiderevision'] = true; /** * The developer group is deprecated, but can be activated if need be * to use the 'lockdb' and 'unlockdb' special pages. Those require * that a lock file be defined and creatable/removable by the web * server. */ # $wgGroupPermissions['developer']['siteadmin'] = true; /** * Set of available actions that can be restricted via action=protect * You probably shouldn't change this. * Translated trough restriction-* messages. */ $wgRestrictionTypes = array( 'edit', 'move' ); /** * Set of permission keys that can be selected via action=protect. * 'autoconfirm' allows all registerd users if $wgAutoConfirmAge is 0. */ $wgRestrictionLevels = array( '', 'autoconfirmed', 'sysop' ); /** * Set the minimum permissions required to edit pages in each * namespace. If you list more than one permission, a user must * have all of them to edit pages in that namespace. */ $wgNamespaceProtection = array(); $wgNamespaceProtection[ NS_MEDIAWIKI ] = array( 'editinterface' ); /** * Pages in namespaces in this array can not be used as templates. * Elements must be numeric namespace ids. * Among other things, this may be useful to enforce read-restrictions * which may otherwise be bypassed by using the template machanism. */ $wgNonincludableNamespaces = array(); /** * Number of seconds an account is required to age before * it's given the implicit 'autoconfirm' group membership. * This can be used to limit privileges of new accounts. * * Accounts created by earlier versions of the software * may not have a recorded creation date, and will always * be considered to pass the age test. * * When left at 0, all registered accounts will pass. */ $wgAutoConfirmAge = 0; //$wgAutoConfirmAge = 600; // ten minutes //$wgAutoConfirmAge = 3600*24; // one day # Number of edits an account requires before it is autoconfirmed # Passing both this AND the time requirement is needed $wgAutoConfirmCount = 0; //$wgAutoConfirmCount = 50; # Proxy scanner settings # /** * If you enable this, every editor's IP address will be scanned for open HTTP * proxies. * * Don't enable this. Many sysops will report "hostile TCP port scans" to your * ISP and ask for your server to be shut down. * * You have been warned. */ $wgBlockOpenProxies = false; /** Port we want to scan for a proxy */ $wgProxyPorts = array( 80, 81, 1080, 3128, 6588, 8000, 8080, 8888, 65506 ); /** Script used to scan */ $wgProxyScriptPath = "$IP/includes/proxy_check.php"; /** */ $wgProxyMemcExpiry = 86400; /** This should always be customised in LocalSettings.php */ $wgSecretKey = false; /** big list of banned IP addresses, in the keys not the values */ $wgProxyList = array(); /** deprecated */ $wgProxyKey = false; /** Number of accounts each IP address may create, 0 to disable. * Requires memcached */ $wgAccountCreationThrottle = 0; # Client-side caching: /** Allow client-side caching of pages */ $wgCachePages = true; /** * Set this to current time to invalidate all prior cached pages. Affects both * client- and server-side caching. * You can get the current date on your server by using the command: * date +%Y%m%d%H%M%S */ $wgCacheEpoch = '20030516000000'; /** * Bump this number when changing the global style sheets and JavaScript. * It should be appended in the query string of static CSS and JS includes, * to ensure that client-side caches don't keep obsolete copies of global * styles. */ $wgStyleVersion = '73'; # Server-side caching: /** * This will cache static pages for non-logged-in users to reduce * database traffic on public sites. * Must set $wgShowIPinHeader = false */ $wgUseFileCache = false; /** Directory where the cached page will be saved */ $wgFileCacheDirectory = false; /// defaults to "{$wgUploadDirectory}/cache"; /** * When using the file cache, we can store the cached HTML gzipped to save disk * space. Pages will then also be served compressed to clients that support it. * THIS IS NOT COMPATIBLE with ob_gzhandler which is now enabled if supported in * the default LocalSettings.php! If you enable this, remove that setting first. * * Requires zlib support enabled in PHP. */ $wgUseGzip = false; /** Whether MediaWiki should send an ETag header */ $wgUseETag = false; # Email notification settings # /** For email notification on page changes */ $wgPasswordSender = $wgEmergencyContact; # true: from page editor if s/he opted-in # false: Enotif mails appear to come from $wgEmergencyContact $wgEnotifFromEditor = false; // TODO move UPO to preferences probably ? # If set to true, users get a corresponding option in their preferences and can choose to enable or disable at their discretion # If set to false, the corresponding input form on the user preference page is suppressed # It call this to be a "user-preferences-option (UPO)" $wgEmailAuthentication = true; # UPO (if this is set to false, texts referring to authentication are suppressed) $wgEnotifWatchlist = false; # UPO $wgEnotifUserTalk = false; # UPO $wgEnotifRevealEditorAddress = false; # UPO; reply-to address may be filled with page editor's address (if user allowed this in the preferences) $wgEnotifMinorEdits = true; # UPO; false: "minor edits" on pages do not trigger notification mails. # # Attention: _every_ change on a user_talk page trigger a notification mail (if the user is not yet notified) # Send a generic mail instead of a personalised mail for each user. This # always uses UTC as the time zone, and doesn't include the username. # # For pages with many users watching, this can significantly reduce mail load. # Has no effect when using sendmail rather than SMTP; $wgEnotifImpersonal = false; # Maximum number of users to mail at once when using impersonal mail. Should # match the limit on your mail server. $wgEnotifMaxRecips = 500; # Send mails via the job queue. $wgEnotifUseJobQ = false; /** * Array of usernames who will be sent a notification email for every change which occurs on a wiki */ $wgUsersNotifedOnAllChanges = array(); /** Show watching users in recent changes, watchlist and page history views */ $wgRCShowWatchingUsers = false; # UPO /** Show watching users in Page views */ $wgPageShowWatchingUsers = false; /** Show the amount of changed characters in recent changes */ $wgRCShowChangedSize = true; /** * If the difference between the character counts of the text * before and after the edit is below that value, the value will be * highlighted on the RC page. */ $wgRCChangedSizeThreshold = -500; /** * Show "Updated (since my last visit)" marker in RC view, watchlist and history * view for watched pages with new changes */ $wgShowUpdatedMarker = true; $wgCookieExpiration = 2592000; /** Clock skew or the one-second resolution of time() can occasionally cause cache * problems when the user requests two pages within a short period of time. This * variable adds a given number of seconds to vulnerable timestamps, thereby giving * a grace period. */ $wgClockSkewFudge = 5; # Squid-related settings # /** Enable/disable Squid */ $wgUseSquid = false; /** If you run Squid3 with ESI support, enable this (default:false): */ $wgUseESI = false; /** Internal server name as known to Squid, if different */ # $wgInternalServer = 'http://yourinternal.tld:8000'; $wgInternalServer = $wgServer; /** * Cache timeout for the squid, will be sent as s-maxage (without ESI) or * Surrogate-Control (with ESI). Without ESI, you should strip out s-maxage in * the Squid config. 18000 seconds = 5 hours, more cache hits with 2678400 = 31 * days */ $wgSquidMaxage = 18000; /** * A list of proxy servers (ips if possible) to purge on changes don't specify * ports here (80 is default). When mediawiki is running behind a proxy, its * address should be listed in $wgSquidServers otherwise mediawiki won't rely * on the X-FORWARDED-FOR header to determine the user IP address and * all users will appear to come from the proxy IP address. Don't use domain * names here, only IP adresses. */ # $wgSquidServers = array('127.0.0.1'); $wgSquidServers = array(); $wgSquidServersNoPurge = array(); /** Maximum number of titles to purge in any one client operation */ $wgMaxSquidPurgeTitles = 400; /** HTCP multicast purging */ $wgHTCPPort = 4827; $wgHTCPMulticastTTL = 1; # $wgHTCPMulticastAddress = "224.0.0.85"; $wgHTCPMulticastAddress = false; # Cookie settings: # /** * Set to set an explicit domain on the login cookies eg, "justthis.domain. org" * or ".any.subdomain.net" */ $wgCookieDomain = ''; $wgCookiePath = '/'; $wgCookieSecure = ($wgProto == 'https'); $wgDisableCookieCheck = false; /** Override to customise the session name */ $wgSessionName = false; /** Whether to allow inline image pointing to other websites */ $wgAllowExternalImages = false; /** If the above is false, you can specify an exception here. Image URLs * that start with this string are then rendered, while all others are not. * You can use this to set up a trusted, simple repository of images. * * Example: * $wgAllowExternalImagesFrom = 'http://127.0.0.1/'; */ $wgAllowExternalImagesFrom = ''; /** Disable database-intensive features */ $wgMiserMode = false; /** Disable all query pages if miser mode is on, not just some */ $wgDisableQueryPages = false; /** Number of rows to cache in 'querycache' table when miser mode is on */ $wgQueryCacheLimit = 1000; /** Number of links to a page required before it is deemed "wanted" */ $wgWantedPagesThreshold = 1; /** Enable slow parser functions */ $wgAllowSlowParserFunctions = false; /** * To use inline TeX, you need to compile 'texvc' (in the 'math' subdirectory of * the MediaWiki package and have latex, dvips, gs (ghostscript), andconvert * (ImageMagick) installed and available in the PATH. * Please see math/README for more information. */ $wgUseTeX = false; /** Location of the texvc binary */ $wgTexvc = './math/texvc'; # # Profiling / debugging # # You have to create a 'profiling' table in your database before using # profiling see maintenance/archives/patch-profiling.sql . # # To enable profiling, edit StartProfiler.php /** Only record profiling info for pages that took longer than this */ $wgProfileLimit = 0.0; /** Don't put non-profiling info into log file */ $wgProfileOnly = false; /** Log sums from profiling into "profiling" table in db. */ $wgProfileToDatabase = false; /** If true, print a raw call tree instead of per-function report */ $wgProfileCallTree = false; /** Should application server host be put into profiling table */ $wgProfilePerHost = false; /** Settings for UDP profiler */ $wgUDPProfilerHost = '127.0.0.1'; $wgUDPProfilerPort = '3811'; /** Detects non-matching wfProfileIn/wfProfileOut calls */ $wgDebugProfiling = false; /** Output debug message on every wfProfileIn/wfProfileOut */ $wgDebugFunctionEntry = 0; /** Lots of debugging output from SquidUpdate.php */ $wgDebugSquid = false; /** Whereas to count the number of time an article is viewed. * Does not work if pages are cached (for example with squid). */ $wgDisableCounters = false; $wgDisableTextSearch = false; $wgDisableSearchContext = false; /** * If you've disabled search semi-permanently, this also disables updates to the * table. If you ever re-enable, be sure to rebuild the search table. */ $wgDisableSearchUpdate = false; /** Uploads have to be specially set up to be secure */ $wgEnableUploads = false; /** * Show EXIF data, on by default if available. * Requires PHP's EXIF extension: http://www.php.net/manual/en/ref.exif.php * * NOTE FOR WINDOWS USERS: * To enable EXIF functions, add the folloing lines to the * "Windows extensions" section of php.ini: * * extension=extensions/php_mbstring.dll * extension=extensions/php_exif.dll */ $wgShowEXIF = function_exists( 'exif_read_data' ); /** * Set to true to enable the upload _link_ while local uploads are disabled. * Assumes that the special page link will be bounced to another server where * uploads do work. */ $wgRemoteUploads = false; $wgDisableAnonTalk = false; /** * Do DELETE/INSERT for link updates instead of incremental */ $wgUseDumbLinkUpdate = false; /** * Anti-lock flags - bitfield * ALF_PRELOAD_LINKS * Preload links during link update for save * ALF_PRELOAD_EXISTENCE * Preload cur_id during replaceLinkHolders * ALF_NO_LINK_LOCK * Don't use locking reads when updating the link table. This is * necessary for wikis with a high edit rate for performance * reasons, but may cause link table inconsistency * ALF_NO_BLOCK_LOCK * As for ALF_LINK_LOCK, this flag is a necessity for high-traffic * wikis. */ $wgAntiLockFlags = 0; /** * Path to the GNU diff3 utility. If the file doesn't exist, edit conflicts will * fall back to the old behaviour (no merging). */ $wgDiff3 = '/usr/bin/diff3'; /** * We can also compress text in the old revisions table. If this is set on, old * revisions will be compressed on page save if zlib support is available. Any * compressed revisions will be decompressed on load regardless of this setting * *but will not be readable at all* if zlib support is not available. */ $wgCompressRevisions = false; /** * This is the list of preferred extensions for uploading files. Uploading files * with extensions not in this list will trigger a warning. */ $wgFileExtensions = array( 'png', 'gif', 'jpg', 'jpeg' ); /** Files with these extensions will never be allowed as uploads. */ $wgFileBlacklist = array( # HTML may contain cookie-stealing JavaScript and web bugs 'html', 'htm', 'js', 'jsb', # PHP scripts may execute arbitrary code on the server 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', # Other types that may be interpreted by some servers 'shtml', 'jhtml', 'pl', 'py', 'cgi', # May contain harmful executables for Windows victims 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl' ); /** Files with these mime types will never be allowed as uploads * if $wgVerifyMimeType is enabled. */ $wgMimeTypeBlacklist= array( # HTML may contain cookie-stealing JavaScript and web bugs 'text/html', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', # PHP scripts may execute arbitrary code on the server 'application/x-php', 'text/x-php', # Other types that may be interpreted by some servers 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', # Windows metafile, client-side vulnerability on some systems 'application/x-msmetafile' ); /** This is a flag to determine whether or not to check file extensions on upload. */ $wgCheckFileExtensions = true; /** * If this is turned off, users may override the warning for files not covered * by $wgFileExtensions. */ $wgStrictFileExtensions = true; /** Warn if uploaded files are larger than this (in bytes)*/ $wgUploadSizeWarning = 150 * 1024; /** For compatibility with old installations set to false */ $wgPasswordSalt = true; /** Which namespaces should support subpages? * See Language.php for a list of namespaces. */ $wgNamespacesWithSubpages = array( NS_TALK => true, NS_USER => true, NS_USER_TALK => true, NS_PROJECT_TALK => true, NS_IMAGE_TALK => true, NS_MEDIAWIKI_TALK => true, NS_TEMPLATE_TALK => true, NS_HELP_TALK => true, NS_CATEGORY_TALK => true ); $wgNamespacesToBeSearchedDefault = array( NS_MAIN => true, ); /** If set, a bold ugly notice will show up at the top of every page. */ $wgSiteNotice = ''; # # Images settings # /** * Plugins for media file type handling. * Each entry in the array maps a MIME type to a class name */ $wgMediaHandlers = array( 'image/jpeg' => 'BitmapHandler', 'image/png' => 'BitmapHandler', 'image/gif' => 'BitmapHandler', 'image/x-ms-bmp' => 'BmpHandler', 'image/svg+xml' => 'SvgHandler', 'image/vnd.djvu' => 'DjVuHandler', ); /** * Resizing can be done using PHP's internal image libraries or using * ImageMagick or another third-party converter, e.g. GraphicMagick. * These support more file formats than PHP, which only supports PNG, * GIF, JPG, XBM and WBMP. * * Use Image Magick instead of PHP builtin functions. */ $wgUseImageMagick = false; /** The convert command shipped with ImageMagick */ $wgImageMagickConvertCommand = '/usr/bin/convert'; /** Sharpening parameter to ImageMagick */ $wgSharpenParameter = '0x0.4'; /** Reduction in linear dimensions below which sharpening will be enabled */ $wgSharpenReductionThreshold = 0.85; /** * Use another resizing converter, e.g. GraphicMagick * %s will be replaced with the source path, %d with the destination * %w and %h will be replaced with the width and height * * An example is provided for GraphicMagick * Leave as false to skip this */ #$wgCustomConvertCommand = "gm convert %s -resize %wx%h %d" $wgCustomConvertCommand = false; # Scalable Vector Graphics (SVG) may be uploaded as images. # Since SVG support is not yet standard in browsers, it is # necessary to rasterize SVGs to PNG as a fallback format. # # An external program is required to perform this conversion: $wgSVGConverters = array( 'ImageMagick' => '$path/convert -background white -geometry $width $input PNG:$output', 'sodipodi' => '$path/sodipodi -z -w $width -f $input -e $output', 'inkscape' => '$path/inkscape -z -w $width -f $input -e $output', 'batik' => 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg' => '$path/rsvg -w$width -h$height $input $output', ); /** Pick one of the above */ $wgSVGConverter = 'ImageMagick'; /** If not in the executable PATH, specify */ $wgSVGConverterPath = ''; /** Don't scale a SVG larger than this */ $wgSVGMaxSize = 1024; /** * Don't thumbnail an image if it will use too much working memory * Default is 50 MB if decompressed to RGBA form, which corresponds to * 12.5 million pixels or 3500x3500 */ $wgMaxImageArea = 1.25e7; /** * If rendered thumbnail files are older than this timestamp, they * will be rerendered on demand as if the file didn't already exist. * Update if there is some need to force thumbs and SVG rasterizations * to rerender, such as fixes to rendering bugs. */ $wgThumbnailEpoch = '20030516000000'; /** * If set, inline scaled images will still produce tags ready for * output instead of showing an error message. * * This may be useful if errors are transitory, especially if the site * is configured to automatically render thumbnails on request. * * On the other hand, it may obscure error conditions from debugging. * Enable the debug log or the 'thumbnail' log group to make sure errors * are logged to a file for review. */ $wgIgnoreImageErrors = false; /** * Allow thumbnail rendering on page view. If this is false, a valid * thumbnail URL is still output, but no file will be created at * the target location. This may save some time if you have a * thumb.php or 404 handler set up which is faster than the regular * webserver(s). */ $wgGenerateThumbnailOnParse = true; /** Obsolete, always true, kept for compatibility with extensions */ $wgUseImageResize = true; /** Set $wgCommandLineMode if it's not set already, to avoid notices */ if( !isset( $wgCommandLineMode ) ) { $wgCommandLineMode = false; } /** For colorized maintenance script output, is your terminal background dark ? */ $wgCommandLineDarkBg = false; # # Recent changes settings # /** Log IP addresses in the recentchanges table; can be accessed only by extensions (e.g. CheckUser) or a DB admin */ $wgPutIPinRC = true; /** * Recentchanges items are periodically purged; entries older than this many * seconds will go. * For one week : 7 * 24 * 3600 */ $wgRCMaxAge = 7 * 24 * 3600; # Send RC updates via UDP $wgRC2UDPAddress = false; $wgRC2UDPPort = false; $wgRC2UDPPrefix = ''; # # Copyright and credits settings # /** RDF metadata toggles */ $wgEnableDublinCoreRdf = false; $wgEnableCreativeCommonsRdf = false; /** Override for copyright metadata. * TODO: these options need documentation */ $wgRightsPage = NULL; $wgRightsUrl = NULL; $wgRightsText = NULL; $wgRightsIcon = NULL; /** Set this to some HTML to override the rights icon with an arbitrary logo */ $wgCopyrightIcon = NULL; /** Set this to true if you want detailed copyright information forms on Upload. */ $wgUseCopyrightUpload = false; /** Set this to false if you want to disable checking that detailed copyright * information values are not empty. */ $wgCheckCopyrightUpload = true; /** * Set this to the number of authors that you want to be credited below an * article text. Set it to zero to hide the attribution block, and a negative * number (like -1) to show all authors. Note that this will require 2-3 extra * database hits, which can have a not insignificant impact on performance for * large wikis. */ $wgMaxCredits = 0; /** If there are more than $wgMaxCredits authors, show $wgMaxCredits of them. * Otherwise, link to a separate credits page. */ $wgShowCreditsIfMax = true; /** * Set this to false to avoid forcing the first letter of links to capitals. * WARNING: may break links! This makes links COMPLETELY case-sensitive. Links * appearing with a capital at the beginning of a sentence will *not* go to the * same place as links in the middle of a sentence using a lowercase initial. */ $wgCapitalLinks = true; /** * List of interwiki prefixes for wikis we'll accept as sources for * Special:Import (for sysops). Since complete page history can be imported, * these should be 'trusted'. * * If a user has the 'import' permission but not the 'importupload' permission, * they will only be able to run imports through this transwiki interface. */ $wgImportSources = array(); /** * Optional default target namespace for interwiki imports. * Can use this to create an incoming "transwiki"-style queue. * Set to numeric key, not the name. * * Users may override this in the Special:Import dialog. */ $wgImportTargetNamespace = null; /** * If set to false, disables the full-history option on Special:Export. * This is currently poorly optimized for long edit histories, so is * disabled on Wikimedia's sites. */ $wgExportAllowHistory = true; /** * If set nonzero, Special:Export requests for history of pages with * more revisions than this will be rejected. On some big sites things * could get bogged down by very very long pages. */ $wgExportMaxHistory = 0; $wgExportAllowListContributors = false ; /** Text matching this regular expression will be recognised as spam * See http://en.wikipedia.org/wiki/Regular_expression */ $wgSpamRegex = false; /** Similarly you can get a function to do the job. The function will be given * the following args: * - a Title object for the article the edit is made on * - the text submitted in the textarea (wpTextbox1) * - the section number. * The return should be boolean indicating whether the edit matched some evilness: * - true : block it * - false : let it through * * For a complete example, have a look at the SpamBlacklist extension. */ $wgFilterCallback = false; /** Go button goes straight to the edit screen if the article doesn't exist. */ $wgGoToEdit = false; /** Allow raw, unchecked HTML in ... sections. * THIS IS VERY DANGEROUS on a publically editable site, so USE wgGroupPermissions * TO RESTRICT EDITING to only those that you trust */ $wgRawHtml = false; /** * $wgUseTidy: use tidy to make sure HTML output is sane. * Tidy is a free tool that fixes broken HTML. * See http://www.w3.org/People/Raggett/tidy/ * $wgTidyBin should be set to the path of the binary and * $wgTidyConf to the path of the configuration file. * $wgTidyOpts can include any number of parameters. * * $wgTidyInternal controls the use of the PECL extension to use an in- * process tidy library instead of spawning a separate program. * Normally you shouldn't need to override the setting except for * debugging. To install, use 'pear install tidy' and add a line * 'extension=tidy.so' to php.ini. */ $wgUseTidy = false; $wgAlwaysUseTidy = false; $wgTidyBin = 'tidy'; $wgTidyConf = $IP.'/includes/tidy.conf'; $wgTidyOpts = ''; $wgTidyInternal = function_exists( 'tidy_load_config' ); /** See list of skins and their symbolic names in languages/Language.php */ $wgDefaultSkin = 'monobook'; /** * Settings added to this array will override the default globals for the user * preferences used by anonymous visitors and newly created accounts. * For instance, to disable section editing links: * $wgDefaultUserOptions ['editsection'] = 0; * */ $wgDefaultUserOptions = array( 'quickbar' => 1, 'underline' => 2, 'cols' => 80, 'rows' => 25, 'searchlimit' => 20, 'contextlines' => 5, 'contextchars' => 50, 'skin' => false, 'math' => 1, 'rcdays' => 7, 'rclimit' => 50, 'wllimit' => 250, 'highlightbroken' => 1, 'stubthreshold' => 0, 'previewontop' => 1, 'editsection' => 1, 'editsectiononrightclick'=> 0, 'showtoc' => 1, 'showtoolbar' => 1, 'date' => 'default', 'imagesize' => 2, 'thumbsize' => 2, 'rememberpassword' => 0, 'enotifwatchlistpages' => 0, 'enotifusertalkpages' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'shownumberswatching' => 1, 'fancysig' => 0, 'externaleditor' => 0, 'externaldiff' => 0, 'showjumplinks' => 1, 'numberheadings' => 0, 'uselivepreview' => 0, 'watchlistdays' => 3.0, ); /** Whether or not to allow and use real name fields. Defaults to true. */ $wgAllowRealName = true; /***************************************************************************** * Extensions */ /** * A list of callback functions which are called once MediaWiki is fully initialised */ $wgExtensionFunctions = array(); /** * Extension functions for initialisation of skins. This is called somewhat earlier * than $wgExtensionFunctions. */ $wgSkinExtensionFunctions = array(); /** * List of valid skin names. * The key should be the name in all lower case, the value should be a display name. * The default skins will be added later, by Skin::getSkinNames(). Use * Skin::getSkinNames() as an accessor if you wish to have access to the full list. */ $wgValidSkinNames = array(); /** * Special page list. * See the top of SpecialPage.php for documentation. */ $wgSpecialPages = array(); /** * Array mapping class names to filenames, for autoloading. */ $wgAutoloadClasses = array(); /** * An array of extension types and inside that their names, versions, authors * and urls, note that the version and url key can be omitted. * * * $wgExtensionCredits[$type][] = array( * 'name' => 'Example extension', * 'version' => 1.9, * 'author' => 'Foo Barstein', * 'url' => 'http://wwww.example.com/Example%20Extension/', * ); * * * Where $type is 'specialpage', 'parserhook', or 'other'. */ $wgExtensionCredits = array(); /* * end extensions ******************************************************************************/ /** * Allow user Javascript page? * This enables a lot of neat customizations, but may * increase security risk to users and server load. */ $wgAllowUserJs = false; /** * Allow user Cascading Style Sheets (CSS)? * This enables a lot of neat customizations, but may * increase security risk to users and server load. */ $wgAllowUserCss = false; /** Use the site's Javascript page? */ $wgUseSiteJs = true; /** Use the site's Cascading Style Sheets (CSS)? */ $wgUseSiteCss = true; /** Filter for Special:Randompage. Part of a WHERE clause */ $wgExtraRandompageSQL = false; /** Allow the "info" action, very inefficient at the moment */ $wgAllowPageInfo = false; /** Maximum indent level of toc. */ $wgMaxTocLevel = 999; /** Name of the external diff engine to use */ $wgExternalDiffEngine = false; /** Use RC Patrolling to check for vandalism */ $wgUseRCPatrol = true; /** Set maximum number of results to return in syndication feeds (RSS, Atom) for * eg Recentchanges, Newpages. */ $wgFeedLimit = 50; /** _Minimum_ timeout for cached Recentchanges feed, in seconds. * A cached version will continue to be served out even if changes * are made, until this many seconds runs out since the last render. * * If set to 0, feed caching is disabled. Use this for debugging only; * feed generation can be pretty slow with diffs. */ $wgFeedCacheTimeout = 60; /** When generating Recentchanges RSS/Atom feed, diffs will not be generated for * pages larger than this size. */ $wgFeedDiffCutoff = 32768; /** * Additional namespaces. If the namespaces defined in Language.php and * Namespace.php are insufficient, you can create new ones here, for example, * to import Help files in other languages. * PLEASE NOTE: Once you delete a namespace, the pages in that namespace will * no longer be accessible. If you rename it, then you can access them through * the new namespace name. * * Custom namespaces should start at 100 to avoid conflicting with standard * namespaces, and should always follow the even/odd main/talk pattern. */ #$wgExtraNamespaces = # array(100 => "Hilfe", # 101 => "Hilfe_Diskussion", # 102 => "Aide", # 103 => "Discussion_Aide" # ); $wgExtraNamespaces = NULL; /** * Namespace aliases * These are alternate names for the primary localised namespace names, which * are defined by $wgExtraNamespaces and the language file. If a page is * requested with such a prefix, the request will be redirected to the primary * name. * * Set this to a map from namespace names to IDs. * Example: * $wgNamespaceAliases = array( * 'Wikipedian' => NS_USER, * 'Help' => 100, * ); */ $wgNamespaceAliases = array(); /** * Limit images on image description pages to a user-selectable limit. In order * to reduce disk usage, limits can only be selected from a list. * The user preference is saved as an array offset in the database, by default * the offset is set with $wgDefaultUserOptions['imagesize']. Make sure you * change it if you alter the array (see bug 8858). * This is the list of settings the user can choose from: */ $wgImageLimits = array ( array(320,240), array(640,480), array(800,600), array(1024,768), array(1280,1024), array(10000,10000) ); /** * Adjust thumbnails on image pages according to a user setting. In order to * reduce disk usage, the values can only be selected from a list. This is the * list of settings the user can choose from: */ $wgThumbLimits = array( 120, 150, 180, 200, 250, 300 ); /** * Adjust width of upright images when parameter 'upright' is used * This allows a nicer look for upright images without the need to fix the width * by hardcoded px in wiki sourcecode. */ $wgThumbUpright = 0.75; /** * On category pages, show thumbnail gallery for images belonging to that * category instead of listing them as articles. */ $wgCategoryMagicGallery = true; /** * Paging limit for categories */ $wgCategoryPagingLimit = 200; /** * Browser Blacklist for unicode non compliant browsers * Contains a list of regexps : "/regexp/" matching problematic browsers */ $wgBrowserBlackList = array( /** * Netscape 2-4 detection * The minor version may contain strings such as "Gold" or "SGoldC-SGI" * Lots of non-netscape user agents have "compatible", so it's useful to check for that * with a negative assertion. The [UIN] identifier specifies the level of security * in a Netscape/Mozilla browser, checking for it rules out a number of fakers. * The language string is unreliable, it is missing on NS4 Mac. * * Reference: http://www.psychedelix.com/agents/index.shtml */ '/^Mozilla\/2\.[^ ]+ [^(]*?\((?!compatible).*; [UIN]/', '/^Mozilla\/3\.[^ ]+ [^(]*?\((?!compatible).*; [UIN]/', '/^Mozilla\/4\.[^ ]+ [^(]*?\((?!compatible).*; [UIN]/', /** * MSIE on Mac OS 9 is teh sux0r, converts þ to , ð to , Þ to and Ð to * * Known useragents: * - Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) * - Mozilla/4.0 (compatible; MSIE 5.15; Mac_PowerPC) * - Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) * - [...] * * @link http://en.wikipedia.org/w/index.php?title=User%3A%C6var_Arnfj%F6r%F0_Bjarmason%2Ftestme&diff=12356041&oldid=12355864 * @link http://en.wikipedia.org/wiki/Template%3AOS9 */ '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/', /** * Google wireless transcoder, seems to eat a lot of chars alive * http://it.wikipedia.org/w/index.php?title=Luciano_Ligabue&diff=prev&oldid=8857361 */ '/^Mozilla\/4\.0 \(compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;\)/' ); /** * Fake out the timezone that the server thinks it's in. This will be used for * date display and not for what's stored in the DB. Leave to null to retain * your server's OS-based timezone value. This is the same as the timezone. * * This variable is currently used ONLY for signature formatting, not for * anything else. */ # $wgLocaltimezone = 'GMT'; # $wgLocaltimezone = 'PST8PDT'; # $wgLocaltimezone = 'Europe/Sweden'; # $wgLocaltimezone = 'CET'; $wgLocaltimezone = null; /** * Set an offset from UTC in minutes to use for the default timezone setting * for anonymous users and new user accounts. * * This setting is used for most date/time displays in the software, and is * overrideable in user preferences. It is *not* used for signature timestamps. * * You can set it to match the configured server timezone like this: * $wgLocalTZoffset = date("Z") / 60; * * If your server is not configured for the timezone you want, you can set * this in conjunction with the signature timezone and override the TZ * environment variable like so: * $wgLocaltimezone="Europe/Berlin"; * putenv("TZ=$wgLocaltimezone"); * $wgLocalTZoffset = date("Z") / 60; * * Leave at NULL to show times in universal time (UTC/GMT). */ $wgLocalTZoffset = null; /** * When translating messages with wfMsg(), it is not always clear what should be * considered UI messages and what shoud be content messages. * * For example, for regular wikipedia site like en, there should be only one * 'mainpage', therefore when getting the link of 'mainpage', we should treate * it as content of the site and call wfMsgForContent(), while for rendering the * text of the link, we call wfMsg(). The code in default behaves this way. * However, sites like common do offer different versions of 'mainpage' and the * like for different languages. This array provides a way to override the * default behavior. For example, to allow language specific mainpage and * community portal, set * * $wgForceUIMsgAsContentMsg = array( 'mainpage', 'portal-url' ); */ $wgForceUIMsgAsContentMsg = array(); /** * Authentication plugin. */ $wgAuth = null; /** * Global list of hooks. * Add a hook by doing: * $wgHooks['event_name'][] = $function; * or: * $wgHooks['event_name'][] = array($function, $data); * or: * $wgHooks['event_name'][] = array($object, 'method'); */ $wgHooks = array(); /** * The logging system has two levels: an event type, which describes the * general category and can be viewed as a named subset of all logs; and * an action, which is a specific kind of event that can exist in that * log type. */ $wgLogTypes = array( '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'patrol', ); /** * Lists the message key string for each log type. The localized messages * will be listed in the user interface. * * Extensions with custom log types may add to this array. */ $wgLogNames = array( '' => 'log', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', ); /** * Lists the message key string for descriptive text to be shown at the * top of each log type. * * Extensions with custom log types may add to this array. */ $wgLogHeaders = array( '' => 'alllogstext', 'block' => 'blocklogtext', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'delete' => 'dellogpagetext', 'upload' => 'uploadlogpagetext', 'move' => 'movelogpagetext', 'import' => 'importlogpagetext', 'patrol' => 'patrol-log-header', ); /** * Lists the message key string for formatting individual events of each * type and action when listed in the logs. * * Extensions with custom log types may add to this array. */ $wgLogActions = array( 'block/block' => 'blocklogentry', 'block/unblock' => 'unblocklogentry', 'protect/protect' => 'protectedarticle', 'protect/unprotect' => 'unprotectedarticle', 'rights/rights' => 'rightslogentry', 'delete/delete' => 'deletedarticle', 'delete/restore' => 'undeletedarticle', 'delete/revision' => 'revdelete-logentry', 'upload/upload' => 'uploadedimage', 'upload/revert' => 'uploadedimage', 'move/move' => '1movedto2', 'move/move_redir' => '1movedto2_redir', 'import/upload' => 'import-logentry-upload', 'import/interwiki' => 'import-logentry-interwiki', ); /** * Experimental preview feature to fetch rendered text * over an XMLHttpRequest from JavaScript instead of * forcing a submit and reload of the whole page. * Leave disabled unless you're testing it. */ $wgLivePreview = false; /** * Disable the internal MySQL-based search, to allow it to be * implemented by an extension instead. */ $wgDisableInternalSearch = false; /** * Set this to a URL to forward search requests to some external location. * If the URL includes '$1', this will be replaced with the URL-encoded * search term. * * For example, to forward to Google you'd have something like: * $wgSearchForwardUrl = 'http://www.google.com/search?q=$1' . * '&domains=http://example.com' . * '&sitesearch=http://example.com' . * '&ie=utf-8&oe=utf-8'; */ $wgSearchForwardUrl = null; /** * If true, external URL links in wiki text will be given the * rel="nofollow" attribute as a hint to search engines that * they should not be followed for ranking purposes as they * are user-supplied and thus subject to spamming. */ $wgNoFollowLinks = true; /** * Namespaces in which $wgNoFollowLinks doesn't apply. * See Language.php for a list of namespaces. */ $wgNoFollowNsExceptions = array(); /** * Robot policies per namespaces. * The default policy is 'index,follow', the array is made of namespace * constants as defined in includes/Defines.php * Example: * $wgNamespaceRobotPolicies = array( NS_TALK => 'noindex' ); */ $wgNamespaceRobotPolicies = array(); /** + * Robot policies per article. + * These override the per-namespace robot policies. + * Must be in the form of an array where the key part is a properly + * canonicalised text form title and the value is a robot policy. + * Example: + * $wgArticleRobotPolicies = array( 'Main Page' => 'noindex' ); + */ +$wgArticleRobotPolicies = array(); + +/** * Specifies the minimal length of a user password. If set to * 0, empty passwords are allowed. */ $wgMinimalPasswordLength = 0; /** * Activate external editor interface for files and pages * See http://meta.wikimedia.org/wiki/Help:External_editors */ $wgUseExternalEditor = true; /** Whether or not to sort special pages in Special:Specialpages */ $wgSortSpecialPages = true; /** * Specify the name of a skin that should not be presented in the * list of available skins. * Use for blacklisting a skin which you do not want to remove * from the .../skins/ directory */ $wgSkipSkin = ''; $wgSkipSkins = array(); # More of the same /** * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc. */ $wgDisabledActions = array(); /** * Disable redirects to special pages and interwiki redirects, which use a 302 and have no "redirected from" link */ $wgDisableHardRedirects = false; /** * Use http.dnsbl.sorbs.net to check for open proxies */ $wgEnableSorbs = false; $wgSorbsUrl = 'http.dnsbl.sorbs.net.'; /** * Proxy whitelist, list of addresses that are assumed to be non-proxy despite what the other * methods might say */ $wgProxyWhitelist = array(); /** * Simple rate limiter options to brake edit floods. * Maximum number actions allowed in the given number of seconds; * after that the violating client receives HTTP 500 error pages * until the period elapses. * * array( 4, 60 ) for a maximum of 4 hits in 60 seconds. * * This option set is experimental and likely to change. * Requires memcached. */ $wgRateLimits = array( 'edit' => array( 'anon' => null, // for any and all anonymous edits (aggregate) 'user' => null, // for each logged-in user 'newbie' => null, // for each recent account; overrides 'user' 'ip' => null, // for each anon and recent account 'subnet' => null, // ... with final octet removed ), 'move' => array( 'user' => null, 'newbie' => null, 'ip' => null, 'subnet' => null, ), 'mailpassword' => array( 'anon' => NULL, ), 'emailuser' => array( 'user' => null, ), ); /** * Set to a filename to log rate limiter hits. */ $wgRateLimitLog = null; /** * Array of groups which should never trigger the rate limiter */ $wgRateLimitsExcludedGroups = array( 'sysop', 'bureaucrat' ); /** * On Special:Unusedimages, consider images "used", if they are put * into a category. Default (false) is not to count those as used. */ $wgCountCategorizedImagesAsUsed = false; /** * External stores allow including content * from non database sources following URL links * * Short names of ExternalStore classes may be specified in an array here: * $wgExternalStores = array("http","file","custom")... * * CAUTION: Access to database might lead to code execution */ $wgExternalStores = false; /** * An array of external mysql servers, e.g. * $wgExternalServers = array( 'cluster1' => array( 'srv28', 'srv29', 'srv30' ) ); */ $wgExternalServers = array(); /** * The place to put new revisions, false to put them in the local text table. * Part of a URL, e.g. DB://cluster1 * * Can be an array instead of a single string, to enable data distribution. Keys * must be consecutive integers, starting at zero. Example: * * $wgDefaultExternalStore = array( 'DB://cluster1', 'DB://cluster2' ); * */ $wgDefaultExternalStore = false; /** * Revision text may be cached in $wgMemc to reduce load on external storage * servers and object extraction overhead for frequently-loaded revisions. * * Set to 0 to disable, or number of seconds before cache expiry. */ $wgRevisionCacheExpiry = 0; /** * list of trusted media-types and mime types. * Use the MEDIATYPE_xxx constants to represent media types. * This list is used by Image::isSafeFile * * Types not listed here will have a warning about unsafe content * displayed on the images description page. It would also be possible * to use this for further restrictions, like disabling direct * [[media:...]] links for non-trusted formats. */ $wgTrustedMediaFormats= array( MEDIATYPE_BITMAP, //all bitmap formats MEDIATYPE_AUDIO, //all audio formats MEDIATYPE_VIDEO, //all plain video formats "image/svg+xml", //svg (only needed if inline rendering of svg is not supported) "application/pdf", //PDF files #"application/x-shockwave-flash", //flash/shockwave movie ); /** * Allow special page inclusions such as {{Special:Allpages}} */ $wgAllowSpecialInclusion = true; /** * Timeout for HTTP requests done via CURL */ $wgHTTPTimeout = 3; /** * Proxy to use for CURL requests. */ $wgHTTPProxy = false; /** * Enable interwiki transcluding. Only when iw_trans=1. */ $wgEnableScaryTranscluding = false; /** * Expiry time for interwiki transclusion */ $wgTranscludeCacheExpiry = 3600; /** * Support blog-style "trackbacks" for articles. See * http://www.sixapart.com/pronet/docs/trackback_spec for details. */ $wgUseTrackbacks = false; /** * Enable filtering of categories in Recentchanges */ $wgAllowCategorizedRecentChanges = false ; /** * Number of jobs to perform per request. May be less than one in which case * jobs are performed probabalistically. If this is zero, jobs will not be done * during ordinary apache requests. In this case, maintenance/runJobs.php should * be run periodically. */ $wgJobRunRate = 1; /** * Number of rows to update per job */ $wgUpdateRowsPerJob = 500; /** * Number of rows to update per query */ $wgUpdateRowsPerQuery = 10; /** * Enable AJAX framework */ $wgUseAjax = false; /** * Enable auto suggestion for the search bar * Requires $wgUseAjax to be true too. * Causes wfSajaxSearch to be added to $wgAjaxExportList */ $wgAjaxSearch = false; /** * List of Ajax-callable functions. * Extensions acting as Ajax callbacks must register here */ $wgAjaxExportList = array( ); /** * Enable watching/unwatching pages using AJAX. * Requires $wgUseAjax to be true too. * Causes wfAjaxWatch to be added to $wgAjaxExportList */ $wgAjaxWatch = false; /** * Allow DISPLAYTITLE to change title display */ $wgAllowDisplayTitle = false ; /** * Array of usernames which may not be registered or logged in from * Maintenance scripts can still use these */ $wgReservedUsernames = array( 'MediaWiki default', // Default 'Main Page' and MediaWiki: message pages 'Conversion script', // Used for the old Wikipedia software upgrade 'Maintenance script', // Maintenance scripts which perform editing, image import script 'Template namespace initialisation script', // Used in 1.2->1.3 upgrade ); /** * MediaWiki will reject HTMLesque tags in uploaded files due to idiotic browsers which can't * perform basic stuff like MIME detection and which are vulnerable to further idiots uploading * crap files as images. When this directive is on, will be allowed in files with * an "image/svg+xml" MIME type. You should leave this disabled if your web server is misconfigured * and doesn't send appropriate MIME types for SVG images. */ $wgAllowTitlesInSVG = false; /** * Array of namespaces which can be deemed to contain valid "content", as far * as the site statistics are concerned. Useful if additional namespaces also * contain "content" which should be considered when generating a count of the * number of articles in the wiki. */ $wgContentNamespaces = array( NS_MAIN ); /** * Maximum amount of virtual memory available to shell processes under linux, in KB. */ $wgMaxShellMemory = 102400; /** * Maximum file size created by shell processes under linux, in KB * ImageMagick convert for example can be fairly hungry for scratch space */ $wgMaxShellFileSize = 102400; /** * DJVU settings * Path of the djvudump executable * Enable this and $wgDjvuRenderer to enable djvu rendering */ # $wgDjvuDump = 'djvudump'; $wgDjvuDump = null; /** * Path of the ddjvu DJVU renderer * Enable this and $wgDjvuDump to enable djvu rendering */ # $wgDjvuRenderer = 'ddjvu'; $wgDjvuRenderer = null; /** * Path of the djvutoxml executable * This works like djvudump except much, much slower as of version 3.5. * * For now I recommend you use djvudump instead. The djvuxml output is * probably more stable, so we'll switch back to it as soon as they fix * the efficiency problem. * http://sourceforge.net/tracker/index.php?func=detail&aid=1704049&group_id=32953&atid=406583 */ # $wgDjvuToXML = 'djvutoxml'; $wgDjvuToXML = null; /** * Shell command for the DJVU post processor * Default: pnmtopng, since ddjvu generates ppm output * Set this to false to output the ppm file directly. */ $wgDjvuPostProcessor = 'pnmtojpeg'; /** * File extension for the DJVU post processor output */ $wgDjvuOutputExtension = 'jpg'; /** * Enable direct access to the data API * through api.php */ $wgEnableAPI = true; $wgEnableWriteAPI = false; /** * Parser test suite files to be run by parserTests.php when no specific * filename is passed to it. * * Extensions may add their own tests to this array, or site-local tests * may be added via LocalSettings.php * * Use full paths. */ $wgParserTestFiles = array( "$IP/maintenance/parserTests.txt", ); /** * Break out of framesets. This can be used to prevent external sites from * framing your site with ads. */ $wgBreakFrames = false; /** * Set this to an array of special page names to prevent * maintenance/updateSpecialPages.php from updating those pages. */ $wgDisableQueryPageUpdate = false; /** * Set this to false to disable cascading protection */ $wgEnableCascadingProtection = true; /** * Disable output compression (enabled by default if zlib is available) */ $wgDisableOutputCompression = false; /** * If lag is higher than $wgSlaveLagWarning, show a warning in some special * pages (like watchlist). If the lag is higher than $wgSlaveLagCritical, * show a more obvious warning. */ $wgSlaveLagWarning = 10; $wgSlaveLagCritical = 30; ?>