diff options
author | nobody <nobody@localhost> | 2004-06-27 00:05:32 +0000 |
---|---|---|
committer | nobody <nobody@localhost> | 2004-06-27 00:05:32 +0000 |
commit | 0c1d741ff4792d486258b390cf50cf3f9e229511 (patch) | |
tree | 55961c46b433ade0739763bee2ba3c4843d13751 /includes | |
parent | d5c8171a3157337557bc54ecb730d7dd35778ca3 (diff) | |
parent | 1aaed5fd7c7f4d7ea7abbfc7915bab5954d60a30 (diff) | |
download | mediawikicore-1.3.0beta4a.tar.gz mediawikicore-1.3.0beta4a.zip |
This commit was manufactured by cvs2svn to create tag1.3.0beta4a
'REL1_3_0beta4a'.
Diffstat (limited to 'includes')
69 files changed, 4749 insertions, 2875 deletions
diff --git a/includes/Article.php b/includes/Article.php index 6ccdb7bb2a40..6dea6747dca4 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -1,11 +1,13 @@ <?php +# $Id$ +# # Class representing a Wikipedia article and history. # See design.doc for an overview. # Note: edit user interface and cache support functions have been # moved to separate EditPage and CacheManager classes. -require_once( "CacheManager.php" ); +require_once( 'CacheManager.php' ); class Article { /* private */ var $mContent, $mContentLoaded; @@ -25,39 +27,169 @@ class Article { $this->mContentLoaded = false; $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded $this->mRedirectedFrom = $this->mUserText = - $this->mTimestamp = $this->mComment = $this->mFileCache = ""; + $this->mTimestamp = $this->mComment = $this->mFileCache = ''; $this->mCountAdjustment = 0; - $this->mTouched = "19700101000000"; + $this->mTouched = '19700101000000'; } - /* static */ function getRevisionText( $row, $prefix = "old_" ) { - # Deal with optional compression of archived pages. - # This can be done periodically via maintenance/compressOld.php, and - # as pages are saved if $wgCompressRevisions is set. - $text = $prefix . "text"; - $flags = $prefix . "flags"; - if( isset( $row->$flags ) && (false !== strpos( $row->$flags, "gzip" ) ) ) { - return gzinflate( $row->$text ); + # Get revision text associated with an old or archive row + # $row is usually an object from wfFetchRow(), both the flags and the text field must be included + /* static */ function getRevisionText( $row, $prefix = 'old_' ) { + # Get data + $textField = $prefix . 'text'; + $flagsField = $prefix . 'flags'; + + if ( isset( $row->$flagsField ) ) { + $flags = explode( ",", $row->$flagsField ); + } else { + $flags = array(); + } + + if ( isset( $row->$textField ) ) { + $text = $row->$textField; + } else { + return false; } - if( isset( $row->$text ) ) { - return $row->$text; + + if ( in_array( 'link', $flags ) ) { + # Handle link type + $text = Article::followLink( $text ); + } elseif ( in_array( 'gzip', $flags ) ) { + # Deal with optional compression of archived pages. + # This can be done periodically via maintenance/compressOld.php, and + # as pages are saved if $wgCompressRevisions is set. + return gzinflate( $text ); } - return false; + return $text; } /* static */ function compressRevisionText( &$text ) { global $wgCompressRevisions; if( !$wgCompressRevisions ) { - return ""; + return ''; } - if( !function_exists( "gzdeflate" ) ) { + if( !function_exists( 'gzdeflate' ) ) { wfDebug( "Article::compressRevisionText() -- no zlib support, not compressing\n" ); - return ""; + return ''; } $text = gzdeflate( $text ); - return "gzip"; + return 'gzip'; } + # Returns the text associated with a "link" type old table row + /* static */ function followLink( $link ) { + # Split the link into fields and values + $lines = explode( '\n', $link ); + $hash = ''; + $locations = array(); + foreach ( $lines as $line ) { + # Comments + if ( $line{0} == '#' ) { + continue; + } + # Field/value pairs + if ( preg_match( '/^(.*?)\s*:\s*(.*)$/', $line, $matches ) ) { + $field = strtolower($matches[1]); + $value = $matches[2]; + if ( $field == 'hash' ) { + $hash = $value; + } elseif ( $field == 'location' ) { + $locations[] = $value; + } + } + } + + if ( $hash === '' ) { + return false; + } + + # Look in each specified location for the text + $text = false; + foreach ( $locations as $location ) { + $text = Article::fetchFromLocation( $location, $hash ); + if ( $text !== false ) { + break; + } + } + + return $text; + } + + /* static */ function fetchFromLocation( $location, $hash ) { + global $wgLoadBalancer; + $fname = 'fetchFromLocation'; + wfProfileIn( $fname ); + + $p = strpos( $location, ':' ); + if ( $p === false ) { + wfProfileOut( $fname ); + return false; + } + + $type = substr( $location, 0, $p ); + $text = false; + switch ( $type ) { + case 'mysql': + # MySQL locations are specified by mysql://<machineID>/<dbname>/<tblname>/<index> + # Machine ID 0 is the current connection + if ( preg_match( '/^mysql:\/\/(\d+)\/([A-Za-z_]+)\/([A-Za-z_]+)\/([A-Za-z_]+)$/', + $location, $matches ) ) { + $machineID = $matches[1]; + $dbName = $matches[2]; + $tblName = $matches[3]; + $index = $matches[4]; + if ( $machineID == 0 ) { + # Current connection + $db =& wfGetDB(); + } else { + # Alternate connection + $db =& $wgLoadBalancer->getConnection( $machineID ); + + if ( array_key_exists( $machineId, $wgKnownMysqlServers ) ) { + # Try to open, return false on failure + $params = $wgKnownDBServers[$machineId]; + $db = Database::newFromParams( $params['server'], $params['user'], $params['password'], + $dbName, 1, false, true, true ); + } + } + if ( $db->isOpen() ) { + $index = wfStrencode( $index ); + $res = $db->query( "SELECT blob_data FROM $dbName.$tblName WHERE blob_index='$index'", $fname ); + $row = $db->fetchObject( $res ); + $text = $row->text_data; + } + } + break; + case 'file': + # File locations are of the form file://<filename>, relative to the current directory + if ( preg_match( '/^file:\/\/(.*)$', $location, $matches ) ) + $filename = strstr( $location, 'file://' ); + $text = @file_get_contents( $matches[1] ); + } + if ( $text !== false ) { + # Got text, now we need to interpret it + # The first line contains information about how to do this + $p = strpos( $text, '\n' ); + $type = substr( $text, 0, $p ); + $text = substr( $text, $p + 1 ); + switch ( $type ) { + case 'plain': + break; + case 'gzip': + $text = gzinflate( $text ); + break; + case 'object': + $object = unserialize( $text ); + $text = $object->getItem( $hash ); + break; + default: + $text = false; + } + } + wfProfileOut( $fname ); + return $text; + } + # Note that getContent/loadContent may follow redirects if # not told otherwise, and so may cause a change to mTitle. @@ -70,34 +202,34 @@ class Article { $action = $wgRequest->getText( 'action', 'view' ); $section = $wgRequest->getText( 'section' ); - $fname = "Article::getContent"; + $fname = 'Article::getContent'; wfProfileIn( $fname ); if ( 0 == $this->getID() ) { - if ( "edit" == $action ) { + if ( 'edit' == $action ) { wfProfileOut( $fname ); - return ""; # was "newarticletext", now moved above the box) + return ''; # was "newarticletext", now moved above the box) } wfProfileOut( $fname ); - return wfMsg( "noarticletext" ); + return wfMsg( 'noarticletext' ); } else { $this->loadContent( $noredir ); if( # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page ( $this->mTitle->getNamespace() == Namespace::getTalk( Namespace::getUser()) ) && - preg_match("/^\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3}$/",$this->mTitle->getText()) && - $action=="view" + preg_match('/^\d{1,3}\.\d{1,3}.\d{1,3}\.\d{1,3}$/',$this->mTitle->getText()) && + $action=='view' ) { wfProfileOut( $fname ); - return $this->mContent . "\n" .wfMsg("anontalkpagetext"); } + return $this->mContent . "\n" .wfMsg('anontalkpagetext'); } else { - if($action=="edit") { - if($section!="") { - if($section=="new") { + if($action=='edit') { + if($section!='') { + if($section=='new') { wfProfileOut( $fname ); - return ""; + return ''; } # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML @@ -132,18 +264,18 @@ class Article { # split it up by section $secs = preg_split( - "/(^=+.*?=+|^<h[1-6].*?" . ">.*?<\/h[1-6].*?" . ">)/mi", + '/(^=+.*?=+|^<h[1-6].*?' . '>.*?<\/h[1-6].*?' . '>)/mi', $striptext, -1, PREG_SPLIT_DELIM_CAPTURE); if($section==0) { $rv=$secs[0]; } else { $headline=$secs[$section*2-1]; - preg_match( "/^(=+).*?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>/mi",$headline,$matches); + preg_match( '/^(=+).*?=+|^<h([1-6]).*?' . '>.*?<\/h[1-6].*?' . '>/mi',$headline,$matches); $hlevel=$matches[1]; # translate wiki heading into level - if(strpos($hlevel,"=")!==false) { + if(strpos($hlevel,'=')!==false) { $hlevel=strlen($hlevel); } @@ -154,9 +286,9 @@ class Article { while(!empty($secs[$count*2-1]) && !$break) { $subheadline=$secs[$count*2-1]; - preg_match( "/^(=+).*?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>/mi",$subheadline,$matches); + preg_match( '/^(=+).*?=+|^<h([1-6]).*?' . '>.*?<\/h[1-6].*?' . '>/mi',$subheadline,$matches); $subhlevel=$matches[1]; - if(strpos($subhlevel,"=")!==false) { + if(strpos($subhlevel,'=')!==false) { $subhlevel=strlen($subhlevel); } if($subhlevel > $hlevel) { @@ -171,6 +303,7 @@ class Article { } # reinsert stripped tags $rv=$parser->unstrip($rv,$striparray); + $rv=$parser->unstripNoWiki($rv,$striparray); $rv=trim($rv); return $rv; @@ -180,14 +313,14 @@ class Article { # Load the revision (including cur_text) into this object function loadContent( $noredir = false ) { - global $wgOut, $wgMwRedir, $wgRequest; + global $wgOut, $wgMwRedir, $wgRequest, $wgIsPg; # Query variables :P $oldid = $wgRequest->getVal( 'oldid' ); $redirect = $wgRequest->getVal( 'redirect' ); if ( $this->mContentLoaded ) return; - $fname = "Article::loadContent"; + $fname = 'Article::loadContent'; # Pre-fill content with error message so that if something # fails we'll have something telling us what we intended. @@ -198,17 +331,17 @@ class Article { $t .= ",oldid={$oldid}"; } if ( isset( $redirect ) ) { - $redirect = ($redirect == "no") ? "no" : "yes"; + $redirect = ($redirect == 'no') ? 'no' : 'yes'; $t .= ",redirect={$redirect}"; } - $this->mContent = wfMsg( "missingarticle", $t ); + $this->mContent = wfMsg( 'missingarticle', $t ); if ( ! $oldid ) { # Retrieve current version $id = $this->getID(); if ( 0 == $id ) return; - $sql = "SELECT " . - "cur_text,cur_timestamp,cur_user,cur_counter,cur_restrictions,cur_touched " . + $sql = 'SELECT ' . + 'cur_text,cur_timestamp,cur_user,cur_user_text,cur_comment,cur_counter,cur_restrictions,cur_touched ' . "FROM cur WHERE cur_id={$id}"; wfDebug( "$sql\n" ); $res = wfQuery( $sql, DB_READ, $fname ); @@ -219,9 +352,9 @@ class Article { $s = wfFetchObject( $res ); # If we got a redirect, follow it (unless we've been told # not to by either the function parameter or the query - if ( ( "no" != $redirect ) && ( false == $noredir ) && + if ( ( 'no' != $redirect ) && ( false == $noredir ) && ( $wgMwRedir->matchStart( $s->cur_text ) ) ) { - if ( preg_match( "/\\[\\[([^\\]\\|]+)[\\]\\|]/", + if ( preg_match( '/\\[\\[([^\\]\\|]+)[\\]\\|]/', $s->cur_text, $m ) ) { $rt = Title::newFromText( $m[1] ); if( $rt ) { @@ -229,7 +362,7 @@ class Article { # Fill the HTTP response "Location" header and ignore # the rest of the page we're on. - if ( $rt->getInterwiki() != "" ) { + if ( $rt->getInterwiki() != '' ) { $wgOut->redirect( $rt->getFullURL() ) ; return; } @@ -239,7 +372,7 @@ class Article { } $rid = $rt->getArticleID(); if ( 0 != $rid ) { - $sql = "SELECT cur_text,cur_timestamp,cur_user," . + $sql = 'SELECT cur_text,cur_timestamp,cur_user,cur_user_text,cur_comment,' . "cur_counter,cur_restrictions,cur_touched FROM cur WHERE cur_id={$rid}"; $res = wfQuery( $sql, DB_READ, $fname ); @@ -255,15 +388,19 @@ class Article { $this->mContent = $s->cur_text; $this->mUser = $s->cur_user; + $this->mUserText = $s->cur_user_text; + $this->mComment = $s->cur_comment; $this->mCounter = $s->cur_counter; $this->mTimestamp = $s->cur_timestamp; $this->mTouched = $s->cur_touched; - $this->mTitle->mRestrictions = explode( ",", trim( $s->cur_restrictions ) ); + $this->mTitle->mRestrictions = explode( ',', trim( $s->cur_restrictions ) ); $this->mTitle->mRestrictionsLoaded = true; wfFreeResult( $res ); } else { # oldid set, retrieve historical version - $sql = "SELECT old_namespace,old_title,old_text,old_timestamp,old_user,old_flags FROM old " . - "WHERE old_id={$oldid}"; + $oldtable=$wgIsPg?'"old"':'old'; + $sql = "SELECT old_namespace,old_title,old_text,old_timestamp,". + "old_user,old_user_text,old_comment,old_flags FROM old ". + "WHERE old_id={$oldid}"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { return; @@ -278,6 +415,8 @@ class Article { } $this->mContent = Article::getRevisionText( $s ); $this->mUser = $s->old_user; + $this->mUserText = $s->old_user_text; + $this->mComment = $s->old_comment; $this->mCounter = 0; $this->mTimestamp = $s->old_timestamp; wfFreeResult( $res ); @@ -289,14 +428,14 @@ class Article { # Gets the article text without using so many damn globals # Returns false on error function getContentWithoutUsingSoManyDamnGlobals( $oldid = 0, $noredir = false ) { - global $wgMwRedir; + global $wgMwRedir, $wgIsPg; if ( $this->mContentLoaded ) { return $this->mContent; } $this->mContent = false; - $fname = "Article::loadContent"; + $fname = 'Article::loadContent'; if ( ! $oldid ) { # Retrieve current version $id = $this->getID(); @@ -304,8 +443,8 @@ class Article { return false; } - $sql = "SELECT " . - "cur_text,cur_timestamp,cur_user,cur_counter,cur_restrictions,cur_touched " . + $sql = 'SELECT ' . + 'cur_text,cur_timestamp,cur_user,cur_counter,cur_restrictions,cur_touched ' . "FROM cur WHERE cur_id={$id}"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { @@ -316,13 +455,13 @@ class Article { # If we got a redirect, follow it (unless we've been told # not to by either the function parameter or the query if ( !$noredir && $wgMwRedir->matchStart( $s->cur_text ) ) { - if ( preg_match( "/\\[\\[([^\\]\\|]+)[\\]\\|]/", + if ( preg_match( '/\\[\\[([^\\]\\|]+)[\\]\\|]/', $s->cur_text, $m ) ) { $rt = Title::newFromText( $m[1] ); - if( $rt && $rt->getInterwiki() == "" && $rt->getNamespace() != Namespace::getSpecial() ) { + if( $rt && $rt->getInterwiki() == '' && $rt->getNamespace() != Namespace::getSpecial() ) { $rid = $rt->getArticleID(); if ( 0 != $rid ) { - $sql = "SELECT cur_text,cur_timestamp,cur_user," . + $sql = 'SELECT cur_text,cur_timestamp,cur_user,' . "cur_counter,cur_restrictions,cur_touched FROM cur WHERE cur_id={$rid}"; $res = wfQuery( $sql, DB_READ, $fname ); @@ -345,7 +484,8 @@ class Article { $this->mTitle->mRestrictionsLoaded = true; wfFreeResult( $res ); } else { # oldid set, retrieve historical version - $sql = "SELECT old_text,old_timestamp,old_user,old_flags FROM old " . + $oldtable=$wgIsPg?'"old"':'old'; + $sql = "SELECT old_text,old_timestamp,old_user,old_flags FROM $oldtable " . "WHERE old_id={$oldid}"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { @@ -375,7 +515,7 @@ class Article { { if ( -1 == $this->mCounter ) { $id = $this->getID(); - $this->mCounter = wfGetSQL( "cur", "cur_counter", "cur_id={$id}" ); + $this->mCounter = wfGetSQL( 'cur', 'cur_counter', "cur_id={$id}" ); } return $this->mCounter; } @@ -389,7 +529,7 @@ class Article { if ( 0 != $this->mTitle->getNamespace() ) { return 0; } if ( $wgMwRedir->matchStart( $text ) ) { return 0; } - $token = ($wgUseCommaCount ? "," : "[[" ); + $token = ($wgUseCommaCount ? ',' : '[[' ); if ( false === strstr( $text, $token ) ) { return 0; } return 1; } @@ -402,10 +542,10 @@ class Article { global $wgOut; if ( -1 != $this->mUser ) return; - $sql = "SELECT cur_user,cur_user_text,cur_timestamp," . - "cur_comment,cur_minor_edit FROM cur WHERE " . - "cur_id=" . $this->getID(); - $res = wfQuery( $sql, DB_READ, "Article::loadLastEdit" ); + $sql = 'SELECT cur_user,cur_user_text,cur_timestamp,' . + 'cur_comment,cur_minor_edit FROM cur WHERE ' . + 'cur_id=' . $this->getID(); + $res = wfQuery( $sql, DB_READ, 'Article::loadLastEdit' ); if ( wfNumRows( $res ) > 0 ) { $s = wfFetchObject( $res ); @@ -449,7 +589,7 @@ class Article { function getContributors($limit = 0, $offset = 0) { - $fname = "Article::getContributors"; + $fname = 'Article::getContributors'; # XXX: this is expensive; cache this info somewhere. @@ -457,19 +597,19 @@ class Article { $contribs = array(); - $sql = "SELECT old.old_user, old.old_user_text, " . - " user.user_real_name, MAX(old.old_timestamp) as timestamp" . - " FROM old, user " . - " WHERE old.old_user = user.user_id " . - " AND old.old_namespace = " . $title->getNamespace() . - " AND old.old_title = \"" . $title->getDBkey() . "\"" . - " AND old.old_user != 0 " . - " AND old.old_user != " . $this->getUser() . - " GROUP BY old.old_user " . - " ORDER BY timestamp DESC "; + $sql = 'SELECT old.old_user, old.old_user_text, ' . + ' user.user_real_name, MAX(old.old_timestamp) as timestamp' . + ' FROM old, user ' . + ' WHERE old.old_user = user.user_id ' . + ' AND old.old_namespace = ' . $title->getNamespace() . + ' AND old.old_title = "' . $title->getDBkey() . '"' . + ' AND old.old_user != 0 ' . + ' AND old.old_user != ' . $this->getUser() . + ' GROUP BY old.old_user ' . + ' ORDER BY timestamp DESC '; if ($limit > 0) { - $sql .= " LIMIT $limit"; + $sql .= ' LIMIT '.$limit; } $res = wfQuery($sql, DB_READ, $fname); @@ -481,11 +621,11 @@ class Article { # Count anonymous users - $res = wfQuery("SELECT COUNT(*) AS cnt " . - " FROM old " . - " WHERE old_namespace = " . $title->getNamespace() . + $res = wfQuery('SELECT COUNT(*) AS cnt ' . + ' FROM old ' . + ' WHERE old_namespace = ' . $title->getNamespace() . " AND old_title = '" . $title->getDBkey() . "'" . - " AND old_user = 0 ", DB_READ, $fname); + ' AND old_user = 0 ', DB_READ, $fname); while ( $line = wfFetchObject( $res ) ) { $contribs[0] = array($line->cnt, 'Anonymous'); @@ -502,7 +642,7 @@ class Article { global $wgUser, $wgOut, $wgLang, $wgRequest; global $wgLinkCache, $IP, $wgEnableParserCache; - $fname = "Article::view"; + $fname = 'Article::view'; wfProfileIn( $fname ); # Get variables from query string :P @@ -510,7 +650,7 @@ class Article { $diff = $wgRequest->getVal( 'diff' ); $wgOut->setArticleFlag( true ); - $wgOut->setRobotpolicy( "index,follow" ); + $wgOut->setRobotpolicy( 'index,follow' ); # If we got diff and oldid in the query, we want to see a # diff page instead of the article. @@ -533,48 +673,67 @@ class Article { return; } } - - $text = $this->getContent( false ); # May change mTitle by following a redirect - # Another whitelist check in case oldid or redirects are altering the title - if ( !$this->mTitle->userCanRead() ) { - $wgOut->loginToUse(); - $wgOut->output(); - exit; + # Should the parser cache be used? + if ( $wgEnableParserCache && intval($wgUser->getOption( 'stubthreshold' )) == 0 && empty( $oldid ) ) { + $pcache = true; + } else { + $pcache = false; } - $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); + $outputDone = false; + if ( $pcache ) { + if ( $wgOut->tryParserCache( $this, $wgUser ) ) { + $outputDone = true; + } + } - # We're looking at an old revision + if ( !$outputDone ) { + $text = $this->getContent( false ); # May change mTitle by following a redirect + + # Another whitelist check in case oldid or redirects are altering the title + if ( !$this->mTitle->userCanRead() ) { + $wgOut->loginToUse(); + $wgOut->output(); + exit; + } + - if ( !empty( $oldid ) ) { - $this->setOldSubtitle(); - $wgOut->setRobotpolicy( "noindex,follow" ); - } - if ( "" != $this->mRedirectedFrom ) { - $sk = $wgUser->getSkin(); - $redir = $sk->makeKnownLink( $this->mRedirectedFrom, "", - "redirect=no" ); - $s = wfMsg( "redirectedfrom", $redir ); - $wgOut->setSubtitle( $s ); - } + # We're looking at an old revision - $wgLinkCache->preFill( $this->mTitle ); + if ( !empty( $oldid ) ) { + $this->setOldSubtitle(); + $wgOut->setRobotpolicy( 'noindex,follow' ); + } + if ( '' != $this->mRedirectedFrom ) { + $sk = $wgUser->getSkin(); + $redir = $sk->makeKnownLink( $this->mRedirectedFrom, '', + 'redirect=no' ); + $s = wfMsg( 'redirectedfrom', $redir ); + $wgOut->setSubtitle( $s ); + + # Can't cache redirects + $pcache = false; + } - # 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 ( - $this->mTitle->getNamespace() == Namespace::getUser() && - preg_match("/\\/[\\w]+\\.(css|js)$/", $this->mTitle->getDBkey()) - ) { - $wgOut->addWikiText( wfMsg('usercssjs')); - $wgOut->addHTML( '<pre>'.htmlspecialchars($this->mContent)."\n</pre>" ); - } else if( $wgEnableParserCache && intval($wgUser->getOption( "stubthreshold" )) == 0 ){ - $wgOut->addWikiText( $text, true, $this ); - } else { - $wgOut->addWikiText( $text ); + $wgLinkCache->preFill( $this->mTitle ); + + # 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 ( + $this->mTitle->getNamespace() == Namespace::getUser() && + preg_match('/\\/[\\w]+\\.(css|js)$/', $this->mTitle->getDBkey()) + ) { + $wgOut->addWikiText( wfMsg('clearyourcache')); + $wgOut->addHTML( '<pre>'.htmlspecialchars($this->mContent)."\n</pre>" ); + } else if ( $pcache ) { + $wgOut->addWikiText( $text, true, $this ); + } else { + $wgOut->addWikiText( $text ); + } } - + $wgOut->setPageTitle( $this->mTitle->getPrefixedText() ); + # Add link titles as META keywords $wgOut->addMetaTags() ; @@ -590,9 +749,9 @@ class Article { /* private */ function insertNewArticle( $text, $summary, $isminor, $watchthis ) { global $wgOut, $wgUser, $wgLinkCache, $wgMwRedir; - global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer; + global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer, $wgIsPg, $wgIsMySQL; - $fname = "Article::insertNewArticle"; + $fname = 'Article::insertNewArticle'; $this->mCountAdjustment = $this->isCountable( $text ); @@ -605,12 +764,23 @@ class Article { $now = wfTimestampNow(); $won = wfInvertTimestamp( $now ); wfSeedRandom(); - $rand = number_format( mt_rand() / mt_getrandmax(), 12, ".", "" ); + $rand = number_format( mt_rand() / mt_getrandmax(), 12, '.', '' ); + + if ($wgIsPg) { + $cur_id_column="cur_id,"; + $cur_id=wfGetSQL(""," nextval('cur_cur_id_seq')"); + $cur_id_value="{$cur_id},"; + } else { + $cur_id_column=""; + $cur_id=""; + $cur_id_value=""; + } + $isminor = ( $isminor && $wgUser->getID() ) ? 1 : 0; - $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," . - "cur_comment,cur_user,cur_timestamp,cur_minor_edit,cur_counter," . - "cur_restrictions,cur_user_text,cur_is_redirect," . - "cur_is_new,cur_random,cur_touched,inverse_timestamp) VALUES ({$ns},'" . wfStrencode( $ttl ) . "', '" . + $sql = "INSERT INTO cur ({$cur_id_column}cur_namespace,cur_title,cur_text," . + 'cur_comment,cur_user,cur_timestamp,cur_minor_edit,cur_counter,' . + 'cur_restrictions,cur_user_text,cur_is_redirect,' . + "cur_is_new,cur_random,cur_touched,inverse_timestamp) VALUES ({$cur_id_value}{$ns},'" . wfStrencode( $ttl ) . "', '" . wfStrencode( $text ) . "', '" . wfStrencode( $summary ) . "', '" . $wgUser->getID() . "', '{$now}', " . @@ -618,7 +788,7 @@ class Article { wfStrencode( $wgUser->getName() ) . "', $redir, 1, $rand, '{$now}', '{$won}')"; $res = wfQuery( $sql, DB_WRITE, $fname ); - $newid = wfInsertId(); + $newid = $wgIsPg?$cur_id:wfInsertId(); $this->mTitle->resetArticleID( $newid ); Article::onArticleCreate( $this->mTitle ); @@ -640,16 +810,16 @@ class Article { # standard deferred updates $this->editUpdates( $text ); - $this->showArticle( $text, wfMsg( "newarticle" ) ); + $this->showArticle( $text, wfMsg( 'newarticle' ) ); } /* Side effects: loads last edit */ - function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = ""){ + function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = ''){ $this->loadLastEdit(); $oldtext = $this->getContent( true ); - if ($section != "") { - if($section=="new") { + if ($section != '') { + if($section=='new') { if($summary) $subject="== {$summary} ==\n\n"; $text=$oldtext."\n\n".$subject.$text; } else { @@ -665,7 +835,7 @@ class Article { # split it up # Unfortunately we can't simply do a preg_replace because that might # replace the wrong section, so we have to use the section counter instead - $secs=preg_split("/(^=+.*?=+|^<h[1-6].*?" . ">.*?<\/h[1-6].*?" . ">)/mi", + $secs=preg_split('/(^=+.*?=+|^<h[1-6].*?' . '>.*?<\/h[1-6].*?' . '>)/mi', $oldtext,-1,PREG_SPLIT_DELIM_CAPTURE); $secs[$section*2]=$text."\n\n"; // replace with edited @@ -677,30 +847,30 @@ class Article { # be erased, as the mother section has been replaced with # the text of all subsections. $headline=$secs[$section*2-1]; - preg_match( "/^(=+).*?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>/mi",$headline,$matches); + preg_match( '/^(=+).*?=+|^<h([1-6]).*?' . '>.*?<\/h[1-6].*?' . '>/mi',$headline,$matches); $hlevel=$matches[1]; # determine headline level for wikimarkup headings - if(strpos($hlevel,"=")!==false) { + if(strpos($hlevel,'=')!==false) { $hlevel=strlen($hlevel); } - $secs[$section*2-1]=""; // erase old headline + $secs[$section*2-1]=''; // erase old headline $count=$section+1; $break=false; while(!empty($secs[$count*2-1]) && !$break) { $subheadline=$secs[$count*2-1]; preg_match( - "/^(=+).*?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>/mi",$subheadline,$matches); + '/^(=+).*?=+|^<h([1-6]).*?' . '>.*?<\/h[1-6].*?' . '>/mi',$subheadline,$matches); $subhlevel=$matches[1]; - if(strpos($subhlevel,"=")!==false) { + if(strpos($subhlevel,'=')!==false) { $subhlevel=strlen($subhlevel); } if($subhlevel > $hlevel) { // erase old subsections - $secs[$count*2-1]=""; - $secs[$count*2]=""; + $secs[$count*2-1]=''; + $secs[$count*2]=''; } if($subhlevel <= $hlevel) { $break=true; @@ -710,25 +880,27 @@ class Article { } } - $text=join("",$secs); + $text=join('',$secs); # reinsert the stuff that we stripped out earlier $text=$parser->unstrip($text,$striparray); + $text=$parser->unstripNoWiki($text,$striparray); } } return $text; } - function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = "" ) + function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) { global $wgOut, $wgUser, $wgLinkCache; global $wgDBtransactions, $wgMwRedir; global $wgUseSquid, $wgInternalServer; - $fname = "Article::updateArticle"; + global $wgIsPg; + $fname = 'Article::updateArticle'; if ( $this->mMinorEdit ) { $me1 = 1; } else { $me1 = 0; } if ( $minor && $wgUser->getID() ) { $me2 = 1; } else { $me2 = 0; } - if ( preg_match( "/^((" . $wgMwRedir->getBaseRegex() . ")[^\\n]+)/i", $text, $m ) ) { + if ( preg_match( "/^((" . $wgMwRedir->getBaseRegex() . ')[^\\n]+)/i', $text, $m ) ) { $redir = 1; $text = $m[1] . "\n"; # Remove all content but redirect } @@ -739,7 +911,7 @@ class Article { # Update article, but only if changed. if( $wgDBtransactions ) { - $sql = "BEGIN"; + $sql = 'BEGIN'; wfQuery( $sql, DB_WRITE ); } $oldtext = $this->getContent( true ); @@ -768,9 +940,22 @@ class Article { # This overwrites $oldtext if revision compression is on $flags = Article::compressRevisionText( $oldtext ); - $sql = "INSERT INTO old (old_namespace,old_title,old_text," . - "old_comment,old_user,old_user_text,old_timestamp," . - "old_minor_edit,inverse_timestamp,old_flags) VALUES (" . + $oldtable=$wgIsPg?'"old"':'old'; + if ($wgIsPg) { + $oldtable='"old"'; + $old_id_column='old_id,'; + $old_id=wfGetSQL(""," nextval('old_old_id_seq')"); + $old_id_value=$old_id.','; + } else { + $oldtable='old'; + $old_id_column=''; + $old_id_value=''; + } + + $sql = "INSERT INTO $oldtable ({$old_id_column}old_namespace,old_title,old_text," . + 'old_comment,old_user,old_user_text,old_timestamp,' . + 'old_minor_edit,inverse_timestamp,old_flags) VALUES (' . + $old_id_value. $this->mTitle->getNamespace() . ", '" . wfStrencode( $this->mTitle->getDBkey() ) . "', '" . wfStrencode( $oldtext ) . "', '" . @@ -780,7 +965,8 @@ class Article { $this->getTimestamp() . "', " . $me1 . ", '" . wfInvertTimestamp( $this->getTimestamp() ) . "','$flags')"; $res = wfQuery( $sql, DB_WRITE, $fname ); - $oldid = wfInsertID( $res ); + + $oldid = $wgIsPg?$old_id:wfInsertId( $res ); $bot = (int)($wgUser->isBot() || $forceBot); RecentChange::notifyEdit( $now, $this->mTitle, $me2, $wgUser, $summary, @@ -789,7 +975,7 @@ class Article { } if( $wgDBtransactions ) { - $sql = "COMMIT"; + $sql = 'COMMIT'; wfQuery( $sql, DB_WRITE ); } @@ -824,7 +1010,7 @@ class Article { $u->doUpdate(); } - $this->showArticle( $text, wfMsg( "updated" ), $sectionanchor ); + $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor ); return true; } @@ -847,9 +1033,9 @@ class Article { $wgOut->addWikiText( $text ); if( $wgMwRedir->matchStart( $text ) ) - $r = "redirect=no"; + $r = 'redirect=no'; else - $r = ""; + $r = ''; $wgOut->redirect( $this->mTitle->getFullURL( $r ).$sectionanchor ); } @@ -861,7 +1047,7 @@ class Article { global $wgDeferredUpdateList; if ( 0 == $wgUser->getID() ) { - $wgOut->errorpage( "watchnologin", "watchnologintext" ); + $wgOut->errorpage( 'watchnologin', 'watchnologintext' ); return; } if ( wfReadOnly() ) { @@ -873,16 +1059,16 @@ class Article { else $wgUser->removeWatch( $this->mTitle ); - $wgOut->setPagetitle( wfMsg( $add ? "addedwatch" : "removedwatch" ) ); - $wgOut->setRobotpolicy( "noindex,follow" ); + $wgOut->setPagetitle( wfMsg( $add ? 'addedwatch' : 'removedwatch' ) ); + $wgOut->setRobotpolicy( 'noindex,follow' ); $sk = $wgUser->getSkin() ; $link = $this->mTitle->getPrefixedText(); if($add) - $text = wfMsg( "addedwatchtext", $link ); + $text = wfMsg( 'addedwatchtext', $link ); else - $text = wfMsg( "removedwatchtext", $link ); + $text = wfMsg( 'removedwatchtext', $link ); $wgOut->addWikiText( $text ); $up = new UserUpdate(); @@ -896,7 +1082,7 @@ class Article { $this->watch( false ); } - function protect( $limit = "sysop" ) + function protect( $limit = 'sysop' ) { global $wgUser, $wgOut, $wgRequest; @@ -910,7 +1096,7 @@ class Article { } $id = $this->mTitle->getArticleID(); if ( 0 == $id ) { - $wgOut->fatalError( wfMsg( "badarticleerror" ) ); + $wgOut->fatalError( wfMsg( 'badarticleerror' ) ); return; } @@ -921,50 +1107,50 @@ class Article { $sql = "UPDATE cur SET cur_touched='" . wfTimestampNow() . "'," . "cur_restrictions='{$limit}' WHERE cur_id={$id}"; - wfQuery( $sql, DB_WRITE, "Article::protect" ); + wfQuery( $sql, DB_WRITE, 'Article::protect' ); - $log = new LogPage( wfMsg( "protectlogpage" ), wfMsg( "protectlogtext" ) ); + $log = new LogPage( wfMsg( 'protectlogpage' ), wfMsg( 'protectlogtext' ) ); if ( $limit === "" ) { - $log->addEntry( wfMsg( "unprotectedarticle", $this->mTitle->getPrefixedText() ), $reason ); + $log->addEntry( wfMsg( 'unprotectedarticle', $this->mTitle->getPrefixedText() ), $reason ); } else { - $log->addEntry( wfMsg( "protectedarticle", $this->mTitle->getPrefixedText() ), $reason ); + $log->addEntry( wfMsg( 'protectedarticle', $this->mTitle->getPrefixedText() ), $reason ); } $wgOut->redirect( $this->mTitle->getFullURL() ); return; } else { - $reason = htmlspecialchars( wfMsg( "protectreason" ) ); - return $this->confirmProtect( "", $reason, $limit ); + $reason = htmlspecialchars( wfMsg( 'protectreason' ) ); + return $this->confirmProtect( '', $reason, $limit ); } } # Output protection confirmation dialog - function confirmProtect( $par, $reason, $limit = "sysop" ) + function confirmProtect( $par, $reason, $limit = 'sysop' ) { global $wgOut; wfDebug( "Article::confirmProtect\n" ); $sub = htmlspecialchars( $this->mTitle->getPrefixedText() ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); - $check = ""; - $protcom = ""; + $check = ''; + $protcom = ''; - if ( $limit === "" ) { - $wgOut->setSubtitle( wfMsg( "unprotectsub", $sub ) ); - $wgOut->addWikiText( wfMsg( "confirmunprotecttext" ) ); - $check = htmlspecialchars( wfMsg( "confirmunprotect" ) ); - $protcom = htmlspecialchars( wfMsg( "unprotectcomment" ) ); - $formaction = $this->mTitle->escapeLocalURL( "action=unprotect" . $par ); + if ( $limit === '' ) { + $wgOut->setSubtitle( wfMsg( 'unprotectsub', $sub ) ); + $wgOut->addWikiText( wfMsg( 'confirmunprotecttext' ) ); + $check = htmlspecialchars( wfMsg( 'confirmunprotect' ) ); + $protcom = htmlspecialchars( wfMsg( 'unprotectcomment' ) ); + $formaction = $this->mTitle->escapeLocalURL( 'action=unprotect' . $par ); } else { - $wgOut->setSubtitle( wfMsg( "protectsub", $sub ) ); - $wgOut->addWikiText( wfMsg( "confirmprotecttext" ) ); - $check = htmlspecialchars( wfMsg( "confirmprotect" ) ); - $protcom = htmlspecialchars( wfMsg( "protectcomment" ) ); - $formaction = $this->mTitle->escapeLocalURL( "action=protect" . $par ); + $wgOut->setSubtitle( wfMsg( 'protectsub', $sub ) ); + $wgOut->addWikiText( wfMsg( 'confirmprotecttext' ) ); + $check = htmlspecialchars( wfMsg( 'confirmprotect' ) ); + $protcom = htmlspecialchars( wfMsg( 'protectcomment' ) ); + $formaction = $this->mTitle->escapeLocalURL( 'action=protect' . $par ); } - $confirm = htmlspecialchars( wfMsg( "confirm" ) ); + $confirm = htmlspecialchars( wfMsg( 'confirm' ) ); $wgOut->addHTML( " <form id='protectconfirm' method='post' action=\"{$formaction}\"> @@ -1002,14 +1188,14 @@ class Article { function unprotect() { - return $this->protect( "" ); + return $this->protect( '' ); } # UI entry point for page deletion function delete() { - global $wgUser, $wgOut, $wgMessageCache, $wgRequest; - $fname = "Article::delete"; + global $wgUser, $wgOut, $wgMessageCache, $wgRequest, $wgIsPg; + $fname = 'Article::delete'; $confirm = $wgRequest->getBool( 'wpConfirm' ) && $wgRequest->wasPosted(); $reason = $wgRequest->getText( 'wpReason' ); @@ -1026,10 +1212,10 @@ class Article { } # Better double-check that it hasn't been deleted yet! - $wgOut->setPagetitle( wfMsg( "confirmdelete" ) ); - if ( ( "" == trim( $this->mTitle->getText() ) ) + $wgOut->setPagetitle( wfMsg( 'confirmdelete' ) ); + if ( ( '' == trim( $this->mTitle->getText() ) ) or ( $this->mTitle->getArticleId() == 0 ) ) { - $wgOut->fatalError( wfMsg( "cannotdelete" ) ); + $wgOut->fatalError( wfMsg( 'cannotdelete' ) ); return; } @@ -1044,12 +1230,13 @@ class Article { $ns = $this->mTitle->getNamespace(); $title = $this->mTitle->getDBkey(); $etitle = wfStrencode( $title ); - $sql = "SELECT old_text,old_flags FROM old WHERE old_namespace=$ns and old_title='$etitle' ORDER BY inverse_timestamp LIMIT 1"; + $oldtable=$wgIsPg?'"old"':'old'; + $sql = "SELECT old_text,old_flags FROM $oldtable WHERE old_namespace=$ns and old_title='$etitle' ORDER BY inverse_timestamp LIMIT 1"; $res = wfQuery( $sql, DB_READ, $fname ); if( ($old=wfFetchObject($res)) && !$confirm ) { $skin=$wgUser->getSkin(); - $wgOut->addHTML("<b>".wfMsg("historywarning")); - $wgOut->addHTML( $skin->historyLink() ."</b>"); + $wgOut->addHTML('<b>'.wfMsg('historywarning')); + $wgOut->addHTML( $skin->historyLink() .'</b>'); } $sql="SELECT cur_text FROM cur WHERE cur_namespace=$ns and cur_title='$etitle'"; @@ -1074,31 +1261,31 @@ class Article { # 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 = wfMsg("exblank"); + if($length == 0 && $reason === '') { + $reason = wfMsg('exblank'); } - if($length < 500 && $reason === "") { + if($length < 500 && $reason === '') { # comment field=255, let's grep the first 150 to have some user # space left $text=substr($text,0,150); # let's strip out newlines and HTML tags - $text=preg_replace("/\"/","'",$text); - $text=preg_replace("/\</","<",$text); - $text=preg_replace("/\>/",">",$text); - $text=preg_replace("/[\n\r]/","",$text); + $text=preg_replace('/\"/',"'",$text); + $text=preg_replace('/\</','<',$text); + $text=preg_replace('/\>/','>',$text); + $text=preg_replace("/[\n\r]/",'',$text); if(!$blanked) { - $reason=wfMsg("excontent"). " '".$text; + $reason=wfMsg('excontent'). " '".$text; } else { - $reason=wfMsg("exbeforeblank") . " '".$text; + $reason=wfMsg('exbeforeblank') . " '".$text; } - if($length>150) { $reason .= "..."; } # we've only pasted part of the text + if($length>150) { $reason .= '...'; } # we've only pasted part of the text $reason.="'"; } } - return $this->confirmDelete( "", $reason ); + return $this->confirmDelete( '', $reason ); } # Output deletion confirmation dialog @@ -1109,15 +1296,15 @@ class Article { wfDebug( "Article::confirmDelete\n" ); $sub = htmlspecialchars( $this->mTitle->getPrefixedText() ); - $wgOut->setSubtitle( wfMsg( "deletesub", $sub ) ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); - $wgOut->addWikiText( wfMsg( "confirmdeletetext" ) ); + $wgOut->setSubtitle( wfMsg( 'deletesub', $sub ) ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->addWikiText( wfMsg( 'confirmdeletetext' ) ); - $formaction = $this->mTitle->escapeLocalURL( "action=delete" . $par ); + $formaction = $this->mTitle->escapeLocalURL( 'action=delete' . $par ); - $confirm = htmlspecialchars( wfMsg( "confirm" ) ); - $check = htmlspecialchars( wfMsg( "confirmcheck" ) ); - $delcom = htmlspecialchars( wfMsg( "deletecomment" ) ); + $confirm = htmlspecialchars( wfMsg( 'confirm' ) ); + $check = htmlspecialchars( wfMsg( 'confirmcheck' ) ); + $delcom = htmlspecialchars( wfMsg( 'deletecomment' ) ); $wgOut->addHTML( " <form id='deleteconfirm' method='post' action=\"{$formaction}\"> @@ -1157,26 +1344,26 @@ class Article { function doDelete( $reason ) { global $wgOut, $wgUser, $wgLang; - $fname = "Article::doDelete"; + $fname = 'Article::doDelete'; wfDebug( "$fname\n" ); if ( $this->doDeleteArticle( $reason ) ) { $deleted = $this->mTitle->getPrefixedText(); - $wgOut->setPagetitle( wfMsg( "actioncomplete" ) ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); + $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); $sk = $wgUser->getSkin(); $loglink = $sk->makeKnownLink( $wgLang->getNsText( Namespace::getWikipedia() ) . - ":" . wfMsg( "dellogpage" ), wfMsg( "deletionlog" ) ); + ':' . wfMsg( 'dellogpage' ), wfMsg( 'deletionlog' ) ); $text = wfMsg( "deletedtext", $deleted, $loglink ); - $wgOut->addHTML( "<p>" . $text . "</p>\n" ); + $wgOut->addHTML( '<p>' . $text . "</p>\n" ); $wgOut->returnToMain( false ); } else { - $wgOut->fatalError( wfMsg( "cannotdelete" ) ); + $wgOut->fatalError( wfMsg( 'cannotdelete' ) ); } } @@ -1188,14 +1375,14 @@ class Article { global $wgUser, $wgLang; global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer; - $fname = "Article::doDeleteArticle"; - wfDebug( "$fname\n" ); + $fname = 'Article::doDeleteArticle'; + wfDebug( $fname."\n" ); $ns = $this->mTitle->getNamespace(); $t = wfStrencode( $this->mTitle->getDBkey() ); $id = $this->mTitle->getArticleID(); - if ( "" == $t || $id == 0 ) { + if ( '' == $t || $id == 0 ) { return false; } @@ -1208,7 +1395,7 @@ class Article { if ( $wgUseSquid ) { $urls = array( $this->mTitle->getInternalURL(), - $this->mTitle->getInternalURL( "history" ) + $this->mTitle->getInternalURL( 'history' ) ); foreach ( $linksTo as $linkTo ) { $urls[] = $linkTo->getInternalURL(); @@ -1223,17 +1410,17 @@ class Article { Title::touchArray( $linksTo ); # Move article and history to the "archive" table - $sql = "INSERT INTO archive (ar_namespace,ar_title,ar_text," . - "ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit," . - "ar_flags) SELECT cur_namespace,cur_title,cur_text,cur_comment," . - "cur_user,cur_user_text,cur_timestamp,cur_minor_edit,0 FROM cur " . + $sql = 'INSERT INTO archive (ar_namespace,ar_title,ar_text,' . + 'ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit,' . + 'ar_flags) SELECT cur_namespace,cur_title,cur_text,cur_comment,' . + 'cur_user,cur_user_text,cur_timestamp,cur_minor_edit,0 FROM cur ' . "WHERE cur_namespace={$ns} AND cur_title='{$t}'"; wfQuery( $sql, DB_WRITE, $fname ); - $sql = "INSERT INTO archive (ar_namespace,ar_title,ar_text," . - "ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit," . - "ar_flags) SELECT old_namespace,old_title,old_text,old_comment," . - "old_user,old_user_text,old_timestamp,old_minor_edit,old_flags " . + $sql = 'INSERT INTO archive (ar_namespace,ar_title,ar_text,' . + 'ar_comment,ar_user,ar_user_text,ar_timestamp,ar_minor_edit,' . + 'ar_flags) SELECT old_namespace,old_title,old_text,old_comment,' . + 'old_user,old_user_text,old_timestamp,old_minor_edit,old_flags ' . "FROM old WHERE old_namespace={$ns} AND old_title='{$t}'"; wfQuery( $sql, DB_WRITE, $fname ); @@ -1256,11 +1443,11 @@ class Article { Article::onArticleDelete( $this->mTitle ); - $sql = "INSERT INTO brokenlinks (bl_from,bl_to) VALUES "; + $sql = 'INSERT INTO brokenlinks (bl_from,bl_to) VALUES '; $first = true; foreach ( $linksTo as $titleObj ) { - if ( ! $first ) { $sql .= ","; } + if ( ! $first ) { $sql .= ','; } $first = false; # Get article ID. Efficient because it was loaded into the cache by getLinksTo(). $linkID = $titleObj->getArticleID(); @@ -1285,9 +1472,9 @@ class Article { $sql = "DELETE FROM categorylinks WHERE cl_from={$id}"; wfQuery( $sql, DB_WRITE, $fname ); - $log = new LogPage( wfMsg( "dellogpage" ), wfMsg( "dellogpagetext" ) ); + $log = new LogPage( wfMsg( 'dellogpage' ), wfMsg( 'dellogpagetext' ) ); $art = $this->mTitle->getPrefixedText(); - $log->addEntry( wfMsg( "deletedarticle", $art ), $reason ); + $log->addEntry( wfMsg( 'deletedarticle', $art ), $reason ); # Clear the cached article id so the interface doesn't act like we exist $this->mTitle->resetArticleID( 0 ); @@ -1297,7 +1484,7 @@ class Article { function rollback() { - global $wgUser, $wgLang, $wgOut, $wgRequest; + global $wgUser, $wgLang, $wgOut, $wgRequest, $wgIsMySQL, $wgIsPg; if ( ! $wgUser->isSysop() ) { $wgOut->sysopRequired(); @@ -1316,11 +1503,12 @@ class Article { $n = $this->mTitle->getNamespace(); # Get the last editor - $sql = "SELECT cur_id,cur_user,cur_user_text,cur_comment FROM cur WHERE cur_title='{$tt}' AND cur_namespace={$n}"; + $sql = 'SELECT cur_id,cur_user,cur_user_text,cur_comment ' . + "FROM cur WHERE cur_title='{$tt}' AND cur_namespace={$n}"; $res = wfQuery( $sql, DB_READ ); if( ($x = wfNumRows( $res )) != 1 ) { # Something wrong - $wgOut->addHTML( wfMsg( "notanarticle" ) ); + $wgOut->addHTML( wfMsg( 'notanarticle' ) ); return; } $s = wfFetchObject( $res ); @@ -1328,48 +1516,51 @@ class Article { $uid = $s->cur_user; $pid = $s->cur_id; - $from = str_replace( '_', ' ', $wgRequest->getVal( "from" ) ); + $from = str_replace( '_', ' ', $wgRequest->getVal( 'from' ) ); if( $from != $s->cur_user_text ) { - $wgOut->setPageTitle(wfmsg("rollbackfailed")); - $wgOut->addWikiText( wfMsg( "alreadyrolled", + $wgOut->setPageTitle(wfmsg('rollbackfailed')); + $wgOut->addWikiText( wfMsg( 'alreadyrolled', htmlspecialchars( $this->mTitle->getPrefixedText()), htmlspecialchars( $from ), htmlspecialchars( $s->cur_user_text ) ) ); - if($s->cur_comment != "") { + if($s->cur_comment != '') { $wgOut->addHTML( - wfMsg("editcomment", + wfMsg('editcomment', htmlspecialchars( $s->cur_comment ) ) ); } return; } # Get the last edit not by this guy - $sql = "SELECT old_text,old_user,old_user_text,old_timestamp,old_flags - FROM old USE INDEX (name_title_timestamp) - WHERE old_namespace={$n} AND old_title='{$tt}' - AND (old_user <> {$uid} OR old_user_text <> '{$ut}') - ORDER BY inverse_timestamp LIMIT 1"; + + $use_index=$wgIsMySQL?"USE INDEX (name_title_timestamp)":""; + $oldtable=$wgIsPg?'"old"':'old'; + $sql = 'SELECT old_text,old_user,old_user_text,old_timestamp,old_flags ' . + "FROM $oldtable {$use_index} " . + "WHERE old_namespace={$n} AND old_title='{$tt}' " . + "AND (old_user <> {$uid} OR old_user_text <> '{$ut}') " . + 'ORDER BY inverse_timestamp LIMIT 1'; $res = wfQuery( $sql, DB_READ ); if( wfNumRows( $res ) != 1 ) { # Something wrong - $wgOut->setPageTitle(wfMsg("rollbackfailed")); - $wgOut->addHTML( wfMsg( "cantrollback" ) ); + $wgOut->setPageTitle(wfMsg('rollbackfailed')); + $wgOut->addHTML( wfMsg( 'cantrollback' ) ); return; } $s = wfFetchObject( $res ); if ( $bot ) { # Mark all reverted edits as bot - $sql = "UPDATE recentchanges SET rc_bot=1 WHERE - rc_cur_id=$pid AND rc_user=$uid AND rc_timestamp > '{$s->old_timestamp}'"; + $sql = 'UPDATE recentchanges SET rc_bot=1 WHERE ' . + "rc_cur_id=$pid AND rc_user=$uid AND rc_timestamp > '{$s->old_timestamp}'"; wfQuery( $sql, DB_WRITE, $fname ); } # Save it! - $newcomment = wfMsg( "revertpage", $s->old_user_text, $from ); - $wgOut->setPagetitle( wfMsg( "actioncomplete" ) ); - $wgOut->setRobotpolicy( "noindex,nofollow" ); - $wgOut->addHTML( "<h2>" . $newcomment . "</h2>\n<hr />\n" ); + $newcomment = wfMsg( 'revertpage', $s->old_user_text, $from ); + $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); + $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->addHTML( '<h2>' . $newcomment . "</h2>\n<hr />\n" ); $this->updateArticle( Article::getRevisionText( $s ), $newcomment, 1, $this->mTitle->userIsWatching(), $bot ); Article::onArticleEdit( $this->mTitle ); $wgOut->returnToMain( false ); @@ -1436,7 +1627,7 @@ class Article { global $wgLang, $wgOut; $td = $wgLang->timeanddate( $this->mTimestamp, true ); - $r = wfMsg( "revisionasof", $td ); + $r = wfMsg( 'revisionasof', $td ); $wgOut->setSubtitle( "({$r})" ); } @@ -1463,7 +1654,7 @@ class Article { $called = true; if($this->isFileCacheable()) { $touched = $this->mTouched; - if( $this->mTitle->getPrefixedDBkey() == wfMsg( "mainpage" ) ) { + if( $this->mTitle->getPrefixedDBkey() == wfMsg( 'mainpage' ) ) { # Expire the main page quicker $expire = wfUnix2Timestamp( time() - 3600 ); $touched = max( $expire, $touched ); @@ -1493,7 +1684,7 @@ class Article { and ($wgUser->getId() == 0) and (!$wgUser->getNewtalk()) and ($this->mTitle->getNamespace() != Namespace::getSpecial()) - and ($action == "view") + and ($action == 'view') and (!isset($oldid)) and (!isset($diff)) and (!isset($redirect)) @@ -1501,10 +1692,11 @@ class Article { and (!$this->mRedirectedFrom); } + # Loads cur_touched and returns a value indicating if it should be used function checkTouched() { $id = $this->getID(); - $sql = "SELECT cur_touched,cur_is_redirect FROM cur WHERE cur_id=$id"; - $res = wfQuery( $sql, DB_READ, "Article::checkTouched" ); + $sql = 'SELECT cur_touched,cur_is_redirect FROM cur WHERE cur_id='.$id; + $res = wfQuery( $sql, DB_READ, 'Article::checkTouched' ); if( $s = wfFetchObject( $res ) ) { $this->mTouched = $s->cur_touched; return !$s->cur_is_redirect; @@ -1512,15 +1704,64 @@ class Article { return false; } } - + + # Edit an article without doing all that other stuff + function quickEdit( $text, $comment = '', $minor = 0 ) { + global $wgUser, $wgMwRedir, $wgIsPg; + $fname = 'Article::quickEdit'; + wfProfileIn( $fname ); + + $ns = $this->mTitle->getNamespace(); + $dbkey = $this->mTitle->getDBkey(); + $encDbKey = wfStrencode( $dbkey ); + $timestamp = wfTimestampNow(); + + # Save to history + $oldtable=$wgIsPg?'"old"':'old'; + $sql = "INSERT INTO $oldtable (old_namespace,old_title,old_text,old_comment,old_user,old_user_text,old_timestamp,inverse_timestamp) + SELECT cur_namespace,cur_title,cur_text,cur_comment,cur_user,cur_user_text,cur_timestamp,99999999999999-cur_timestamp + FROM cur WHERE cur_namespace=$ns AND cur_title='$encDbKey'"; + wfQuery( $sql, DB_WRITE ); + + # Use the affected row count to determine if the article is new + $numRows = wfAffectedRows(); + + # Make an array of fields to be inserted + $fields = array( + 'cur_text' => $text, + 'cur_timestamp' => $timestamp, + 'cur_user' => $wgUser->getID(), + 'cur_user_text' => $wgUser->getName(), + 'inverse_timestamp' => wfInvertTimestamp( $timestamp ), + 'cur_comment' => $comment, + 'cur_is_redirect' => $wgMwRedir->matchStart( $text ) ? 1 : 0, + 'cur_minor_edit' => intval($minor), + 'cur_touched' => $timestamp, + ); + + if ( $numRows ) { + # Update article + $fields['cur_is_new'] = 0; + wfUpdateArray( 'cur', $fields, array( 'cur_namespace' => $ns, 'cur_title' => $dbkey ), $fname ); + } else { + # Insert new article + $fields['cur_is_new'] = 1; + $fields['cur_namespace'] = $ns; + $fields['cur_title'] = $dbkey; + $fields['cur_random'] = $rand = number_format( mt_rand() / mt_getrandmax(), 12, '.', '' ); + wfInsertArray( 'cur', $fields, $fname ); + } + wfProfileOut( $fname ); + } + /* static */ function incViewCount( $id ) { $id = intval( $id ); global $wgHitcounterUpdateFreq; if( $wgHitcounterUpdateFreq <= 1 ){ // - wfQuery("UPDATE cur SET cur_counter = cur_counter + 1 " . - "WHERE cur_id = $id", DB_WRITE); + wfQuery('UPDATE cur SET cur_counter = cur_counter + 1 ' . + 'WHERE cur_id = '.$id, DB_WRITE); return; } @@ -1536,25 +1777,25 @@ class Article { return; } - $res = wfQuery("SELECT COUNT(*) as n FROM hitcounter", DB_WRITE); + $res = wfQuery('SELECT COUNT(*) as n FROM hitcounter', DB_WRITE); $row = wfFetchObject( $res ); $rown = intval( $row->n ); if( $rown >= $wgHitcounterUpdateFreq ){ - wfProfileIn( "Article::incViewCount-collect" ); + wfProfileIn( 'Article::incViewCount-collect' ); $old_user_abort = ignore_user_abort( true ); - wfQuery("LOCK TABLES hitcounter WRITE", DB_WRITE); - wfQuery("CREATE TEMPORARY TABLE acchits TYPE=HEAP ". - "SELECT hc_id,COUNT(*) AS hc_n FROM hitcounter ". - "GROUP BY hc_id", DB_WRITE); - wfQuery("DELETE FROM hitcounter", DB_WRITE); - wfQuery("UNLOCK TABLES", DB_WRITE); - wfQuery("UPDATE cur,acchits SET cur_counter=cur_counter + hc_n ". - "WHERE cur_id = hc_id", DB_WRITE); - wfQuery("DROP TABLE acchits", DB_WRITE); + wfQuery('LOCK TABLES hitcounter WRITE', DB_WRITE); + wfQuery('CREATE TEMPORARY TABLE acchits TYPE=HEAP '. + 'SELECT hc_id,COUNT(*) AS hc_n FROM hitcounter '. + 'GROUP BY hc_id', DB_WRITE); + wfQuery('DELETE FROM hitcounter', DB_WRITE); + wfQuery('UNLOCK TABLES', DB_WRITE); + wfQuery('UPDATE cur,acchits SET cur_counter=cur_counter + hc_n '. + 'WHERE cur_id = hc_id', DB_WRITE); + wfQuery('DROP TABLE acchits', DB_WRITE); ignore_user_abort( $old_user_abort ); - wfProfileOut( "Article::incViewCount-collect" ); + wfProfileOut( 'Article::incViewCount-collect' ); } wfIgnoreSQLErrors( $oldignore ); } @@ -1567,7 +1808,7 @@ class Article { # This is called on page move and undelete, as well as edit /* static */ function onArticleCreate($title_obj){ - global $wgEnablePersistentLC, $wgEnableParserCache, $wgUseSquid, $wgDeferredUpdateList; + global $wgUseSquid, $wgDeferredUpdateList; $titles = $title_obj->getBrokenLinksTo(); @@ -1582,34 +1823,15 @@ class Article { } # Clear persistent link cache - if ( $wgEnablePersistentLC ) { - LinkCache::linksccClearBrokenLinksTo( $title_obj->getPrefixedDBkey() ); - } - - # Clear parser cache (not really used) - if ( $wgEnableParserCache ) { - OutputPage::parsercacheClearBrokenLinksTo( $title_obj->getPrefixedDBkey() ); - } + LinkCache::linksccClearBrokenLinksTo( $title_obj->getPrefixedDBkey() ); } /* static */ function onArticleDelete($title_obj){ - global $wgEnablePersistentLC, $wgEnableParserCache; - if ( $wgEnablePersistentLC ) { - LinkCache::linksccClearLinksTo( $title_obj->getArticleID() ); - } - if ( $wgEnableParserCache ) { - OutputPage::parsercacheClearLinksTo( $title_obj->getArticleID() ); - } + LinkCache::linksccClearLinksTo( $title_obj->getArticleID() ); } /* static */ function onArticleEdit($title_obj){ - global $wgEnablePersistentLC, $wgEnableParserCache; - if ( $wgEnablePersistentLC ) { - LinkCache::linksccClearPage( $title_obj->getArticleID() ); - } - if ( $wgEnableParserCache ) { - OutputPage::parsercacheClearPage( $title_obj->getArticleID(), $title_obj->getNamespace() ); - } + LinkCache::linksccClearPage( $title_obj->getArticleID() ); } } diff --git a/includes/Block.php b/includes/Block.php index d98b07baebb7..e8a53e0efdd3 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -15,8 +15,8 @@ class Block /* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry; /* private */ var $mNetworkBits, $mIntegerAddr; - function Block( $address = "", $user = "", $by = 0, $reason = "", - $timestamp = "" , $auto = 0, $expiry = "" ) + function Block( $address = '', $user = '', $by = 0, $reason = '', + $timestamp = '' , $auto = 0, $expiry = '' ) { $this->mAddress = $address; $this->mUser = $user; @@ -38,18 +38,22 @@ class Block function clear() { - $mAddress = $mReason = $mTimestamp = ""; + $mAddress = $mReason = $mTimestamp = ''; $mUser = $mBy = 0; } # Get a ban from the DB, with either the given address or the given username - function load( $address, $user = 0, $killExpired = true ) + function load( $address = "", $user = 0, $killExpired = true ) { - $fname = "Block::load"; + $fname = 'Block::load'; $ret = false; $killed = false; - if ( 0 == $user ) { + if ( 0 == $user && $address=="" ) { + $sql = "SELECT * from ipblocks"; + } elseif ($address=="") { + $sql = "SELECT * FROM ipblocks WHERE ipb_user={$user}"; + } elseif ($user=="") { $sql = "SELECT * FROM ipblocks WHERE ipb_address='" . wfStrencode( $address ) . "'"; } else { $sql = "SELECT * FROM ipblocks WHERE (ipb_address='" . wfStrencode( $address ) . @@ -109,7 +113,7 @@ class Block function initialiseRange() { if ( $this->mUser == 0 ) { - $rangeParts = explode( "/", $this->mAddress ); + $rangeParts = explode( '/', $this->mAddress ); if ( count( $rangeParts ) == 2 ) { $this->mNetworkBits = $rangeParts[1]; } else { @@ -125,8 +129,8 @@ class Block # Callback with a Block object for every block /*static*/ function enumBlocks( $callback, $tag, $killExpired = true ) { - $sql = "SELECT * FROM ipblocks ORDER BY ipb_timestamp DESC"; - $res = wfQuery( $sql, DB_READ, "Block::enumBans" ); + $sql = 'SELECT * FROM ipblocks ORDER BY ipb_timestamp DESC'; + $res = wfQuery( $sql, DB_READ, 'Block::enumBans' ); $block = new Block(); while ( $row = wfFetchObject( $res ) ) { @@ -144,25 +148,25 @@ class Block function delete() { - $fname = "Block::delete"; + $fname = 'Block::delete'; if ( $this->mAddress == "" ) { $sql = "DELETE FROM ipblocks WHERE ipb_id={$this->mId}"; } else { $sql = "DELETE FROM ipblocks WHERE ipb_address='" . wfStrencode( $this->mAddress ) . "'"; } - wfQuery( $sql, DB_WRITE, "Block::delete" ); + wfQuery( $sql, DB_WRITE, 'Block::delete' ); $this->clearCache(); } function insert() { - $sql = "INSERT INTO ipblocks - (ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry ) - VALUES ('" . wfStrencode( $this->mAddress ) . "', {$this->mUser}, {$this->mBy}, '" . + $sql = 'INSERT INTO ipblocks ' . + '(ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry )' . + "VALUES ('" . wfStrencode( $this->mAddress ) . "', {$this->mUser}, {$this->mBy}, '" . wfStrencode( $this->mReason ) . "','{$this->mTimestamp}', {$this->mAuto}, '{$this->mExpiry}')"; - wfQuery( $sql, DB_WRITE, "Block::insert" ); + wfQuery( $sql, DB_WRITE, 'Block::insert' ); $this->clearCache(); } @@ -188,7 +192,7 @@ class Block function isValid() { - return $this->mAddress != ""; + return $this->mAddress != ''; } function updateTimestamp() @@ -197,10 +201,10 @@ class Block $this->mTimestamp = wfTimestampNow(); $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp ); - wfQuery( "UPDATE ipblocks SET " . + wfQuery( 'UPDATE ipblocks SET ' . "ipb_timestamp='" . $this->mTimestamp . "', " . "ipb_expiry='" . $this->mExpiry . "' " . - "WHERE ipb_address='" . wfStrencode( $this->mAddress ) . "'", DB_WRITE, "Block::updateTimestamp" ); + "WHERE ipb_address='" . wfStrencode( $this->mAddress ) . "'", DB_WRITE, 'Block::updateTimestamp' ); $this->clearCache(); } @@ -232,7 +236,7 @@ class Block /* static */ function normaliseRange( $range ) { - $parts = explode( "/", $range ); + $parts = explode( '/', $range ); if ( count( $parts ) == 2 ) { $shift = 32 - $parts[1]; $ipint = ip2long( $parts[0] ); diff --git a/includes/BlockCache.php b/includes/BlockCache.php index 5b65bdc20a56..8b49a0142c13 100644 --- a/includes/BlockCache.php +++ b/includes/BlockCache.php @@ -7,15 +7,15 @@ class BlockCache { var $mData = false, $mMemcKey; - function BlockCache( $deferLoad = false, $dbName = "" ) + function BlockCache( $deferLoad = false, $dbName = '' ) { global $wgDBname; - if ( $dbName == "" ) { + if ( $dbName == '' ) { $dbName = $wgDBname; } - $this->mMemcKey = "$dbName:ipblocks"; + $this->mMemcKey = $dbName.':ipblocks'; if ( !$deferLoad ) { $this->load(); @@ -36,10 +36,10 @@ class BlockCache } } - if ( $this->mData === false || is_null( $this->mData ) ) { + if ( !is_array( $this->mData ) ) { # Load from DB $this->mData = array(); - Block::enumBlocks( "wfBlockCacheInsert", "" ); # Calls $this->insert() + Block::enumBlocks( 'wfBlockCacheInsert', '' ); # Calls $this->insert() } if ( $saveMemc ) { @@ -78,7 +78,7 @@ class BlockCache if ( $blocked ) { # Clear low order bits if ( $networkBits != 32 ) { - $ip .= "/$networkBits"; + $ip .= '/'.$networkBits; $ip = Block::normaliseRange( $ip ); } $block = new Block(); diff --git a/includes/CacheManager.php b/includes/CacheManager.php index 5ba6ec7318e4..e85f69d94bc7 100644 --- a/includes/CacheManager.php +++ b/includes/CacheManager.php @@ -11,14 +11,14 @@ # $wgFileCacheDirectory # $wgUseGzip -require_once( "Title.php" ); +require_once( 'Title.php' ); class CacheManager { var $mTitle, $mFileCache; function CacheManager( &$title ) { $this->mTitle =& $title; - $this->mFileCache = ""; + $this->mFileCache = ''; } function fileCacheName() { @@ -27,14 +27,14 @@ class CacheManager { $hash = md5( $key = $this->mTitle->getDbkey() ); if( $this->mTitle->getNamespace() ) $key = $wgLang->getNsText( $this->mTitle->getNamespace() ) . ":" . $key; - $key = str_replace( ".", "%2E", urlencode( $key ) ); + $key = str_replace( '.', '%2E', urlencode( $key ) ); $hash1 = substr( $hash, 0, 1 ); $hash2 = substr( $hash, 0, 2 ); $this->mFileCache = "{$wgFileCacheDirectory}/{$hash1}/{$hash2}/{$key}.html"; if($this->useGzip()) - $this->mFileCache .= ".gz"; + $this->mFileCache .= '.gz'; wfDebug( " fileCacheName() - {$this->mFileCache}\n" ); } @@ -75,7 +75,7 @@ class CacheManager { function fetchPageText() { if( $this->useGzip() ) { /* Why is there no gzfile_get_contents() or gzdecode()? */ - return implode( "", gzfile( $this->fileCacheName() ) ); + return implode( '', gzfile( $this->fileCacheName() ) ); } else { return $this->fetchRawText(); } @@ -91,7 +91,7 @@ class CacheManager { if( $this->useGzip() ) { if( wfClientAcceptsGzip() ) { - header( "Content-Encoding: gzip" ); + header( 'Content-Encoding: gzip' ); } else { /* Send uncompressed */ readgzfile( $filename ); @@ -103,38 +103,38 @@ class CacheManager { function checkCacheDirs() { $filename = $this->fileCacheName(); - $mydir2=substr($filename,0,strrpos($filename,"/")); # subdirectory level 2 - $mydir1=substr($mydir2,0,strrpos($mydir2,"/")); # subdirectory level 1 + $mydir2=substr($filename,0,strrpos($filename,'/')); # subdirectory level 2 + $mydir1=substr($mydir2,0,strrpos($mydir2,'/')); # subdirectory level 1 if(!file_exists($mydir1)) { mkdir($mydir1,0775); } # create if necessary if(!file_exists($mydir2)) { mkdir($mydir2,0775); } } function saveToFileCache( $text ) { - if(strcmp($text,"") == 0) return ""; + if(strcmp($text,'') == 0) return ''; wfDebug(" saveToFileCache()\n", false); $this->checkCacheDirs(); - $f = fopen( $this->fileCacheName(), "w" ); + $f = fopen( $this->fileCacheName(), 'w' ); if($f) { $now = wfTimestampNow(); if( $this->useGzip() ) { - $rawtext = str_replace( "</html>", - "<!-- Cached/compressed $now -->\n</html>", + $rawtext = str_replace( '</html>', + '<!-- Cached/compressed '.$now." -->\n</html>", $text ); $text = gzencode( $rawtext ); } else { - $text = str_replace( "</html>", - "<!-- Cached $now -->\n</html>", + $text = str_replace( '</html>', + '<!-- Cached '.$now." -->\n</html>", $text ); } fwrite( $f, $text ); fclose( $f ); if( $this->useGzip() ) { if( wfClientAcceptsGzip() ) { - header( "Content-Encoding: gzip" ); + header( 'Content-Encoding: gzip' ); return $text; } else { return $rawtext; diff --git a/includes/Database.php b/includes/Database.php index d84625492f8e..f3824858133f 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -1,11 +1,10 @@ <?php -require_once( "FulltextStoplist.php" ); +# $Id$ +# This file deals with MySQL interface functions +# and query specifics/optimisations +# require_once( "CacheManager.php" ); -define( "DB_READ", -1 ); -define( "DB_WRITE", -2 ); -define( "DB_LAST", -3 ); - define( "LIST_COMMA", 0 ); define( "LIST_AND", 1 ); define( "LIST_SET", 2 ); @@ -36,7 +35,7 @@ class Database { # Output page, used for reporting errors # FALSE means discard output - function &setOutputPage( &$out ) { return wfSetRef( $this->mOut, $out ); } + function &setOutputPage( &$out ) { $this->mOut =& $out; } # Boolean, controls output of large amounts of debug information function setDebug( $debug ) { return wfSetVar( $this->mDebug, $debug ); } @@ -90,6 +89,12 @@ class Database { { global $wgEmergencyContact; + # Test for missing mysql.so + # Otherwise we get a suppressed fatal error, which is very hard to track down + if ( !function_exists( 'mysql_connect' ) ) { + die( "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" ); + } + $this->close(); $this->mServer = $server; $this->mUser = $user; @@ -140,10 +145,11 @@ class Database { { if ( $this->mFailFunction ) { if ( !is_int( $this->mFailFunction ) ) { - $this->$mFailFunction( $this ); + $ff = $this->mFailFunction; + $ff( $this, mysql_error() ); } } else { - wfEmergencyAbort( $this ); + wfEmergencyAbort( $this, mysql_error() ); } } @@ -151,7 +157,7 @@ class Database { # If errors are explicitly ignored, returns success function query( $sql, $fname = "" ) { - global $wgProfiling; + global $wgProfiling, $wgCommandLineMode; if ( $wgProfiling ) { # generalizeSQL will probably cut down the query to reasonable @@ -174,13 +180,21 @@ class Database { } if ( false === $ret ) { + $error = mysql_error( $this->mConn ); + $errno = mysql_errno( $this->mConn ); if( $this->mIgnoreErrors ) { - wfDebug("SQL ERROR (ignored): " . mysql_error( $this->mConn ) . "\n"); + wfDebug("SQL ERROR (ignored): " . $error . "\n"); } else { - wfDebug("SQL ERROR: " . mysql_error( $this->mConn ) . "\n"); - if ( $this->mOut ) { + wfDebug("SQL ERROR: " . $error . "\n"); + if ( $wgCommandLineMode ) { + wfDebugDieBacktrace( "A database error has occurred\n" . + "Query: $sql\n" . + "Function: $fname\n" . + "Error: $errno $error\n" + ); + } elseif ( $this->mOut ) { // this calls wfAbruptExit() - $this->mOut->databaseError( $fname, $this ); + $this->mOut->databaseError( $fname, $sql, $error, $errno ); } } } @@ -204,6 +218,15 @@ class Database { } return $row; } + + function fetchRow( $res ) { + @$row = mysql_fetch_array( $res ); + if (mysql_errno() ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( mysql_error() ) ); + } + return $row; + } + function numRows( $res ) { @$n = mysql_num_rows( $res ); if( mysql_errno() ) { @@ -254,8 +277,12 @@ class Database { function getArray( $table, $vars, $conds, $fname = "Database::getArray" ) { $vars = implode( ",", $vars ); - $where = Database::makeList( $conds, LIST_AND ); - $sql = "SELECT $vars FROM $table WHERE $where LIMIT 1"; + if ( $conds !== false ) { + $where = Database::makeList( $conds, LIST_AND ); + $sql = "SELECT $vars FROM $table WHERE $where LIMIT 1"; + } else { + $sql = "SELECT $vars FROM $table LIMIT 1"; + } $res = $this->query( $sql, $fname ); if ( $res === false || !$this->numRows( $res ) ) { return false; @@ -314,7 +341,10 @@ class Database { # If errors are explicitly ignored, returns NULL on failure function indexExists( $table, $index, $fname = "Database::indexExists" ) { - $sql = "SHOW INDEXES FROM $table"; + # SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not. + # SHOW INDEX should work for 3.x and up: + # http://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html + $sql = "SHOW INDEX FROM $table"; $res = $this->query( $sql, DB_READ, $fname ); if ( !$res ) { return NULL; @@ -334,6 +364,7 @@ class Database { function tableExists( $table ) { $old = $this->mIgnoreErrors; + $this->mIgnoreErrors = true; $res = $this->query( "SELECT 1 FROM $table LIMIT 1" ); $this->mIgnoreErrors = $old; if( $res ) { @@ -441,12 +472,18 @@ class Database { /* Standard fail function, called by default when a connection cannot be established Displays the file cache if possible */ -function wfEmergencyAbort( &$conn ) { +function wfEmergencyAbort( &$conn, $error ) { global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding, $wgSiteNotice, $wgOutputEncoding; - header( "Content-type: text/html; charset=$wgOutputEncoding" ); + if( !headers_sent() ) { + header( "HTTP/1.0 500 Internal Server Error" ); + header( "Content-type: text/html; charset=$wgOutputEncoding" ); + /* Don't cache error pages! They cause no end of trouble... */ + header( "Cache-control: none" ); + header( "Pragma: nocache" ); + } $msg = $wgSiteNotice; - if($msg == "") $msg = wfMsgNoDB( "noconnect" ); + if($msg == "") $msg = wfMsgNoDB( "noconnect", $error ); $text = $msg; if($wgUseFileCache) { @@ -478,9 +515,6 @@ function wfEmergencyAbort( &$conn ) { } } - /* Don't cache error pages! They cause no end of trouble... */ - header( "Cache-control: none" ); - header( "Pragma: nocache" ); echo $text; wfAbruptExit(); } @@ -515,4 +549,9 @@ function wfInvertTimestamp( $ts ) { "9876543210" ); } + +function wfLimitResult( $limit, $offset ) { + return " LIMIT ".(is_numeric($offset)?"{$offset},":"")."{$limit} "; +} + ?> diff --git a/includes/DatabaseFunctions.php b/includes/DatabaseFunctions.php index 90bb40f19370..0169b9ff5eb3 100644 --- a/includes/DatabaseFunctions.php +++ b/includes/DatabaseFunctions.php @@ -1,4 +1,5 @@ <?php +# $Id$ # Backwards compatibility wrapper for Database.php @@ -7,53 +8,55 @@ # the load balancer will finally call Database, which will # represent a single connection -# NB: This file follows a connect on demand scheme. Do -# not access the $wgDatabase variable directly unless -# you intend to set it. Use wfGetDB(). +# Note: $wgDatabase has ceased to exist. Destroy all references. + +$wgIsMySQL=false; +$wgIsPg=false; + +if ($wgDBtype=="mysql") { + require_once( "Database.php" ); + $wgIsMySQL=true; +} elseif ($wgDBtype=="pgsql") { + require_once( "DatabasePostgreSQL.php" ); + $wgIsPg=true; +} -require_once( "Database.php" ); -# Query the database -# $db: DB_READ = -1 read from slave (or only server) -# DB_WRITE = -2 write to master (or only server) -# 0,1,2,... query a database with a specific index -# Replication is not actually implemented just yet # Usually aborts on failure # If errors are explicitly ignored, returns success function wfQuery( $sql, $db, $fname = "" ) { - global $wgDatabase, $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, - $wgDebugDumpSql, $wgBufferSQLResults, $wgIgnoreSQLErrors; - + global $wgOut; if ( !is_numeric( $db ) ) { # Someone has tried to call this the old way $wgOut->fatalError( wfMsgNoDB( "wrong_wfQuery_params", $db, $sql ) ); } - - $db =& wfGetDB(); - return $db->query( $sql, $fname ); + $c =& wfGetDB( $db ); + if ( $c !== false ) { + return $c->query( $sql, $fname ); + } else { + return false; + } } -# Connect on demand -function &wfGetDB() +function &wfGetDB( $db = DB_LAST ) { - global $wgDatabase, $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, - $wgDebugDumpSql, $wgBufferSQLResults, $wgIgnoreSQLErrors; - if ( !$wgDatabase ) { - $wgDatabase = Database::newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, - $wgDBname, false, $wgDebugDumpSql, $wgBufferSQLResults, $wgIgnoreSQLErrors ); - } - return $wgDatabase; + global $wgLoadBalancer; + return $wgLoadBalancer->getConnection( $db ); } # Turns buffering of SQL result sets on (true) or off (false). Default is # "on" and it should not be changed without good reasons. # Returns the previous state. -function wfBufferSQLResults( $newstate ) +function wfBufferSQLResults( $newstate, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->setBufferResults( $newstate ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->setBufferResults( $newstate ); + } else { + return NULL; + } } # Turns on (false) or off (true) the automatic generation and sending @@ -63,117 +66,206 @@ function wfBufferSQLResults( $newstate ) # situation as appropriate. # Returns the previous state. -function wfIgnoreSQLErrors( $newstate ) +function wfIgnoreSQLErrors( $newstate, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->setIgnoreErrors( $newstate ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->setIgnoreErrors( $newstate ); + } else { + return NULL; + } } -function wfFreeResult( $res ) +function wfFreeResult( $res, $dbi = DB_LAST ) { - $db =& wfGetDB(); - $db->freeResult( $res ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + $db->freeResult( $res ); + return true; + } else { + return false; + } } -function wfFetchObject( $res ) +function wfFetchObject( $res, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->fetchObject( $res ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->fetchObject( $res, $dbi = DB_LAST ); + } else { + return false; + } +} + +function wfFetchRow( $res, $dbi = DB_LAST ) +{ + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->fetchRow ( $res, $dbi = DB_LAST ); + } else { + return false; + } } -function wfNumRows( $res ) +function wfNumRows( $res, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->numRows( $res ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->numRows( $res, $dbi = DB_LAST ); + } else { + return false; + } } -function wfNumFields( $res ) +function wfNumFields( $res, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->numFields( $res ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->numFields( $res ); + } else { + return false; + } } -function wfFieldName( $res, $n ) +function wfFieldName( $res, $n, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->fieldName( $res, $n ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->fieldName( $res, $n, $dbi = DB_LAST ); + } else { + return false; + } } -function wfInsertId() +function wfInsertId( $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->insertId(); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->insertId(); + } else { + return false; + } } -function wfDataSeek( $res, $row ) + +function wfDataSeek( $res, $row, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->dataSeek( $res, $row ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->dataSeek( $res, $row ); + } else { + return false; + } } -function wfLastErrno() +function wfLastErrno( $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->lastErrno(); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->lastErrno(); + } else { + return false; + } } -function wfLastError() +function wfLastError( $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->lastError(); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->lastError(); + } else { + return false; + } } -function wfAffectedRows() +function wfAffectedRows( $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->affectedRows(); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->affectedRows(); + } else { + return false; + } } -function wfLastDBquery() +function wfLastDBquery( $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->lastQuery(); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->lastQuery(); + } else { + return false; + } } -function wfSetSQL( $table, $var, $value, $cond ) +function wfSetSQL( $table, $var, $value, $cond, $dbi = DB_WRITE ) { - $db =& wfGetDB(); - return $db->set( $table, $var, $value, $cond ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->set( $table, $var, $value, $cond ); + } else { + return false; + } } -function wfGetSQL( $table, $var, $cond ) +function wfGetSQL( $table, $var, $cond="", $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->get( $table, $var, $cond ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->get( $table, $var, $cond ); + } else { + return false; + } } -function wfFieldExists( $table, $field ) +function wfFieldExists( $table, $field, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->fieldExists( $table, $field ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->fieldExists( $table, $field ); + } else { + return false; + } } -function wfIndexExists( $table, $index ) +function wfIndexExists( $table, $index, $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->indexExists( $table, $index ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->indexExists( $table, $index ); + } else { + return false; + } } -function wfInsertArray( $table, $array ) +function wfInsertArray( $table, $array, $fname = "wfInsertArray", $dbi = DB_WRITE ) { - $db =& wfGetDB(); - return $db->insertArray( $table, $array ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->insertArray( $table, $array, $fname ); + } else { + return false; + } } -function wfGetArray( $table, $vars, $conds, $fname = "wfGetArray" ) +function wfGetArray( $table, $vars, $conds, $fname = "wfGetArray", $dbi = DB_LAST ) { - $db =& wfGetDB(); - return $db->getArray( $table, $vars, $conds, $fname ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + return $db->getArray( $table, $vars, $conds, $fname ); + } else { + return false; + } } -function wfUpdateArray( $table, $values, $conds, $fname = "wfUpdateArray" ) +function wfUpdateArray( $table, $values, $conds, $fname = "wfUpdateArray", $dbi = DB_WRITE ) { - $db =& wfGetDB(); - $db->updateArray( $table, $values, $conds, $fname ); + $db =& wfGetDB( $dbi ); + if ( $db !== false ) { + $db->updateArray( $table, $values, $conds, $fname ); + return true; + } else { + return false; + } } ?> diff --git a/includes/DatabasePostgreSQL.php b/includes/DatabasePostgreSQL.php new file mode 100644 index 000000000000..f9add198cc75 --- /dev/null +++ b/includes/DatabasePostgreSQL.php @@ -0,0 +1,549 @@ +<?php +# $Id$ +# +# DO NOT USE !!! Unless you want to help developping it. +# +# This file is an attempt to port the mysql database layer to postgreSQL. The +# only thing done so far is s/mysql/pg/ and dieing if function haven't been +# ported. +# +# As said brion 07/06/2004 : +# "table definitions need to be changed. fulltext index needs to work differently +# things that use the last insert id need to be changed. Probably other things +# need to be changed. various semantics may be different." +# +# Hashar + +require_once( "FulltextStoplist.php" ); +require_once( "CacheManager.php" ); + +define( "DB_READ", -1 ); +define( "DB_WRITE", -2 ); +define( "DB_LAST", -3 ); + +define( "LIST_COMMA", 0 ); +define( "LIST_AND", 1 ); +define( "LIST_SET", 2 ); + +class Database { + +#------------------------------------------------------------------------------ +# Variables +#------------------------------------------------------------------------------ + /* private */ var $mLastQuery = ""; + /* private */ var $mBufferResults = true; + /* private */ var $mIgnoreErrors = false; + + /* private */ var $mServer, $mUser, $mPassword, $mConn, $mDBname; + /* private */ var $mOut, $mDebug, $mOpened = false; + + /* private */ var $mFailFunction; + /* private */ var $mLastResult; + +#------------------------------------------------------------------------------ +# Accessors +#------------------------------------------------------------------------------ + # Set functions + # These set a variable and return the previous state + + # Fail function, takes a Database as a parameter + # Set to false for default, 1 for ignore errors + function setFailFunction( $function ) { return wfSetVar( $this->mFailFunction, $function ); } + + # Output page, used for reporting errors + # FALSE means discard output + function &setOutputPage( &$out ) { $this->mOut =& $out; } + + # Boolean, controls output of large amounts of debug information + function setDebug( $debug ) { return wfSetVar( $this->mDebug, $debug ); } + + # Turns buffering of SQL result sets on (true) or off (false). Default is + # "on" and it should not be changed without good reasons. + function setBufferResults( $buffer ) { return wfSetVar( $this->mBufferResults, $buffer ); } + + # Turns on (false) or off (true) the automatic generation and sending + # of a "we're sorry, but there has been a database error" page on + # database errors. Default is on (false). When turned off, the + # code should use wfLastErrno() and wfLastError() to handle the + # situation as appropriate. + function setIgnoreErrors( $ignoreErrors ) { return wfSetVar( $this->mIgnoreErrors, $ignoreErrors ); } + + # Get functions + + function lastQuery() { return $this->mLastQuery; } + function isOpen() { return $this->mOpened; } + +#------------------------------------------------------------------------------ +# Other functions +#------------------------------------------------------------------------------ + + function Database() + { + global $wgOut; + # Can't get a reference if it hasn't been set yet + if ( !isset( $wgOut ) ) { + $wgOut = NULL; + } + $this->mOut =& $wgOut; + + } + + /* static */ function newFromParams( $server, $user, $password, $dbName, + $failFunction = false, $debug = false, $bufferResults = true, $ignoreErrors = false ) + { + $db = new Database; + $db->mFailFunction = $failFunction; + $db->mIgnoreErrors = $ignoreErrors; + $db->mDebug = $debug; + $db->mBufferResults = $bufferResults; + $db->open( $server, $user, $password, $dbName ); + return $db; + } + + # Usually aborts on failure + # If the failFunction is set to a non-zero integer, returns success + function open( $server, $user, $password, $dbName ) + { + global $wgEmergencyContact; + + $this->close(); + $this->mServer = $server; + $this->mUser = $user; + $this->mPassword = $password; + $this->mDBname = $dbName; + + $success = false; + + + if ( "" != $dbName ) { + # start a database connection + @$this->mConn = pg_connect("host=$server dbname=$dbName user=$user password=$password"); + if ( $this->mConn == false ) { + wfDebug( "DB connection error\n" ); + wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" ); + wfDebug( $this->lastError()."\n" ); + } else { + $this->mOpened = true; + } + } + return $this->mConn; + } + + # Closes a database connection, if it is open + # Returns success, true if already closed + function close() + { + $this->mOpened = false; + if ( $this->mConn ) { + return pg_close( $this->mConn ); + } else { + return true; + } + } + + /* private */ function reportConnectionError( $msg = "") + { + if ( $this->mFailFunction ) { + if ( !is_int( $this->mFailFunction ) ) { + $this->$mFailFunction( $this ); + } + } else { + wfEmergencyAbort( $this ); + } + } + + # Usually aborts on failure + # If errors are explicitly ignored, returns success + function query( $sql, $fname = "" ) + { + global $wgProfiling; + + if ( $wgProfiling ) { + # generalizeSQL will probably cut down the query to reasonable + # logging size most of the time. The substr is really just a sanity check. + $profName = "query: " . substr( Database::generalizeSQL( $sql ), 0, 255 ); + wfProfileIn( $profName ); + } + + $this->mLastQuery = $sql; + + if ( $this->mDebug ) { + $sqlx = substr( $sql, 0, 500 ); + $sqlx = wordwrap(strtr($sqlx,"\t\n"," ")); + wfDebug( "SQL: $sqlx\n" ); + } + + $ret = pg_query( $this->mConn , $sql); + $this->mLastResult = $ret; + if ( false == $ret ) { + $error = pg_last_error( $this->mConn ); + // TODO FIXME : no error number function in postgre + // $errno = mysql_errno( $this->mConn ); + if( $this->mIgnoreErrors ) { + wfDebug("SQL ERROR (ignored): " . $error . "\n"); + } else { + wfDebug("SQL ERROR: " . $error . "\n"); + if ( $this->mOut ) { + // this calls wfAbruptExit() + $this->mOut->databaseError( $fname, $sql, $error, 0 ); + } + } + } + + if ( $wgProfiling ) { + wfProfileOut( $profName ); + } + return $ret; + } + + function freeResult( $res ) { + if ( !@pg_free_result( $res ) ) { + wfDebugDieBacktrace( "Unable to free PostgreSQL result\n" ); + } + } + function fetchObject( $res ) { + @$row = pg_fetch_object( $res ); + # FIXME: HACK HACK HACK HACK debug + + # TODO: + # hashar : not sure if the following test really trigger if the object + # fetching failled. + if( pg_last_error($this->mConn) ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( pg_last_error($this->mConn) ) ); + } + return $row; + } + + function fetchRow( $res ) { + @$row = pg_fetch_array( $res ); + if( pg_last_error($this->mConn) ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( pg_last_error($this->mConn) ) ); + } + return $row; + } + + function numRows( $res ) { + @$n = pg_num_rows( $res ); + if( pg_last_error($this->mConn) ) { + wfDebugDieBacktrace( "SQL error: " . htmlspecialchars( pg_last_error($this->mConn) ) ); + } + return $n; + } + function numFields( $res ) { return pg_num_fields( $res ); } + function fieldName( $res, $n ) { return pg_field_name( $res, $n ); } + // TODO FIXME: need to implement something here + function insertId() { + //return mysql_insert_id( $this->mConn ); + wfDebugDieBacktrace( "Database::insertId() error : not implemented for postgre, use sequences" ); + } + function dataSeek( $res, $row ) { return pg_result_seek( $res, $row ); } + function lastErrno() { return $this->lastError(); } + function lastError() { return pg_last_error(); } + function affectedRows() { + return pg_affected_rows( $this->mLastResult ); + } + + # Simple UPDATE wrapper + # Usually aborts on failure + # If errors are explicitly ignored, returns success + function set( $table, $var, $value, $cond, $fname = "Database::set" ) + { + $sql = "UPDATE \"$table\" SET \"$var\" = '" . + wfStrencode( $value ) . "' WHERE ($cond)"; + return !!$this->query( $sql, DB_WRITE, $fname ); + } + + # Simple SELECT wrapper, returns a single field, input must be encoded + # Usually aborts on failure + # If errors are explicitly ignored, returns FALSE on failure + function get( $table, $var, $cond, $fname = "Database::get" ) + { + $from=$table?" FROM \"$table\" ":""; + $where=$cond?" WHERE ($cond)":""; + + $sql = "SELECT $var $from $where"; + + $result = $this->query( $sql, DB_READ, $fname ); + + $ret = ""; + if ( pg_num_rows( $result ) > 0 ) { + $s = pg_fetch_array( $result ); + $ret = $s[0]; + pg_free_result( $result ); + } + return $ret; + } + + # More complex SELECT wrapper, single row only + # Aborts or returns FALSE on error + # Takes an array of selected variables, and a condition map, which is ANDed + # e.g. getArray( "cur", array( "cur_id" ), array( "cur_namespace" => 0, "cur_title" => "Astronomy" ) ) + # would return an object where $obj->cur_id is the ID of the Astronomy article + function getArray( $table, $vars, $conds, $fname = "Database::getArray" ) + { + $vars = implode( ",", $vars ); + $where = Database::makeList( $conds, LIST_AND ); + $sql = "SELECT \"$vars\" FROM \"$table\" WHERE $where LIMIT 1"; + $res = $this->query( $sql, $fname ); + if ( $res === false || !$this->numRows( $res ) ) { + return false; + } + $obj = $this->fetchObject( $res ); + $this->freeResult( $res ); + return $obj; + } + + # Removes most variables from an SQL query and replaces them with X or N for numbers. + # It's only slightly flawed. Don't use for anything important. + /* static */ function generalizeSQL( $sql ) + { + # This does the same as the regexp below would do, but in such a way + # as to avoid crashing php on some large strings. + # $sql = preg_replace ( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql); + + $sql = str_replace ( "\\\\", "", $sql); + $sql = str_replace ( "\\'", "", $sql); + $sql = str_replace ( "\\\"", "", $sql); + $sql = preg_replace ("/'.*'/s", "'X'", $sql); + $sql = preg_replace ('/".*"/s', "'X'", $sql); + + # All newlines, tabs, etc replaced by single space + $sql = preg_replace ( "/\s+/", " ", $sql); + + # All numbers => N + $sql = preg_replace ('/-?[0-9]+/s', "N", $sql); + + return $sql; + } + + # Determines whether a field exists in a table + # Usually aborts on failure + # If errors are explicitly ignored, returns NULL on failure + function fieldExists( $table, $field, $fname = "Database::fieldExists" ) + { + $res = $this->query( "DESCRIBE '$table'", DB_READ, $fname ); + if ( !$res ) { + return NULL; + } + + $found = false; + + while ( $row = $this->fetchObject( $res ) ) { + if ( $row->Field == $field ) { + $found = true; + break; + } + } + return $found; + } + + # Determines whether an index exists + # Usually aborts on failure + # If errors are explicitly ignored, returns NULL on failure + function indexExists( $table, $index, $fname = "Database::indexExists" ) + { + $sql = "SELECT indexname FROM pg_indexes WHERE tablename='$table'"; + $res = $this->query( $sql, DB_READ, $fname ); + if ( !$res ) { + return NULL; + } + + $found = false; + + while ( $row = $this->fetchObject( $res ) ) { + if ( $row->Key_name == $index ) { + $found = true; + break; + } + } + return $found; + } + + function tableExists( $table ) + { + $old = $this->mIgnoreErrors; + $this->mIgnoreErrors = true; + $res = $this->query( "SELECT 1 FROM '$table' LIMIT 1" ); + $this->mIgnoreErrors = $old; + if( $res ) { + $this->freeResult( $res ); + return true; + } else { + return false; + } + } + + function fieldInfo( $table, $field ) + { + $res = $this->query( "SELECT * FROM '$table' LIMIT 1" ); + $n = pg_num_fields( $res ); + for( $i = 0; $i < $n; $i++ ) { + // FIXME + wfDebugDieBacktrace( "Database::fieldInfo() error : mysql_fetch_field() not implemented for postgre" ); + $meta = mysql_fetch_field( $res, $i ); + if( $field == $meta->name ) { + return $meta; + } + } + return false; + } + + # INSERT wrapper, inserts an array into a table + # Keys are field names, values are values + # Usually aborts on failure + # If errors are explicitly ignored, returns success + function insertArray( $table, $a, $fname = "Database::insertArray" ) + { + $sql1 = "INSERT INTO \"$table\" ("; + $sql2 = "VALUES (" . Database::makeList( $a ); + $first = true; + foreach ( $a as $field => $value ) { + if ( !$first ) { + $sql1 .= ","; + } + $first = false; + $sql1 .= $field; + } + $sql = "$sql1) $sql2)"; + return !!$this->query( $sql, $fname ); + } + + # A cross between insertArray and getArray, takes a condition array and a SET array + function updateArray( $table, $values, $conds, $fname = "Database::updateArray" ) + { + $sql = "UPDATE '$table' SET " . $this->makeList( $values, LIST_SET ); + $sql .= " WHERE " . $this->makeList( $conds, LIST_AND ); + $this->query( $sql, $fname ); + } + + # Makes a wfStrencoded list from an array + # $mode: LIST_COMMA - comma separated, no field names + # LIST_AND - ANDed WHERE clause (without the WHERE) + # LIST_SET - comma separated with field names, like a SET clause + /* static */ function makeList( $a, $mode = LIST_COMMA ) + { + $first = true; + $list = ""; + foreach ( $a as $field => $value ) { + if ( !$first ) { + if ( $mode == LIST_AND ) { + $list .= " AND "; + } else { + $list .= ","; + } + } else { + $first = false; + } + if ( $mode == LIST_AND || $mode == LIST_SET ) { + $list .= "$field="; + } + if ( !is_numeric( $value ) ) { + $list .= "'" . wfStrencode( $value ) . "'"; + } else { + $list .= $value; + } + } + return $list; + } + + function startTimer( $timeout ) + { + global $IP; + wfDebugDieBacktrace( "Database::startTimer() error : mysql_thread_id() not implemented for postgre" ); + $tid = mysql_thread_id( $this->mConn ); + exec( "php $IP/killthread.php $timeout $tid &>/dev/null &" ); + } + + function stopTimer() + { + } + +} + +#------------------------------------------------------------------------------ +# Global functions +#------------------------------------------------------------------------------ + +/* Standard fail function, called by default when a connection cannot be established + Displays the file cache if possible */ +function wfEmergencyAbort( &$conn ) { + global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding, $wgSiteNotice, $wgOutputEncoding; + + header( "Content-type: text/html; charset=$wgOutputEncoding" ); + $msg = $wgSiteNotice; + if($msg == "") $msg = wfMsgNoDB( "noconnect" ); + $text = $msg; + + if($wgUseFileCache) { + if($wgTitle) { + $t =& $wgTitle; + } else { + if($title) { + $t = Title::newFromURL( $title ); + } elseif (@$_REQUEST['search']) { + $search = $_REQUEST['search']; + echo wfMsgNoDB( "searchdisabled" ); + echo wfMsgNoDB( "googlesearch", htmlspecialchars( $search ), $wgInputEncoding ); + wfAbruptExit(); + } else { + $t = Title::newFromText( wfMsgNoDB( "mainpage" ) ); + } + } + + $cache = new CacheManager( $t ); + if( $cache->isFileCached() ) { + $msg = "<p style='color: red'><b>$msg<br />\n" . + wfMsgNoDB( "cachederror" ) . "</b></p>\n"; + + $tag = "<div id='article'>"; + $text = str_replace( + $tag, + $tag . $msg, + $cache->fetchPageText() ); + } + } + + /* Don't cache error pages! They cause no end of trouble... */ + header( "Cache-control: none" ); + header( "Pragma: nocache" ); + echo $text; + wfAbruptExit(); +} + +function wfStrencode( $s ) +{ + return pg_escape_string( $s ); +} + +# Use PostgreSQL timestamp without timezone data type +function wfTimestamp2Unix( $ts ) { + return gmmktime( ( (int)substr( $ts, 11, 2) ), + (int)substr( $ts, 14, 2 ), (int)substr( $ts, 17, 2 ), + (int)substr( $ts, 5, 2 ), (int)substr( $ts, 8, 2 ), + (int)substr( $ts, 0, 4 ) ); +} + +function wfUnix2Timestamp( $unixtime ) { + return gmdate( "Y-m-d H:i:s", $unixtime ); +} + +function wfTimestampNow() { + # return NOW + return gmdate( "Y-m-d H:i:s" ); +} + +# Sorting hack for MySQL 3, which doesn't use index sorts for DESC +function wfInvertTimestamp( $ts ) { + $ts=preg_replace("/\D/","",$ts); + return strtr( + $ts, + "0123456789", + "9876543210" + ); +} + +function wfLimitResult( $limit, $offset ) { + return " LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":""); +} + +?> diff --git a/includes/DateFormatter.php b/includes/DateFormatter.php index e903f53daa79..45196512f5fe 100755 --- a/includes/DateFormatter.php +++ b/includes/DateFormatter.php @@ -18,7 +18,7 @@ define("DF_LAST", 8); class DateFormatter { var $mSource, $mTarget; - var $monthNames = "", $rxDM, $rxMD, $rxDMY, $rxYDM, $rxMDY, $rxYMD; + var $monthNames = '', $rxDM, $rxMD, $rxDMY, $rxYDM, $rxMDY, $rxYMD; var $regexes, $pDays, $pMonths, $pYears; var $rules, $xMonths; @@ -58,24 +58,24 @@ class DateFormatter # Extraction keys # See the comments in replace() for the meaning of the letters - $this->keys[DF_DMY] = "jFY"; - $this->keys[DF_YDM] = "Y jF"; - $this->keys[DF_MDY] = "FjY"; - $this->keys[DF_YMD] = "Y Fj"; - $this->keys[DF_DM] = "jF"; - $this->keys[DF_MD] = "Fj"; - $this->keys[DF_ISO1] = "ymd"; # y means ISO year - $this->keys[DF_ISO2] = "ymd"; + $this->keys[DF_DMY] = 'jFY'; + $this->keys[DF_YDM] = 'Y jF'; + $this->keys[DF_MDY] = 'FjY'; + $this->keys[DF_YMD] = 'Y Fj'; + $this->keys[DF_DM] = 'jF'; + $this->keys[DF_MD] = 'Fj'; + $this->keys[DF_ISO1] = 'ymd'; # y means ISO year + $this->keys[DF_ISO2] = 'ymd'; # Target date formats - $this->targets[DF_DMY] = "[[F j|j F]] [[Y]]"; - $this->targets[DF_YDM] = "[[Y]], [[F j|j F]]"; - $this->targets[DF_MDY] = "[[F j]], [[Y]]"; - $this->targets[DF_YMD] = "[[Y]] [[F j]]"; - $this->targets[DF_DM] = "[[F j|j F]]"; - $this->targets[DF_MD] = "[[F j]]"; - $this->targets[DF_ISO1] = "[[Y|y]]-[[F j|m-d]]"; - $this->targets[DF_ISO2] = "[[y-m-d]]"; + $this->targets[DF_DMY] = '[[F j|j F]] [[Y]]'; + $this->targets[DF_YDM] = '[[Y]], [[F j|j F]]'; + $this->targets[DF_MDY] = '[[F j]], [[Y]]'; + $this->targets[DF_YMD] = '[[Y]] [[F j]]'; + $this->targets[DF_DM] = '[[F j|j F]]'; + $this->targets[DF_MD] = '[[F j]]'; + $this->targets[DF_ISO1] = '[[Y|y]]-[[F j|m-d]]'; + $this->targets[DF_ISO2] = '[[y-m-d]]'; # Rules # pref source target @@ -103,7 +103,7 @@ class DateFormatter # Default $this->mTarget = $i; } - $text = preg_replace_callback( $this->regexes[$i], "wfMainDateReplace", $text ); + $text = preg_replace_callback( $this->regexes[$i], 'wfMainDateReplace', $text ); } return $text; } @@ -123,7 +123,7 @@ class DateFormatter $format = $this->targets[$this->mTarget]; # Construct new date - $text = ""; + $text = ''; $fail = false; for ( $p=0; $p < strlen( $format ); $p++ ) { @@ -131,7 +131,7 @@ class DateFormatter switch ( $char ) { case 'd': # ISO day of month if ( is_null($bits['d']) ) { - $text .= sprintf( "%02d", $bits['j'] ); + $text .= sprintf( '%02d', $bits['j'] ); } else { $text .= $bits['d']; } @@ -139,7 +139,7 @@ class DateFormatter case 'm': # ISO month if ( is_null($bits['m']) ) { $m = $this->makeIsoMonth( $bits['F'] ); - if ( !$m || $m == "00" ) { + if ( !$m || $m == '00' ) { $fail = true; } else { $text .= $m; @@ -194,14 +194,14 @@ class DateFormatter function getMonthRegex() { global $wgMonthNamesEn; - return implode( "|", $wgMonthNamesEn ); + return implode( '|', $wgMonthNamesEn ); } # Makes an ISO month, e.g. 02, from a month name function makeIsoMonth( $monthName ) { $n = $this->xMonths[strtolower( $monthName )]; - return sprintf( "%02d", $n ); + return sprintf( '%02d', $n ); } function makeIsoYear( $year ) @@ -210,10 +210,10 @@ class DateFormatter if ( substr( $year, -2 ) == 'BC' ) { $num = IntVal(substr( $year, 0, -3 )) - 1; # PHP bug note: sprintf( "%04d", -1 ) fails poorly - $text = sprintf( "-%04d", $num ); + $text = sprintf( '-%04d', $num ); } else { - $text = sprintf( "%04d", $year ); + $text = sprintf( '%04d', $year ); } return $text; } @@ -221,7 +221,7 @@ class DateFormatter function makeNormalYear( $iso ) { if ( $iso{0} == '-' ) { - $text = (IntVal( substr( $iso, 1 ) ) - 1) . " BC"; + $text = (IntVal( substr( $iso, 1 ) ) - 1) . ' BC'; } else { $text = IntVal( $iso ); } diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 52eb0b1ef1d8..0eaf809ba8ce 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -1,4 +1,5 @@ <?php +# $Id$ # DO NOT EDIT THIS FILE! # To customize your installation, edit "LocalSettings.php". # Note that since all these string interpolations are expanded @@ -6,27 +7,27 @@ # like $wgScriptPath, you must also localize everything that # depends on it. -$wgVersion = "1.3.0beta1"; +$wgVersion = '1.3.0beta4'; -$wgSitename = "MediaWiki"; # Please customize! +$wgSitename = 'MediaWiki'; # Please customize! $wgMetaNamespace = FALSE; # will be same as you set $wgSitename # check if server use https: -$wgProto = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") ? "https" : "http"; +$wgProto = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; if ( @$wgCommandLineMode ) { - $wgServer = $wgProto."://localhost"; + $wgServer = $wgProto.'://localhost'; } else { - $wgServer = $wgProto."://" . $_SERVER["SERVER_NAME"]; - if( $_SERVER["SERVER_PORT"] != 80 ) $wgServer .= ":" . $_SERVER["SERVER_PORT"]; + $wgServer = $wgProto.'://' . $_SERVER['SERVER_NAME']; + if( $_SERVER['SERVER_PORT'] != 80 ) $wgServer .= ":" . $_SERVER['SERVER_PORT']; } unset($wgProto); -$wgScriptPath = "/wiki"; +$wgScriptPath = '/wiki'; # Whether to support URLs like index.php/Page_title -$wgUsePathInfo = ( strpos( php_sapi_name(), "cgi" ) === false ); +$wgUsePathInfo = ( strpos( php_sapi_name(), 'cgi' ) === false ); # ATTN: Old installations used wiki.phtml and redirect.phtml - # make sure that LocalSettings.php is correctly set! @@ -44,25 +45,30 @@ $wgLogo = "{$wgUploadPath}/wiki.png"; $wgMathPath = "{$wgUploadPath}/math"; $wgMathDirectory = "{$wgUploadDirectory}/math"; $wgTmpDirectory = "{$wgUploadDirectory}/tmp"; -$wgEmergencyContact = "wikiadmin@" . getenv( "SERVER_NAME" ); -$wgPasswordSender = "Wikipedia Mail <apache@" . getenv( "SERVER_NAME" ) . ">"; +$wgEmergencyContact = 'wikiadmin@' . getenv( 'SERVER_NAME' ); +$wgPasswordSender = 'Wikipedia Mail <apache@' . getenv( 'SERVER_NAME' ) . '>'; # For using a direct (authenticated) SMTP server connection. # "host" => 'SMTP domain', "IDHost" => 'domain for MessageID', "port" => "25", "auth" => true/false, "username" => user, "password" => password $wgSMTP = false; -# MySQL settings +# Database settings # -$wgDBserver = "localhost"; -$wgDBname = "wikidb"; -$wgDBconnection = ""; -$wgDBuser = "wikiuser"; +$wgDBserver = 'localhost'; +$wgDBname = 'wikidb'; +$wgDBconnection = ''; +$wgDBuser = 'wikiuser'; +$wgDBtype = "mysql"; # "mysql" for working code and "pgsql" for development/broken code + +# Database load balancer +$wgDBservers = false; # e.g. array(0 => "larousse", 1 => "pliny") +$wgDBloads = false; # e.g. array(0 => 0.6, 1 => 0.4); # Sysop SQL queries $wgAllowSysopQueries = false; # Dangerous if not configured properly. -$wgDBsqluser = "sqluser"; -$wgDBsqlpassword = "sqlpass"; -$wgDBpassword = "userpass"; +$wgDBsqluser = 'sqluser'; +$wgDBsqlpassword = 'sqlpass'; +$wgDBpassword = 'userpass'; $wgSqlLogFile = "{$wgUploadDirectory}/sqllog_mFhyRe6"; $wgDBminWordLen = 4; @@ -85,27 +91,28 @@ $wgDBloads = false; # e.g. array(0.6, 0.4); # $wgMemCachedDebug = false; # Will be set to false in Setup.php, if the server isn't working $wgUseMemCached = false; -$wgMemCachedServers = array( "127.0.0.1:11000" ); +$wgMemCachedServers = array( '127.0.0.1:11000' ); $wgMemCachedDebug = false; $wgSessionsInMemcached = false; $wgLinkCacheMemcached = false; # Not fully tested # Language settings # -$wgLanguageCode = "en"; +$wgLanguageCode = 'en'; $wgLanguageFile = false; # Filename of a language file generated by dumpMessages.php $wgInterwikiMagic = true; # Treat language links as magic connectors, not inline links -$wgInputEncoding = "ISO-8859-1"; -$wgOutputEncoding = "ISO-8859-1"; -$wgEditEncoding = ""; -$wgMimeType = "text/html"; -$wgDocType = "-//W3C//DTD XHTML 1.0 Transitional//EN"; -$wgDTD = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"; +$wgInputEncoding = 'ISO-8859-1'; # LanguageUtf8.php normally overrides this +$wgOutputEncoding = 'ISO-8859-1'; # unless you set the next option to true: +$wgUseLatin1 = false; # Enable ISO-8859-1 compatibility mode +$wgEditEncoding = ''; +$wgMimeType = 'text/html'; +$wgDocType = '-//W3C//DTD XHTML 1.0 Transitional//EN'; +$wgDTD = 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'; $wgUseDynamicDates = false; # Enable to allow rewriting dates in page text # DOES NOT FORMAT CORRECTLY FOR MOST LANGUAGES $wgAmericanDates = false; # Enable for English module to print dates # as eg 'May 12' instead of '12 May' -$wgLocalInterwiki = "w"; +$wgLocalInterwiki = 'w'; $wgShowIPinHeader = true; # For non-logged in users $wgMaxNameChars = 32; # Maximum number of bytes in username $wgInterwikiExpiry = 10800; # Expiry time for cache of interwiki table @@ -115,8 +122,8 @@ $wgInterwikiExpiry = 10800; # Expiry time for cache of interwiki table $wgUseDatabaseMessages = true; $wgMsgCacheExpiry = 86400; -$wgExtraSubtitle = ""; -$wgSiteSupportPage = ""; +$wgExtraSubtitle = ''; +$wgSiteSupportPage = ''; # Miscellaneous configuration settings # @@ -124,7 +131,7 @@ $wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR"; # The debug log file should be not be publicly accessible if it is # used, as it may contain private data. -$wgDebugLogFile = ""; +$wgDebugLogFile = ''; $wgDebugRedirects = false; $wgDebugComments = false; @@ -142,6 +149,11 @@ $wgIgnoreSQLErrors = false; # all articles in the category) $wgUseCategoryMagic = true; +# disable experimental dmoz-like category browsing. Output things like: +# Encyclopedia > Music > Style of Music > Jazz +# FIXME: need fixing +$wgUseCategoryBrowser = false; + $wgEnablePersistentLC = false; # Persistent link cache in linkscc table; FAILS on MySQL 3.x $wgCompressedPersistentLC = true; # use gzcompressed blobs @@ -158,24 +170,26 @@ $wgHitcounterUpdateFreq = 1; # User rights $wgWhitelistEdit = false; # true = user must login to edit. $wgWhitelistRead = false; # Pages anonymous user may see, like: = array ( ":Main_Page", "Special:Userlogin", "Wikipedia:Help"); -$wgWhitelistAccount = array ( "user" => 1, "sysop" => 1, "developer" => 1 ); +$wgWhitelistAccount = array ( 'user' => 1, 'sysop' => 1, 'developer' => 1 ); $wgSysopUserBans = false; # Allow sysops to ban logged-in users $wgSysopRangeBans = false; # Allow sysops to ban IP ranges -$wgDefaultBlockExpiry = "24 hours"; # default expiry time +$wgDefaultBlockExpiry = '24 hours'; # default expiry time # strtotime format, or "infinite" for an infinite block $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire $wgBlockOpenProxies = false; # Automatic open proxy test on edit $wgProxyPorts = array( 80, 81, 1080, 3128, 6588, 8000, 8080, 8888, 65506 ); $wgProxyScriptPath = "$IP/proxy_check.php"; $wgProxyMemcExpiry = 86400; -$wgProxyKey = "W1svekXc5u6lZllTZOwnzEk1nbs"; +$wgProxyKey = 'W1svekXc5u6lZllTZOwnzEk1nbs'; +$wgProxyList = array(); # big list of banned IP addresses, in the keys not the values +$wgAccountCreationThrottle = 0; # Number of accounts each IP address may create, 0 to disable. Requires memcached # Client-side caching: $wgCachePages = true; # Allow client-side caching of pages # Set this to current time to invalidate all prior cached pages. # Affects both client- and server-side caching. -$wgCacheEpoch = "20030516000000"; +$wgCacheEpoch = '20030516000000'; # Server-side caching: # This will cache static pages for non-logged-in users @@ -205,8 +219,8 @@ $wgCookieExpiration = 2592000; # Set to set an explicit domain on the login cookies # eg, "justthis.domain.org" or ".any.subdomain.net" -$wgCookieDomain = ""; -$wgCookiePath = "/"; +$wgCookieDomain = ''; +$wgCookiePath = '/'; $wgDisableCookieCheck = false; $wgAllowExternalImages = true; @@ -220,18 +234,7 @@ $wgWLCacheTimeout = 3600; # The hour or so mentioned above # convert (ImageMagick) installed and available in the PATH. # Please see math/README for more information. $wgUseTeX = false; -$wgTexvc = "./math/texvc"; # Location of the texvc binary - -# Support for inline hieroglyphs, see http://aoineko.free.fr/ The -# WikiHiero php files must be present in the same directory as the -# rest of the mediawiki code, and WikiHiero must have been configured -# with the correct image locations. -$wgUseWikiHiero = false; - -# Support for inline timelines, see http://members.chello.nl/epzachte/Wikipedia/EasyTimeline/Introduction.htm -# The Timeline php files must be present in the extension directory and you must have the -# ploticus tool available, see http://ploticus.sourceforge.net/ -$wgUseTimeline = false; +$wgTexvc = './math/texvc'; # Location of the texvc binary # Profiling / debugging $wgProfiling = false; # Enable for more detailed by-function times in debug log @@ -253,11 +256,11 @@ $wgDisableAnonTalk = false; # We can serve pages compressed in order to save bandwidth, # but this will increase CPU usage. # Requires zlib support enabled in PHP. -$wgUseGzip = function_exists( "gzencode" ); +$wgUseGzip = function_exists( 'gzencode' ); # 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"; +$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. @@ -267,18 +270,18 @@ $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", "jpg", "jpeg", "ogg" ); +$wgFileExtensions = array( 'png', 'jpg', 'jpeg', 'ogg' ); # Files with these extensions will never be allowed as uploads. $wgFileBlacklist = array( # HTML may contain cookie-stealing JavaScript and web bugs - "html", "htm", + 'html', 'htm', # PHP scripts may execute arbitrary code on the server - "php", "phtml", "php3", "php4", "phps", + 'php', 'phtml', 'php3', 'php4', 'phps', # Other types that may be interpreted by some servers - "shtml", "jhtml", "pl", "py", + 'shtml', 'jhtml', 'pl', 'py', # May contain harmful executables for Windows victims - "exe", "scr", "dll", "msi", "vbs", "bat", "com", "pif", "cmd", "vxd", "cpl" ); + 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl' ); # This is a flag to determine whether or not to check file extensions on # upload. @@ -288,6 +291,9 @@ $wgCheckFileExtensions = true; # covered by $wgFileExtensions. $wgStrictFileExtensions = true; +# Warn if uploaded files are larger than this +$wgUploadSizeWarning = 150000; + $wgPasswordSalt = true; # For compatibility with old installations set to false # Which namespaces should support subpages? @@ -318,7 +324,7 @@ $wgUseImageResize = false; ## of the builtin functions # $wgUseImageMagick = false; -$wgImageMagickConvertCommand = "/usr/bin/convert"; +$wgImageMagickConvertCommand = '/usr/bin/convert'; # PHPTal is a library for page templates. MediaWiki includes # a recent PHPTal distribution. It is required to use the @@ -332,6 +338,9 @@ if( !isset( $wgCommandLineMode ) ) { # Show seconds in Recent Changes $wgRCSeconds = false; +# Log IP addresses in the recentchanges table +$wgPutIPinRC = false; + # RDF metadata toggles $wgEnableDublinCoreRdf = false; $wgEnableCreativeCommonsRdf = false; @@ -343,6 +352,14 @@ $wgRightsUrl = NULL; $wgRightsText = NULL; $wgRightsIcon = 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 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 @@ -364,6 +381,8 @@ $wgMaxCredits = 0; # Text matching this regular expression will be recognised as spam # See http://en.wikipedia.org/wiki/Regular_expression $wgSpamRegex = false; +# Similarly if this function returns true +$wgFilterCallback = false; # Go button goes straight to the edit screen if the article doesn't exist $wgGoToEdit = false; @@ -388,8 +407,12 @@ $wgTidyConf = $IP.'/extensions/tidy/tidy.conf'; $wgTidyOpts = ''; # See list of skins and their symbolic names in language/Language.php -$wgDefaultSkin = "monobook"; +$wgDefaultSkin = 'monobook'; + +# Whether or not to allow real name fields. Defaults to true. +$wgAllowRealName = true; # Extensions $wgExtensionFunctions = array(); + ?> diff --git a/includes/DifferenceEngine.php b/includes/DifferenceEngine.php index 4ba5b7713d8d..2e3937ee4802 100644 --- a/includes/DifferenceEngine.php +++ b/includes/DifferenceEngine.php @@ -18,7 +18,9 @@ class DifferenceEngine { function showDiffPage() { global $wgUser, $wgTitle, $wgOut, $wgLang; - + $fname = "DifferenceEngine::showDiffPage"; + wfProfileIn( $fname ); + $t = $wgTitle->getPrefixedText() . " (Diff: {$this->mOldid}, " . "{$this->mNewid})"; $mtext = wfMsg( "missingarticle", $t ); @@ -27,6 +29,7 @@ class DifferenceEngine { if ( ! $this->loadText() ) { $wgOut->setPagetitle( wfMsg( "errorpagetitle" ) ); $wgOut->addHTML( $mtext ); + wfProfileOut( $fname ); return; } $wgOut->suppressQuickbar(); @@ -44,6 +47,7 @@ class DifferenceEngine { if ( !( $this->mOldPage->userCanRead() && $this->mNewPage->userCanRead() ) ) { $wgOut->loginToUse(); $wgOut->output(); + wfProfileOut( $fname ); exit; } @@ -80,6 +84,8 @@ class DifferenceEngine { $oldHeader, $newHeader ); $wgOut->addHTML( "<hr /><h2>{$this->mNewtitle}</h2>\n" ); $wgOut->addWikiText( $this->mNewtext ); + + wfProfileOut( $fname ); } function showDiff( $otext, $ntext, $otitle, $ntitle ) @@ -112,9 +118,10 @@ cellpadding='0' cellspacing='4px' class='diff'><tr> # function loadText() { - global $wgTitle, $wgOut, $wgLang; + global $wgTitle, $wgOut, $wgLang, $wgIsMySQL, $wgIsPg; $fname = "DifferenceEngine::loadText"; + $oldtable=$wgIsPg?'"old"':'old'; if ( 0 == $this->mNewid || 0 == $this->mOldid ) { $wgOut->setArticleFlag( true ); $this->mNewtitle = wfMsg( "currentrev" ); @@ -130,7 +137,7 @@ cellpadding='0' cellspacing='4px' class='diff'><tr> $this->mNewUser = $s->cur_user_text; $this->mNewComment = $s->cur_comment; } else { - $sql = "SELECT old_namespace,old_title,old_timestamp,old_text,old_flags,old_user_text,old_comment FROM old WHERE " . + $sql = "SELECT old_namespace,old_title,old_timestamp,old_text,old_flags,old_user_text,old_comment FROM $oldtable WHERE " . "old_id={$this->mNewid}"; $res = wfQuery( $sql, DB_READ, $fname ); @@ -146,14 +153,15 @@ cellpadding='0' cellspacing='4px' class='diff'><tr> $this->mNewComment = $s->old_comment; } if ( 0 == $this->mOldid ) { + $use_index=$wgIsMySQL?"USE INDEX (name_title_timestamp)":""; $sql = "SELECT old_namespace,old_title,old_timestamp,old_text,old_flags,old_user_text,old_comment " . - "FROM old USE INDEX (name_title_timestamp) WHERE " . + "FROM $oldtable $use_index WHERE " . "old_namespace=" . $this->mNewPage->getNamespace() . " AND " . "old_title='" . wfStrencode( $this->mNewPage->getDBkey() ) . "' ORDER BY inverse_timestamp LIMIT 1"; $res = wfQuery( $sql, DB_READ, $fname ); } else { - $sql = "SELECT old_namespace,old_title,old_timestamp,old_text,old_flags,old_user_text,old_comment FROM old WHERE " . + $sql = "SELECT old_namespace,old_title,old_timestamp,old_text,old_flags,old_user_text,old_comment FROM $oldtable WHERE " . "old_id={$this->mOldid}"; $res = wfQuery( $sql, DB_READ, $fname ); } @@ -1015,7 +1023,7 @@ class _HWLDF_WordAccumulator { function _flushGroup ($new_tag) { if ($this->_group !== '') { if ($this->_tag == 'mark') - $this->_line .= "<font color=\"red\">$this->_group</font>"; + $this->_line .= '<span class="diffchange">'.$this->_group.'</span>'; else $this->_line .= $this->_group; } @@ -1116,8 +1124,8 @@ class TableDiffFormatter extends DiffFormatter $l1 = wfMsg( "lineno", $xbeg ); $l2 = wfMsg( "lineno", $ybeg ); - $r = "<tr><td colspan='2' align='left'><strong>{$l1}</strong></td>\n" . - "<td colspan='2' align='left'><strong>{$l2}</strong></td></tr>\n"; + $r = '<tr><td colspan="2" align="left"><strong>'.$l1."</strong></td>\n" . + '<td colspan="2" align="left"><strong>'.$l2."</strong></td></tr>\n"; return $r; } @@ -1133,27 +1141,27 @@ class TableDiffFormatter extends DiffFormatter } function addedLine( $line ) { - return "<td>+</td><td class='diff-addedline'>" . - "<small>{$line}</small></td>"; + return '<td>+</td><td class="diff-addedline">' . + $line.'</td>'; } function deletedLine( $line ) { - return "<td>-</td><td class='diff-deletedline'>" . - "<small>{$line}</small></td>"; + return '<td>-</td><td class="diff-deletedline">' . + $line.'</td>'; } function emptyLine() { - return "<td colspan='2'> </td>"; + return '<td colspan="2"> </td>'; } function contextLine( $line ) { - return "<td> </td><td class='diff-context'><small>{$line}</small></td>"; + return '<td> </td><td class="diff-context">'.$line.'</td>'; } function _added($lines) { global $wgOut; foreach ($lines as $line) { - $wgOut->addHTML( "<tr>" . $this->emptyLine() . + $wgOut->addHTML( '<tr>' . $this->emptyLine() . $this->addedLine( $line ) . "</tr>\n" ); } } @@ -1161,7 +1169,7 @@ class TableDiffFormatter extends DiffFormatter function _deleted($lines) { global $wgOut; foreach ($lines as $line) { - $wgOut->addHTML( "<tr>" . $this->deletedLine( $line ) . + $wgOut->addHTML( '<tr>' . $this->deletedLine( $line ) . $this->emptyLine() . "</tr>\n" ); } } @@ -1169,7 +1177,7 @@ class TableDiffFormatter extends DiffFormatter function _context( $lines ) { global $wgOut; foreach ($lines as $line) { - $wgOut->addHTML( "<tr>" . $this->contextLine( $line ) . + $wgOut->addHTML( '<tr>' . $this->contextLine( $line ) . $this->contextLine( $line ) . "</tr>\n" ); } } @@ -1182,7 +1190,7 @@ class TableDiffFormatter extends DiffFormatter while ( $line = array_shift( $del ) ) { $aline = array_shift( $add ); - $wgOut->addHTML( "<tr>" . $this->deletedLine( $line ) . + $wgOut->addHTML( '<tr>' . $this->deletedLine( $line ) . $this->addedLine( $aline ) . "</tr>\n" ); } $this->_added( $add ); # If any leftovers diff --git a/includes/EditPage.php b/includes/EditPage.php index d9959ae39f97..2d779ac70efb 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -62,6 +62,7 @@ class EditPage { } function importFormData( &$request ) { + global $wgIsMySQL, $wgIsPg; # These fields need to be checked for encoding. # Also remove trailing whitespace, but don't remove _initial_ # whitespace from the text boxes. This may be significant formatting. @@ -70,7 +71,12 @@ class EditPage { $this->summary = trim( $request->getText( "wpSummary" ) ); $this->edittime = $request->getVal( 'wpEdittime' ); - if( !preg_match( '/^\d{14}$/', $this->edittime ) ) $this->edittime = ""; + if ($wgIsMySQL) + if( !preg_match( '/^\d{14}$/', $this->edittime )) $this->edittime = ""; + if ($wgIsPg) + if ( !preg_match( '/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/', + $this->edittime )) + $this->edittime = ""; $this->preview = $request->getCheck( 'wpPreview' ); $this->save = $request->wasPosted() && !$this->preview; @@ -108,7 +114,7 @@ class EditPage { global $wgLang, $wgParser, $wgTitle; global $wgAllowAnonymousMinor; global $wgWhitelistEdit; - global $wgSpamRegex; + global $wgSpamRegex, $wgFilterCallback; $sk = $wgUser->getSkin(); $isConflict = false; @@ -131,9 +137,12 @@ class EditPage { if ( "save" == $formtype ) { # Check for spam if ( $wgSpamRegex && preg_match( $wgSpamRegex, $this->textbox1 ) ) { - sleep(10); - $wgOut->redirect( $this->mTitle->getFullURL() ); - return; + $this->spamPage(); + return; + } + if ( $wgFilterCallback && $wgFilterCallback( $this->mTitle, $this->textbox1, $this->section ) ) { + # Error messages or other handling should be performed by the filter function + return; } if ( $wgUser->isBlocked() ) { $this->blockedIPpage(); @@ -200,13 +209,19 @@ class EditPage { $hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches ); # we can't deal with anchors, includes, html etc in the header for now, # headline would need to be parsed to improve this - if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) { + #if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) { + if($hasmatch and strlen($matches[2]) > 0) { global $wgInputEncoding; $headline = do_html_entity_decode( $matches[2], ENT_COMPAT, $wgInputEncoding ); - # strip out HTML, will be useful when - # $headline = preg_replace( "/<.*?" . ">/","",$headline ); + # strip out HTML + $headline = preg_replace( "/<.*?" . ">/","",$headline ); $headline = trim( $headline ); - $sectionanchor = '#'.preg_replace("/[ \\?&\\/<>\\(\\)\\[\\]=,+']+/", '_', urlencode( $headline ) ); + $sectionanchor = '#'.urlencode( str_replace(' ', '_', $headline ) ); + $replacearray = array( + '%3A' => ':', + '%' => '.' + ); + $sectionanchor = str_replace(array_keys($replacearray),array_values($replacearray),$sectionanchor); } } @@ -301,12 +316,12 @@ class EditPage { $save = wfMsg( "savearticle" ); $prev = wfMsg( "showpreview" ); - $cancel = $sk->makeKnownLink( $this->mTitle->getPrefixedURL(), + $cancel = $sk->makeKnownLink( $this->mTitle->getPrefixedText(), wfMsg( "cancel" ) ); - $edithelpurl = $sk->makeUrl( wfMsg( "edithelppage" )); - $edithelp = '<a onclick="window.open('. - "'$edithelpurl', 'helpwindow', 'width=610,height=400,left=10,top=10'".'); return false;" href="'.$edithelpurl.'">'. - wfMsg( "edithelp" ).'</a>'; + $edithelpurl = $sk->makeUrl( wfMsg( 'edithelppage' )); + $edithelp = '<a target="helpwindow" href="'.$edithelpurl.'">'. + htmlspecialchars( wfMsg( 'edithelp' ) ).'</a> '. + htmlspecialchars( wfMsg( 'newwindow' ) ); $copywarn = wfMsg( "copyrightwarning", $sk->makeKnownLink( wfMsg( "copyrightpage" ) ) ); @@ -354,7 +369,6 @@ class EditPage { $previewhead.="<h2>" . wfMsg( "previewconflict" ) . "</h2>\n"; } - $previewtext = wfUnescapeHTML( $this->textbox1 ); $parserOptions = ParserOptions::newFromUser( $wgUser ); $parserOptions->setUseCategoryMagic( false ); @@ -371,7 +385,7 @@ class EditPage { $parserOutput = $wgParser->parse( $previewtext , $wgTitle, $parserOptions ); $wgOut->addHTML( $parserOutput->mText ); } else { - $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $previewtext ) ."\n\n", + $parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $this->textbox1 ) ."\n\n", $wgTitle, $parserOptions ); $previewHTML = $parserOutput->mText; @@ -379,6 +393,8 @@ class EditPage { $wgOut->addHTML($previewhead); $wgOut->addHTML($previewHTML); } + $wgOut->addCategoryLinks($parserOutput->getCategoryLinks()); + $wgOut->addLanguageLinks($parserOutput->getLanguageLinks()); $wgOut->addHTML( "<br style=\"clear:both;\" />\n" ); } } @@ -410,12 +426,12 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . </textarea> <br />{$editsummary} {$checkboxhtml} -<input tabindex='5' type='submit' value=\"{$save}\" name=\"wpSave\" accesskey=\"".wfMsg('accesskey-save')."\"". +<input tabindex='5' id='wpSave' type='submit' value=\"{$save}\" name=\"wpSave\" accesskey=\"".wfMsg('accesskey-save')."\"". " title=\"".wfMsg('tooltip-save')."\"/> -<input tabindex='6' type='submit' value=\"{$prev}\" name=\"wpPreview\" accesskey=\"".wfMsg('accesskey-preview')."\"". +<input tabindex='6' id='wpSave' type='submit' value=\"{$prev}\" name=\"wpPreview\" accesskey=\"".wfMsg('accesskey-preview')."\"". " title=\"".wfMsg('tooltip-preview')."\"/> <em>{$cancel}</em> | <em>{$edithelp}</em> -<br /><br />{$copywarn} +<br /><div id=\"editpage-copywarn\">{$copywarn}</div> <input type='hidden' value=\"" . htmlspecialchars( $this->section ) . "\" name=\"wpSection\" /> <input type='hidden' value=\"{$this->edittime}\" name=\"wpEdittime\" />\n" ); @@ -425,7 +441,7 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . wfMsg( "yourtext" ), wfMsg( "storedversion" ) ); $wgOut->addHTML( "<h2>" . wfMsg( "yourtext" ) . "</h2> -<textarea tabindex=6 name=\"wpTextbox2\" rows='{$rows}' cols='{$cols}' wrap='virtual'>" +<textarea tabindex=6 id='wpTextbox2' name=\"wpTextbox2\" rows='{$rows}' cols='{$cols}' wrap='virtual'>" . htmlspecialchars( $wgLang->recodeForEdit( $this->textbox2 ) ) . " </textarea>" ); @@ -450,7 +466,11 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $reason = $wgUser->blockedFor(); $ip = $wgIP; - $name = User::whoIs( $id ); + if ( is_string( $id ) ) { + $name = $id; + } else { + $name = User::whoIs( $id ); + } $link = "[[" . $wgLang->getNsText( Namespace::getUser() ) . ":{$name}|{$name}]]"; @@ -472,6 +492,17 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $wgOut->returnToMain( false ); } + function spamPage() + { + global $wgOut; + $wgOut->setPageTitle( wfMsg( "spamprotectiontitle" ) ); + $wgOut->setRobotpolicy( "noindex,nofollow" ); + $wgOut->setArticleRelated( false ); + + $wgOut->addWikiText( wfMsg( "spamprotectiontext" ) ); + $wgOut->returnToMain( false ); + } + # Forks processes to scan the originating IP for an open proxy server # MemCached can be used to skip IPs that have already been scanned function proxyCheck() @@ -516,6 +547,7 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . } /* private */ function mergeChangesInto( &$text ){ + global $wgIsPg; $oldDate = $this->edittime; $res = wfQuery("SELECT cur_text FROM cur WHERE cur_id=" . $this->mTitle->getArticleID() . " FOR UPDATE", DB_WRITE); @@ -524,10 +556,13 @@ htmlspecialchars( $wgLang->recodeForEdit( $this->textbox1 ) ) . $yourtext = $obj->cur_text; $ns = $this->mTitle->getNamespace(); $title = wfStrencode( $this->mTitle->getDBkey() ); - $res = wfQuery("SELECT old_text FROM old WHERE old_namespace = $ns AND ". + $oldtable=$wgIsPg?'"old"':'old'; + $res = wfQuery("SELECT old_text,old_flags FROM $oldtable WHERE old_namespace = $ns AND ". "old_title = '{$title}' AND old_timestamp = '{$oldDate}'", DB_WRITE); $obj = wfFetchObject($res); - if(wfMerge($obj->old_text, $text, $yourtext, $result)){ + $oldText = Article::getRevisionText( $obj ); + + if(wfMerge($oldText, $text, $yourtext, $result)){ $text = $result; return true; } else { diff --git a/includes/Feed.php b/includes/Feed.php index 0be93e8a7017..b0d208b251e1 100644 --- a/includes/Feed.php +++ b/includes/Feed.php @@ -20,18 +20,18 @@ # http://www.gnu.org/copyleft/gpl.html $wgFeedClasses = array( - "rss" => "RSSFeed", - "atom" => "AtomFeed", + 'rss' => 'RSSFeed', + 'atom' => 'AtomFeed', ); class FeedItem { - var $Title = "Wiki"; - var $Description = ""; - var $Url = ""; - var $Date = ""; - var $Author = ""; + var $Title = 'Wiki'; + var $Description = ''; + var $Url = ''; + var $Date = ''; + var $Author = ''; - function FeedItem( $Title, $Description, $Url, $Date = "", $Author = "", $Comments = "" ) { + function FeedItem( $Title, $Description, $Url, $Date = '', $Author = '', $Comments = '' ) { $this->Title = $Title; $this->Description = $Description; $this->Url = $Url; @@ -44,8 +44,8 @@ class FeedItem { function xmlEncode( $string ) { global $wgInputEncoding, $wgLang; $string = str_replace( "\r\n", "\n", $string ); - if( strcasecmp( $wgInputEncoding, "utf-8" ) != 0 ) { - $string = $wgLang->iconv( $wgInputEncoding, "utf-8", $string ); + if( strcasecmp( $wgInputEncoding, 'utf-8' ) != 0 ) { + $string = $wgLang->iconv( $wgInputEncoding, 'utf-8', $string ); } return htmlspecialchars( $string ); } @@ -85,7 +85,7 @@ class ChannelFeed extends FeedItem { # print "</feed>"; } - function outXmlHeader( $mimetype="application/xml" ) { + function outXmlHeader( $mimetype='application/xml' ) { global $wgServer, $wgStylePath, $wgOut; # We take over from $wgOut, excepting its cache header info @@ -102,7 +102,7 @@ class ChannelFeed extends FeedItem { class RSSFeed extends ChannelFeed { function formatTime( $ts ) { - return gmdate( "D, d M Y H:i:s \G\M\T", wfTimestamp2Unix( $ts ) ); + return gmdate( 'D, d M Y H:i:s \G\M\T', wfTimestamp2Unix( $ts ) ); } function outHeader() { @@ -143,7 +143,7 @@ class RSSFeed extends ChannelFeed { class AtomFeed extends ChannelFeed { function formatTime( $ts ) { // need to use RFC 822 time format at least for rss2.0 - return gmdate( "Y-m-d\TH:i:s", wfTimestamp2Unix( $ts ) ); + return gmdate( 'Y-m-d\TH:i:s', wfTimestamp2Unix( $ts ) ); } function outHeader() { @@ -186,4 +186,4 @@ class AtomFeed extends ChannelFeed { } } -?>
\ No newline at end of file +?> diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 8989b6078d75..dd5197d07d11 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -5,9 +5,9 @@ $wgNumberOfArticles = -1; # Unset $wgTotalViews = -1; $wgTotalEdits = -1; -require_once( "DatabaseFunctions.php" ); -require_once( "UpdateClasses.php" ); -require_once( "LogPage.php" ); +require_once( 'DatabaseFunctions.php' ); +require_once( 'UpdateClasses.php' ); +require_once( 'LogPage.php' ); /* * Compatibility functions @@ -23,8 +23,8 @@ if( !function_exists('iconv') ) { # This will *not* work in all circumstances. function iconv( $from, $to, $string ) { if(strcasecmp( $from, $to ) == 0) return $string; - if(strcasecmp( $from, "utf-8" ) == 0) return utf8_decode( $string ); - if(strcasecmp( $to, "utf-8" ) == 0) return utf8_encode( $string ); + if(strcasecmp( $from, 'utf-8' ) == 0) return utf8_decode( $string ); + if(strcasecmp( $to, 'utf-8' ) == 0) return utf8_encode( $string ); return $string; } } @@ -32,7 +32,7 @@ if( !function_exists('iconv') ) { if( !function_exists('file_get_contents') ) { # Exists in PHP 4.3.0+ function file_get_contents( $filename ) { - return implode( "", file( $filename ) ); + return implode( '', file( $filename ) ); } } @@ -40,22 +40,22 @@ if( !function_exists('is_a') ) { # Exists in PHP 4.2.0+ function is_a( $object, $class_name ) { return - (strcasecmp( get_class( $object, $class_name ) == 0) || - is_subclass_of( $object, $class_name ) ); + (strcasecmp( get_class( $object ), $class_name ) == 0) || + is_subclass_of( $object, $class_name ); } } # html_entity_decode exists in PHP 4.3.0+ but is FATALLY BROKEN even then, # with no UTF-8 support. -function do_html_entity_decode( $string, $quote_style=ENT_COMPAT, $charset="ISO-8859-1" ) { +function do_html_entity_decode( $string, $quote_style=ENT_COMPAT, $charset='ISO-8859-1' ) { static $trans; if( !isset( $trans ) ) { $trans = array_flip( get_html_translation_table( HTML_ENTITIES, $quote_style ) ); # Assumes $charset will always be the same through a run, and only understands # utf-8 or default. Note - mixing latin1 named entities and unicode numbered # ones will result in a bad link. - if( strcasecmp( "utf-8", $charset ) == 0 ) { - $trans = array_map( "utf8_encode", $trans ); + if( strcasecmp( 'utf-8', $charset ) == 0 ) { + $trans = array_map( 'utf8_encode', $trans ); } } return strtr( $string, $trans ); @@ -77,19 +77,19 @@ function wfSeedRandom() # Generates a URL from a URL-encoded title and a query string # Title::getLocalURL() is preferred in most cases # -function wfLocalUrl( $a, $q = "" ) +function wfLocalUrl( $a, $q = '' ) { global $wgServer, $wgScript, $wgArticlePath; - $a = str_replace( " ", "_", $a ); + $a = str_replace( ' ', '_', $a ); - if ( "" == $a ) { - if( "" == $q ) { + if ( '' == $a ) { + if( '' == $q ) { $a = $wgScript; } else { $a = "{$wgScript}?{$q}"; } - } else if ( "" == $q ) { + } else if ( '' == $q ) { $a = str_replace( "$1", $a, $wgArticlePath ); } else if ($wgScript != '' ) { $a = "{$wgScript}?title={$a}&{$q}"; @@ -99,18 +99,18 @@ function wfLocalUrl( $a, $q = "" ) return $a; } -function wfLocalUrlE( $a, $q = "" ) +function wfLocalUrlE( $a, $q = '' ) { return wfEscapeHTML( wfLocalUrl( $a, $q ) ); # die( "Call to obsolete function wfLocalUrlE()" ); } -function wfFullUrl( $a, $q = "" ) { - wfDebugDieBacktrace( "Call to obsolete function wfFullUrl(); use Title::getFullURL" ); +function wfFullUrl( $a, $q = '' ) { + wfDebugDieBacktrace( 'Call to obsolete function wfFullUrl(); use Title::getFullURL' ); } -function wfFullUrlE( $a, $q = "" ) { - wfDebugDieBacktrace( "Call to obsolete function wfFullUrlE(); use Title::getFullUrlE" ); +function wfFullUrlE( $a, $q = '' ) { + wfDebugDieBacktrace( 'Call to obsolete function wfFullUrlE(); use Title::getFullUrlE' ); } @@ -143,27 +143,28 @@ function wfImageArchiveUrl( $name ) function wfUrlencode ( $s ) { $s = urlencode( $s ); - $s = preg_replace( "/%3[Aa]/", ":", $s ); - $s = preg_replace( "/%2[Ff]/", "/", $s ); + $s = preg_replace( '/%3[Aa]/', ':', $s ); + $s = preg_replace( '/%2[Ff]/', '/', $s ); return $s; } function wfUtf8Sequence($codepoint) { - if($codepoint < 0x80) return chr($codepoint); - if($codepoint < 0x800) return chr($codepoint >> 6 & 0x3f | 0xc0) . - chr($codepoint & 0x3f | 0x80); - if($codepoint < 0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) . - chr($codepoint >> 6 & 0x3f | 0x80) . - chr($codepoint & 0x3f | 0x80); + if($codepoint < 0x80) return chr($codepoint); + if($codepoint < 0x800) return chr($codepoint >> 6 & 0x3f | 0xc0) . + chr($codepoint & 0x3f | 0x80); + if($codepoint < 0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) . + chr($codepoint >> 6 & 0x3f | 0x80) . + chr($codepoint & 0x3f | 0x80); if($codepoint < 0x100000) return chr($codepoint >> 18 & 0x07 | 0xf0) . # Double-check this - chr($codepoint >> 12 & 0x3f | 0x80) . - chr($codepoint >> 6 & 0x3f | 0x80) . - chr($codepoint & 0x3f | 0x80); + chr($codepoint >> 12 & 0x3f | 0x80) . + chr($codepoint >> 6 & 0x3f | 0x80) . + chr($codepoint & 0x3f | 0x80); # Doesn't yet handle outside the BMP return "&#$codepoint;"; } +# Converts numeric character entities to UTF-8 function wfMungeToUtf8($string) { global $wgInputEncoding; # This is debatable #$string = iconv($wgInputEncoding, "UTF-8", $string); @@ -189,7 +190,7 @@ function wfUtf8Entity( $matches ) { } if ( $length != strlen( $char ) ) { - return ""; + return ''; } if ( $length == 1 ) { return $char; @@ -235,23 +236,25 @@ function logProfilingData() list( $usec, $sec ) = explode( " ", $wgRequestTime ); $start = (float)$sec + (float)$usec; $elapsed = $now - $start; - if ( "" != $wgDebugLogFile ) { + if ( $wgProfiling ) { $prof = wfGetProfilingOutput( $start, $elapsed ); - $forward = ""; + $forward = ''; if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) - $forward = " forwarded for " . $_SERVER['HTTP_X_FORWARDED_FOR']; + $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; if( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) - $forward .= " client IP " . $_SERVER['HTTP_CLIENT_IP']; + $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP']; if( !empty( $_SERVER['HTTP_FROM'] ) ) - $forward .= " from " . $_SERVER['HTTP_FROM']; + $forward .= ' from ' . $_SERVER['HTTP_FROM']; if( $forward ) $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; if($wgUser->getId() == 0) - $forward .= " anon"; + $forward .= ' anon'; $log = sprintf( "%s\t%04.3f\t%s\n", - gmdate( "YmdHis" ), $elapsed, + gmdate( 'YmdHis' ), $elapsed, urldecode( $_SERVER['REQUEST_URI'] . $forward ) ); - error_log( $log . $prof, 3, $wgDebugLogFile ); + if ( '' != $wgDebugLogFile ) { + error_log( $log . $prof, 3, $wgDebugLogFile ); + } } } @@ -288,7 +291,7 @@ function wfMsgNoDB( $key ) { function wfMsgReal( $key, $args, $useDB ) { global $wgReplacementKeys, $wgMessageCache, $wgLang; - $fname = "wfMsg"; + $fname = 'wfMsg'; wfProfileIn( $fname ); if ( $wgMessageCache ) { $message = $wgMessageCache->get( $key, $useDB ); @@ -309,28 +312,28 @@ function wfMsgReal( $key, $args, $useDB ) { function wfCleanFormFields( $fields ) { - wfDebugDieBacktrace( "Call to obsolete wfCleanFormFields(). Use wgRequest instead..." ); + wfDebugDieBacktrace( 'Call to obsolete wfCleanFormFields(). Use wgRequest instead...' ); } function wfMungeQuotes( $in ) { - $out = str_replace( "%", "%25", $in ); - $out = str_replace( "'", "%27", $out ); - $out = str_replace( "\"", "%22", $out ); + $out = str_replace( '%', '%25', $in ); + $out = str_replace( "'", '%27', $out ); + $out = str_replace( '"', '%22', $out ); return $out; } function wfDemungeQuotes( $in ) { - $out = str_replace( "%22", "\"", $in ); - $out = str_replace( "%27", "'", $out ); - $out = str_replace( "%25", "%", $out ); + $out = str_replace( '%22', '"', $in ); + $out = str_replace( '%27', "'", $out ); + $out = str_replace( '%25', '%', $out ); return $out; } function wfCleanQueryVar( $var ) { - wfDebugDieBacktrace( "Call to obsolete function wfCleanQueryVar(); use wgRequest instead" ); + wfDebugDieBacktrace( 'Call to obsolete function wfCleanQueryVar(); use wgRequest instead' ); } function wfSearch( $s ) @@ -353,30 +356,48 @@ function wfAbruptExit(){ } $called = true; - if( function_exists( "debug_backtrace" ) ){ // PHP >= 4.3 + if( function_exists( 'debug_backtrace' ) ){ // PHP >= 4.3 $bt = debug_backtrace(); for($i = 0; $i < count($bt) ; $i++){ - $file = $bt[$i]["file"]; - $line = $bt[$i]["line"]; + $file = $bt[$i]['file']; + $line = $bt[$i]['line']; wfDebug("WARNING: Abrupt exit in $file at line $line\n"); } } else { - wfDebug("WARNING: Abrupt exit\n"); + wfDebug('WARNING: Abrupt exit\n'); } exit(); } -function wfDebugDieBacktrace( $msg = "" ) { - $msg .= "\n<p>Backtrace:</p>\n<ul>\n"; - $backtrace = debug_backtrace(); - foreach( $backtrace as $call ) { - $f = explode( DIRECTORY_SEPARATOR, $call['file'] ); - $file = $f[count($f)-1]; - $msg .= "<li>" . $file . " line " . $call['line'] . ", in "; - if( !empty( $call['class'] ) ) $msg .= $call['class'] . "::"; - $msg .= $call['function'] . "()</li>\n"; - } - die( $msg ); +function wfDebugDieBacktrace( $msg = '' ) { + global $wgCommandLineMode; + + if ( function_exists( 'debug_backtrace' ) ) { + if ( $wgCommandLineMode ) { + $msg .= "\nBacktrace:\n"; + } else { + $msg .= "\n<p>Backtrace:</p>\n<ul>\n"; + } + $backtrace = debug_backtrace(); + foreach( $backtrace as $call ) { + $f = explode( DIRECTORY_SEPARATOR, $call['file'] ); + $file = $f[count($f)-1]; + if ( $wgCommandLineMode ) { + $msg .= "$file line {$call['line']}, in "; + } else { + $msg .= '<li>' . $file . " line " . $call['line'] . ', in '; + } + if( !empty( $call['class'] ) ) $msg .= $call['class'] . '::'; + $msg .= $call['function'] . "()"; + + if ( $wgCommandLineMode ) { + $msg .= "\n"; + } else { + $msg .= "</li>\n"; + } + } + } + die( $msg ); } function wfNumberOfArticles() @@ -392,9 +413,9 @@ function wfNumberOfArticles() global $wgNumberOfArticles, $wgTotalViews, $wgTotalEdits; if ( -1 != $wgNumberOfArticles ) return; - $sql = "SELECT ss_total_views, ss_total_edits, ss_good_articles " . - "FROM site_stats WHERE ss_row_id=1"; - $res = wfQuery( $sql, DB_READ, "wfLoadSiteStats" ); + $sql = 'SELECT ss_total_views, ss_total_edits, ss_good_articles ' . + 'FROM site_stats WHERE ss_row_id=1'; + $res = wfQuery( $sql, DB_READ, 'wfLoadSiteStats' ); if ( 0 == wfNumRows( $res ) ) { return; } else { @@ -408,24 +429,24 @@ function wfNumberOfArticles() function wfEscapeHTML( $in ) { return str_replace( - array( "&", "\"", ">", "<" ), - array( "&", """, ">", "<" ), + array( '&', '"', '>', '<' ), + array( '&', '"', '>', '<' ), $in ); } function wfEscapeHTMLTagsOnly( $in ) { return str_replace( - array( "\"", ">", "<" ), - array( """, ">", "<" ), + array( '"', '>', '<' ), + array( '"', '>', '<' ), $in ); } function wfUnescapeHTML( $in ) { - $in = str_replace( "<", "<", $in ); - $in = str_replace( ">", ">", $in ); - $in = str_replace( """, "\"", $in ); - $in = str_replace( "&", "&", $in ); + $in = str_replace( '<', '<', $in ); + $in = str_replace( '>', '>', $in ); + $in = str_replace( '"', '"', $in ); + $in = str_replace( '&', '&', $in ); return $in; } @@ -435,21 +456,21 @@ function wfImageDir( $fname ) $hash = md5( $fname ); $oldumask = umask(0); - $dest = $wgUploadDirectory . "/" . $hash{0}; + $dest = $wgUploadDirectory . '/' . $hash{0}; if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); } - $dest .= "/" . substr( $hash, 0, 2 ); + $dest .= '/' . substr( $hash, 0, 2 ); if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); } umask( $oldumask ); return $dest; } -function wfImageThumbDir( $fname , $subdir="thumb") +function wfImageThumbDir( $fname , $subdir='thumb') { return wfImageArchiveDir( $fname, $subdir ); } -function wfImageArchiveDir( $fname , $subdir="archive") +function wfImageArchiveDir( $fname , $subdir='archive') { global $wgUploadDirectory; @@ -460,9 +481,9 @@ function wfImageArchiveDir( $fname , $subdir="archive") # be written we'll worry about it then. $archive = "{$wgUploadDirectory}/{$subdir}"; if ( ! is_dir( $archive ) ) { @mkdir( $archive, 0777 ); } - $archive .= "/" . $hash{0}; + $archive .= '/' . $hash{0}; if ( ! is_dir( $archive ) ) { @mkdir( $archive, 0777 ); } - $archive .= "/" . substr( $hash, 0, 2 ); + $archive .= '/' . substr( $hash, 0, 2 ); if ( ! is_dir( $archive ) ) { @mkdir( $archive, 0777 ); } umask( $oldumask ); @@ -474,9 +495,9 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source global $wgUser, $wgLang, $wgTitle, $wgOut, $wgDeferredUpdateList; global $wgUseCopyrightUpload; - $fname = "wfRecordUpload"; + $fname = 'wfRecordUpload'; - $sql = "SELECT img_name,img_size,img_timestamp,img_description,img_user," . + $sql = 'SELECT img_name,img_size,img_timestamp,img_description,img_user,' . "img_user_text FROM image WHERE img_name='" . wfStrencode( $name ) . "'"; $res = wfQuery( $sql, DB_READ, $fname ); @@ -486,9 +507,9 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source if ( $wgUseCopyrightUpload ) { - $textdesc = "== " . wfMsg ( "filedesc" ) . " ==\n" . $desc . "\n" . - "== " . wfMsg ( "filestatus" ) . " ==\n" . $copyStatus . "\n" . - "== " . wfMsg ( "filesource" ) . " ==\n" . $source ; + $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" . + '== ' . wfMsg ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" . + '== ' . wfMsg ( 'filesource' ) . " ==\n" . $source ; } else $textdesc = $desc ; @@ -496,27 +517,27 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source $won = wfInvertTimestamp( $now ); if ( 0 == wfNumRows( $res ) ) { - $sql = "INSERT INTO image (img_name,img_size,img_timestamp," . + $sql = 'INSERT INTO image (img_name,img_size,img_timestamp,' . "img_description,img_user,img_user_text) VALUES ('" . wfStrencode( $name ) . "',$size,'{$now}','" . wfStrencode( $desc ) . "', '" . $wgUser->getID() . "', '" . wfStrencode( $wgUser->getName() ) . "')"; wfQuery( $sql, DB_WRITE, $fname ); - $sql = "SELECT cur_id,cur_text FROM cur WHERE cur_namespace=" . + $sql = 'SELECT cur_id,cur_text FROM cur WHERE cur_namespace=' . Namespace::getImage() . " AND cur_title='" . wfStrencode( $name ) . "'"; $res = wfQuery( $sql, DB_READ, $fname ); if ( 0 == wfNumRows( $res ) ) { - $common = + $common = Namespace::getImage() . ",'" . wfStrencode( $name ) . "','" . wfStrencode( $desc ) . "','" . $wgUser->getID() . "','" . wfStrencode( $wgUser->getName() ) . "','" . $now . "',1"; - $sql = "INSERT INTO cur (cur_namespace,cur_title," . - "cur_comment,cur_user,cur_user_text,cur_timestamp,cur_is_new," . - "cur_text,inverse_timestamp,cur_touched) VALUES (" . + $sql = 'INSERT INTO cur (cur_namespace,cur_title,' . + 'cur_comment,cur_user,cur_user_text,cur_timestamp,cur_is_new,' . + 'cur_text,inverse_timestamp,cur_touched) VALUES (' . $common . ",'" . wfStrencode( $textdesc ) . "','{$won}','{$now}')"; wfQuery( $sql, DB_WRITE, $fname ); @@ -531,7 +552,7 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source } else { $s = wfFetchObject( $res ); - $sql = "INSERT INTO oldimage (oi_name,oi_archive_name,oi_size," . + $sql = 'INSERT INTO oldimage (oi_name,oi_archive_name,oi_size,' . "oi_timestamp,oi_description,oi_user,oi_user_text) VALUES ('" . wfStrencode( $s->img_name ) . "','" . wfStrencode( $oldver ) . @@ -555,10 +576,10 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source wfQuery( $sql, DB_WRITE, $fname ); } - $log = new LogPage( wfMsg( "uploadlogpage" ), wfMsg( "uploadlogpagetext" ) ); - $da = wfMsg( "uploadedimage", "[[:" . $wgLang->getNsText( + $log = new LogPage( wfMsg( 'uploadlogpage' ), wfMsg( 'uploadlogpagetext' ) ); + $da = wfMsg( 'uploadedimage', '[[:' . $wgLang->getNsText( Namespace::getImage() ) . ":{$name}|{$name}]]" ); - $ta = wfMsg( "uploadedimage", $name ); + $ta = wfMsg( 'uploadedimage', $name ); $log->addEntry( $da, $desc, $ta ); } @@ -568,21 +589,21 @@ function wfRecordUpload( $name, $oldver, $size, $desc, $copyStatus = "", $source function wfShowingResults( $offset, $limit ) { global $wgLang; - return wfMsg( "showingresults", $wgLang->formatNum( $limit ), $wgLang->formatNum( $offset+1 ) ); + return wfMsg( 'showingresults', $wgLang->formatNum( $limit ), $wgLang->formatNum( $offset+1 ) ); } function wfShowingResultsNum( $offset, $limit, $num ) { global $wgLang; - return wfMsg( "showingresultsnum", $wgLang->formatNum( $limit ), $wgLang->formatNum( $offset+1 ), $wgLang->formatNum( $num ) ); + return wfMsg( 'showingresultsnum', $wgLang->formatNum( $limit ), $wgLang->formatNum( $offset+1 ), $wgLang->formatNum( $num ) ); } -function wfViewPrevNext( $offset, $limit, $link, $query = "", $atend = false ) +function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { global $wgUser, $wgLang; $fmtLimit = $wgLang->formatNum( $limit ); - $prev = wfMsg( "prevn", $fmtLimit ); - $next = wfMsg( "nextn", $fmtLimit ); + $prev = wfMsg( 'prevn', $fmtLimit ); + $next = wfMsg( 'nextn', $fmtLimit ); $link = wfUrlencode( $link ); $sk = $wgUser->getSkin(); @@ -590,8 +611,8 @@ function wfViewPrevNext( $offset, $limit, $link, $query = "", $atend = false ) $po = $offset - $limit; if ( $po < 0 ) { $po = 0; } $q = "limit={$limit}&offset={$po}"; - if ( "" != $query ) { $q .= "&{$query}"; } - $plink = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$prev}</a>"; + if ( '' != $query ) { $q .= "&{$query}"; } + $plink = '<a href="' . wfLocalUrlE( $link, $q ) . "\">{$prev}</a>"; } else { $plink = $prev; } $no = $offset + $limit; @@ -601,26 +622,26 @@ function wfViewPrevNext( $offset, $limit, $link, $query = "", $atend = false ) if ( $atend ) { $nlink = $next; } else { - $nlink = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$next}</a>"; + $nlink = '<a href="' . wfLocalUrlE( $link, $q ) . "\">{$next}</a>"; } - $nums = wfNumLink( $offset, 20, $link , $query ) . " | " . - wfNumLink( $offset, 50, $link, $query ) . " | " . - wfNumLink( $offset, 100, $link, $query ) . " | " . - wfNumLink( $offset, 250, $link, $query ) . " | " . + $nums = wfNumLink( $offset, 20, $link , $query ) . ' | ' . + wfNumLink( $offset, 50, $link, $query ) . ' | ' . + wfNumLink( $offset, 100, $link, $query ) . ' | ' . + wfNumLink( $offset, 250, $link, $query ) . ' | ' . wfNumLink( $offset, 500, $link, $query ); - return wfMsg( "viewprevnext", $plink, $nlink, $nums ); + return wfMsg( 'viewprevnext', $plink, $nlink, $nums ); } -function wfNumLink( $offset, $limit, $link, $query = "" ) +function wfNumLink( $offset, $limit, $link, $query = '' ) { global $wgUser, $wgLang; - if ( "" == $query ) { $q = ""; } + if ( '' == $query ) { $q = ''; } else { $q = "{$query}&"; } $q .= "limit={$limit}&offset={$offset}"; $fmtLimit = $wgLang->formatNum( $limit ); - $s = "<a href=\"" . wfLocalUrlE( $link, $q ) . "\">{$fmtLimit}</a>"; + $s = '<a href="' . wfLocalUrlE( $link, $q ) . "\">{$fmtLimit}</a>"; return $s; } @@ -630,9 +651,9 @@ function wfClientAcceptsGzip() { # FIXME: we may want to blacklist some broken browsers if( preg_match( '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/', - $_SERVER["HTTP_ACCEPT_ENCODING"], + $_SERVER['HTTP_ACCEPT_ENCODING'], $m ) ) { - if( ( $m[1] == "q" ) && ( $m[2] == 0 ) ) return false; + if( ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) return false; wfDebug( " accepts gzip\n" ); return true; } @@ -641,12 +662,12 @@ function wfClientAcceptsGzip() { } # Yay, more global functions! -function wfCheckLimits( $deflimit = 50, $optionname = "rclimit" ) { +function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) { global $wgUser, $wgRequest; $limit = $wgRequest->getInt( 'limit', 0 ); if( $limit < 0 ) $limit = 0; - if( ( $limit == 0 ) && ( $optionname != "" ) ) { + if( ( $limit == 0 ) && ( $optionname != '' ) ) { $limit = (int)$wgUser->getOption( $optionname ); } if( $limit <= 0 ) $limit = $deflimit; @@ -668,13 +689,13 @@ function wfCheckLimits( $deflimit = 50, $optionname = "rclimit" ) { function wfEscapeWikiText( $text ) { $text = str_replace( - array( '[', '|', "'", 'ISBN ' , '://' , "\n=" ), + array( '[', '|', "'", 'ISBN ' , '://' , "\n=" ), array( '[', '|', ''', 'ISBN ', '://' , "\n=" ), htmlspecialchars($text) ); return $text; } -function wfQuotedPrintable( $string, $charset = "" ) +function wfQuotedPrintable( $string, $charset = '' ) { # Probably incomplete; see RFC 2045 if( empty( $charset ) ) { @@ -682,19 +703,19 @@ function wfQuotedPrintable( $string, $charset = "" ) $charset = $wgInputEncoding; } $charset = strtoupper( $charset ); - $charset = str_replace( "ISO-8859", "ISO8859", $charset ); // ? + $charset = str_replace( 'ISO-8859', 'ISO8859', $charset ); // ? $illegal = '\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff='; $replace = $illegal . '\t ?_'; if( !preg_match( "/[$illegal]/", $string ) ) return $string; $out = "=?$charset?Q?"; $out .= preg_replace( "/([$replace])/e", 'sprintf("=%02X",ord("$1"))', $string ); - $out .= "?="; + $out .= '?='; return $out; } function wfTime(){ - $st = explode( " ", microtime() ); + $st = explode( ' ', microtime() ); return (float)$st[0] + (float)$st[1]; } @@ -714,11 +735,10 @@ function wfSetVar( &$dest, $source ) } # Sets dest to a reference to source and returns the original dest +# Pity that doesn't work in PHP function &wfSetRef( &$dest, &$source ) { - $temp =& $dest; - $dest =& $source; - return $temp; + die( "You can't rebind a variable in the caller's scope" ); } # This function takes two arrays as input, and returns a CGI-style string, e.g. @@ -730,11 +750,11 @@ function wfArrayToCGI( $array1, $array2 = NULL ) $array1 = $array1 + $array2; } - $cgi = ""; + $cgi = ''; foreach ( $array1 as $key => $value ) { - if ( "" !== $value ) { - if ( "" != $cgi ) { - $cgi .= "&"; + if ( '' !== $value ) { + if ( '' != $cgi ) { + $cgi .= '&'; } $cgi .= "{$key}={$value}"; } @@ -752,15 +772,15 @@ function wfEscapeShellArg( ) { $args = func_get_args(); $first = true; - $retVal = ""; + $retVal = ''; foreach ( $args as $arg ) { if ( !$first ) { - $retVal .= " "; + $retVal .= ' '; } else { $first = false; } - if (substr(php_uname(), 0, 7) == "Windows") { + if ( wfIsWindows() ) { $retVal .= '"' . str_replace( '"','\"', $arg ) . '"'; } else { $retVal .= escapeshellarg( $arg ); @@ -782,21 +802,21 @@ function wfMerge( $old, $mine, $yours, &$result ){ } # Make temporary files - $td = "/tmp/"; - $oldtextFile = fopen( $oldtextName = tempnam( $td, "merge-old-" ), "w" ); - $mytextFile = fopen( $mytextName = tempnam( $td, "merge-mine-" ), "w" ); - $yourtextFile = fopen( $yourtextName = tempnam( $td, "merge-your-" ), "w" ); + $td = '/tmp/'; + $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' ); + $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' ); + $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' ); fwrite( $oldtextFile, $old ); fclose( $oldtextFile ); fwrite( $mytextFile, $mine ); fclose( $mytextFile ); fwrite( $yourtextFile, $yours ); fclose( $yourtextFile ); # Check for a conflict - $cmd = wfEscapeShellArg( $wgDiff3 ) . " -a --overlap-only " . - wfEscapeShellArg( $mytextName ) . " " . - wfEscapeShellArg( $oldtextName ) . " " . - wfEscapeShellArg( $yourtextName ); - $handle = popen( $cmd, "r" ); + $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a --overlap-only ' . + wfEscapeShellArg( $mytextName ) . ' ' . + wfEscapeShellArg( $oldtextName ) . ' ' . + wfEscapeShellArg( $yourtextName ); + $handle = popen( $cmd, 'r' ); if( fgets( $handle ) ){ $conflict = true; @@ -806,10 +826,10 @@ function wfMerge( $old, $mine, $yours, &$result ){ pclose( $handle ); # Merge differences - $cmd = wfEscapeShellArg( $wgDiff3 ) . " -a -e --merge " . + $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a -e --merge ' . wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName ); - $handle = popen( $cmd, "r" ); - $result = ""; + $handle = popen( $cmd, 'r' ); + $result = ''; do { $data = fread( $handle, 8192 ); if ( strlen( $data ) == 0 ) { @@ -843,13 +863,13 @@ function wfHttpError( $code, $label, $desc ) { # Don't send content if it's a HEAD request. if( $_SERVER['REQUEST_METHOD'] == 'HEAD' ) { - header( "Content-type: text/plain" ); + header( 'Content-type: text/plain' ); print "$desc\n"; } } # Converts an Accept-* header into an array mapping string values to quality factors -function wfAcceptToPrefs( $accept, $def = "*/*" ) { +function wfAcceptToPrefs( $accept, $def = '*/*' ) { # No arg means accept anything (per HTTP spec) if( !$accept ) { return array( $def => 1 ); @@ -857,11 +877,11 @@ function wfAcceptToPrefs( $accept, $def = "*/*" ) { $prefs = array(); - $parts = explode( ",", $accept ); + $parts = explode( ',', $accept ); foreach( $parts as $part ) { # FIXME: doesn't deal with params like 'text/html; level=1' - @list( $value, $qpart ) = explode( ";", $part ); + @list( $value, $qpart ) = explode( ';', $part ); if( !isset( $qpart ) ) { $prefs[$value] = 1; } elseif( preg_match( '/q\s*=\s*(\d*\.\d+)/', $qpart, $match ) ) { @@ -933,4 +953,14 @@ function wfArrayLookup( $a, $b ) return array_flip( array_intersect( array_flip( $a ), array_keys( $b ) ) ); } +# Since Windows is so different to any of the other popular OSes, it seems appropriate +# to have a simple way to test for its presence +function wfIsWindows() { + if (substr(php_uname(), 0, 7) == 'Windows') { + return true; + } else { + return false; + } +} + ?> diff --git a/includes/HistoryBlob.php b/includes/HistoryBlob.php new file mode 100644 index 000000000000..cf170b759531 --- /dev/null +++ b/includes/HistoryBlob.php @@ -0,0 +1,64 @@ +<?php + +# Pure virtual parent +class HistoryBlob +{ + function setMeta() {} + function getMeta() {} + function addItem() {} + function getItem() {} +} + +# The real object +class ConcatenatedGzipHistoryBlob +{ + /* private */ var $mVersion = 0, $mCompressed = false, $mItems = array(); + + function HistoryBlob() { + if ( !function_exists( 'gzdeflate' ) ) { + die( "Need zlib support to read or write this kind of history object (ConcatenatedGzipHistoryBlob)\n" ); + } + } + + function setMeta( $metaData ) { + $this->uncompress(); + $this->mItems['meta'] = $metaData; + } + + function getMeta() { + $this->uncompress(); + return $this->mItems['meta']; + } + + function addItem( $text ) { + $this->uncompress(); + $this->mItems[md5($text)] = $text; + } + + function getItem( $hash ) { + $this->compress(); + return $this->mItems[$hash]; + } + + function compress() { + if ( !$this->mCompressed ) { + $this->mItems = gzdeflate( serialize( $this->mItems ) ); + $this->mCompressed = true; + } + } + + function uncompress() { + if ( $this->mCompressed ) { + $this->mItems = unserialize( gzinflate( $this->mItems ) ); + } + } + + function __sleep() { + compress(); + } + + function __wakeup() { + uncompress(); + } +} +?> diff --git a/includes/Image.php b/includes/Image.php index d0293a5443c7..27eeb9d72e3f 100644 --- a/includes/Image.php +++ b/includes/Image.php @@ -35,16 +35,17 @@ class Image if ( $this->fileExists = file_exists( $this->imagePath ) ) // Sic!, "=" is intended { - $gis = getimagesize( $this->imagePath ); - $this->width = $gis[0]; - $this->height = $gis[1]; - $this->type = $gis[2]; - $this->attr = $gis[3]; - if ( isset( $gis["bits"] ) ) - { - $this->bits = $gis["bits"]; - } else { - $this->bits = 0; + @$gis = getimagesize( $this->imagePath ); + if( $gis !== false ) { + $this->width = $gis[0]; + $this->height = $gis[1]; + $this->type = $gis[2]; + $this->attr = $gis[3]; + if ( isset( $gis["bits"] ) ) { + $this->bits = $gis["bits"]; + } else { + $this->bits = 0; + } } } $this->historyLine = 0; diff --git a/includes/ImagePage.php b/includes/ImagePage.php index 164abb5a370f..6e8d72b6c20e 100644 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@ -67,7 +67,7 @@ class ImagePage extends Article { $line = $this->img->nextHistoryLine(); $s .= $sk->imageHistoryLine( true, $line->img_timestamp, - $this->mTitle->getText(), $line->img_user, + $this->mTitle->getDBkey(), $line->img_user, $line->img_user_text, $line->img_size, $line->img_description ); while ( $line = $this->img->nextHistoryLine() ) { @@ -139,9 +139,9 @@ class ImagePage extends Article { } if ( !is_null( $image ) ) { - $q = "&image={$image}"; + $q = "&image=" . urlencode( $image ); } else if ( !is_null( $oldimage ) ) { - $q = "&oldimage={$oldimage}"; + $q = "&oldimage=" . urlencode( $oldimage ); } else { $q = ""; } diff --git a/includes/LinkCache.php b/includes/LinkCache.php index 8f41cccf7e51..cd0c0879e4e8 100644 --- a/includes/LinkCache.php +++ b/includes/LinkCache.php @@ -171,6 +171,7 @@ class LinkCache { if ( $wgEnablePersistentLC ) { if( $this->fillFromLinkscc( $id ) ){ + wfProfileOut( $fname ); return; } } @@ -301,35 +302,61 @@ class LinkCache { } /* private */ function saveToLinkscc( $pid ){ - global $wgCompressedPersistentLC; + global $wgCompressedPersistentLC, $wgIsMySQL; if( $wgCompressedPersistentLC and function_exists( "gzcompress" ) ) { $ser = wfStrencode( gzcompress( serialize( $this ), 3 )); } else { $ser = wfStrencode( serialize( $this ) ); } - wfQuery("REPLACE INTO linkscc(lcc_pageid,lcc_cacheobj) " . - "VALUES({$pid}, '{$ser}')", DB_WRITE); + if ($wgIsMySQL) { + wfQuery("REPLACE INTO linkscc(lcc_pageid,lcc_cacheobj) " . + "VALUES({$pid}, '{$ser}')", DB_WRITE); + } else { + wfQuery("DELETE FROM linkscc WHERE lcc_pageid={$pid}",DB_WRITE); + wfQuery("INSERT INTO linkscc(lcc_pageid,lcc_cacheobj) " . + "VALUES({$pid}, '{$ser}')", DB_WRITE); + } } # $pid is a page id /* static */ function linksccClearLinksTo( $pid ){ - $pid = intval( $pid ); - wfQuery("DELETE linkscc FROM linkscc,links ". - "WHERE lcc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); - wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); + global $wgEnablePersistentLC, $wgIsMySQL; + if ( $wgEnablePersistentLC ) { + $pid = intval( $pid ); + if ($wgIsMySQL) { + wfQuery("DELETE linkscc FROM linkscc,links ". + "WHERE lcc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); + } else { + wfQuery("DELETE FROM linkscc WHERE lcc_pageid IN ". + "(SELECT l_from FROM links WHERE l_to={$pid})", DB_WRITE); + } + wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); + } } # $title is a prefixed db title, for example like Title->getPrefixedDBkey() returns. /* static */ function linksccClearBrokenLinksTo( $title ){ - $title = wfStrencode( $title ); - wfQuery("DELETE linkscc FROM linkscc,brokenlinks ". - "WHERE lcc_pageid=bl_from AND bl_to='{$title}'", DB_WRITE); + global $wgEnablePersistentLC,$wgIsMySQL; + if ( $wgEnablePersistentLC ) { + $title = wfStrencode( $title ); + if ($wgIsMySQL) { + wfQuery("DELETE linkscc FROM linkscc,brokenlinks ". + "WHERE lcc_pageid=bl_from AND bl_to='{$title}'", DB_WRITE); + } else { + wfQuery("DELETE FROM linkscc WHERE lcc_pageid IN ". + "(SELECT bl_from FROM brokenlinks ". + "WHERE bl_to='{$title}')",DB_WRITE); + } + } } # $pid is a page id /* static */ function linksccClearPage( $pid ){ - $pid = intval( $pid ); - wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); + global $wgEnablePersistentLC; + if ( $wgEnablePersistentLC ) { + $pid = intval( $pid ); + wfQuery("DELETE FROM linkscc WHERE lcc_pageid='{$pid}'", DB_WRITE); + } } } ?> diff --git a/includes/LoadBalancer.php b/includes/LoadBalancer.php index 3df2ac58c604..94f4f55cff0d 100644 --- a/includes/LoadBalancer.php +++ b/includes/LoadBalancer.php @@ -1,10 +1,27 @@ <?php # Database load balancing object +# Valid database indexes +# Operation-based indexes +define( "DB_READ", -1 ); # Read from the slave (or only server) +define( "DB_WRITE", -2 ); # Write to master (or only server) +define( "DB_LAST", -3 ); # Whatever database was used last + +# Task-based indexes +# ***NOT USED YET, EXPERIMENTAL*** +# These may be defined in $wgDBservers. If they aren't, the default reader or writer will be used +# Even numbers are always readers, odd numbers are writers +define( "DB_TASK_FIRST", 1000 ); # First in list +define( "DB_SEARCH_R", 1000 ); # Search read +define( "DB_SEARCH_W", 1001 ); # Search write +define( "DB_ASKSQL_R", 1002 ); # Special:Asksql read +define( "DB_WATCHLIST_R", 1004 ); # Watchlist read +define( "DB_TASK_LAST", 1004) ; # Last in list + class LoadBalancer { /* private */ var $mServers, $mConnections, $mLoads; /* private */ var $mUser, $mPassword, $mDbName, $mFailFunction; - /* private */ var $mForce, $mReadIndex; + /* private */ var $mForce, $mReadIndex, $mLastConn; function LoadBalancer() { @@ -17,6 +34,7 @@ class LoadBalancer { $this->mFailFunction = false; $this->mReadIndex = -1; $this->mForce = -1; + $this->mLastConn = false; } function newFromParams( $servers, $loads, $user, $password, $dbName, $failFunction = false ) @@ -38,6 +56,7 @@ class LoadBalancer { $this->mWriteIndex = -1; $this->mForce = -1; $this->mConnections = array(); + $this->mLastConn = false; wfSeedRandom(); } @@ -53,7 +72,8 @@ class LoadBalancer { foreach ( $weights as $w ) { $sum += $w; } - $rand = mt_rand() / RAND_MAX * $sum; + $max = mt_getrandmax(); + $rand = mt_rand(0, $max) / $max * $sum; $sum = 0; foreach ( $weights as $i => $w ) { @@ -77,8 +97,10 @@ class LoadBalancer { # don't work $loads = $this->mLoads; do { - $i = pickRandom( $loads ); + $i = $this->pickRandom( $loads ); if ( $i !== false ) { + wfDebug( "Using reader #$i: {$this->mServers[$i]}\n" ); + $conn =& $this->getConnection( $i ); if ( !$conn->isOpen() ) { unset( $loads[$i] ); @@ -96,21 +118,49 @@ class LoadBalancer { } return $conn; } - + function &getConnection( $i, $fail = false ) { - if ( !array_key_exists( $i, $this->mConnections) || !$this->mConnections[$i]->isOpen() ) { - $this->mConnections[$i] = Database::newFromParams( $this->mServers[$i], $this->mUser, - $this->mPassword, $this->mDbName, 1 ); - } - if ( !$this->mConnections[$i]->isOpen() ) { - wfDebug( "Failed to connect to database $i at {$this->mServers[$i]}\n" ); - if ( $fail ) { - $this->reportConnectionError( $this->mConnections[$i] ); + /* + # Task-based index + if ( $i >= DB_TASK_FIRST && $i < DB_TASK_LAST ) { + if ( $i % 2 ) { + # Odd index use writer + $i = DB_WRITE; + } else { + # Even index use reader + $i = DB_READ; + } + }*/ + + # Operation-based index + # Note, getReader() and getWriter() will re-enter this function + if ( $i == DB_READ ) { + $this->mLastConn =& $this->getReader(); + } elseif ( $i == DB_WRITE ) { + $this->mLastConn =& $this->getWriter(); + } elseif ( $i == DB_LAST ) { + # Just use $this->mLastConn, which should already be set + if ( $this->mLastConn === false ) { + # Oh dear, not set, best to use the writer for safety + $this->mLastConn =& $this->getWriter(); + } + } else { + # Explicit index + if ( !array_key_exists( $i, $this->mConnections) || !$this->mConnections[$i]->isOpen() ) { + $this->mConnections[$i] = Database::newFromParams( $this->mServers[$i], $this->mUser, + $this->mPassword, $this->mDbName, 1 ); + } + if ( !$this->mConnections[$i]->isOpen() ) { + wfDebug( "Failed to connect to database $i at {$this->mServers[$i]}\n" ); + if ( $fail ) { + $this->reportConnectionError( $this->mConnections[$i] ); + } + $this->mConnections[$i] = false; } - $this->mConnections[$i] = false; + $this->mLastConn =& $this->mConnections[$i]; } - return $this->mConnections[$i]; + return $this->mLastConn; } function reportConnectionError( &$conn ) @@ -129,8 +179,8 @@ class LoadBalancer { function &getWriter() { $c =& $this->getConnection( 0 ); - if ( !$c->isOpen() ) { - reportConnectionError( $conn ); + if ( $c === false || !$c->isOpen() ) { + $this->reportConnectionError( $c ); $c = false; } return $c; @@ -140,4 +190,9 @@ class LoadBalancer { { $this->mForce = $i; } + + function haveIndex( $i ) + { + return array_key_exists( $i, $this->mServers ); + } } diff --git a/includes/MagicWord.php b/includes/MagicWord.php index 9089d5108a2c..bb7b7c1640b3 100644 --- a/includes/MagicWord.php +++ b/includes/MagicWord.php @@ -110,7 +110,7 @@ class MagicWord { $this->mRegexStart = "/^{$this->mBaseRegex}/{$case}"; $this->mVariableRegex = str_replace( "\\$1", "([$variableClass]*?)", $this->mRegex ); $this->mVariableStartToEndRegex = str_replace( "\\$1", "([$variableClass]*?)", - "/^{$this->mBaseRegex}$/{$case}" ); + "/^({$this->mBaseRegex})$/{$case}" ); } # Gets a regex representing matching the word diff --git a/includes/Math.php b/includes/Math.php index 5946061fb48f..8b03af6adcbb 100644 --- a/includes/Math.php +++ b/includes/Math.php @@ -30,7 +30,7 @@ class MathRenderer { if( $this->mode == MW_MATH_SOURCE ) { # No need to render or parse anything more! - return ('$ '.htmlspecialchars( $tex ).' $'); + return ('$ '.htmlspecialchars( $this->tex ).' $'); } if( !$this->_recall() ) { @@ -182,7 +182,7 @@ class MathRenderer { (($this->mode == MW_MATH_MODERN || $this->mode == MW_MATH_MATHML) && ($this->conservativeness == 0))) { return $this->_linkToMathImage(); } else { - return $this->html; + return '<span class="texhtml">'.$this->html.'</span>'; } } diff --git a/includes/MessageCache.php b/includes/MessageCache.php index 66285e18b936..4aee8583134d 100755 --- a/includes/MessageCache.php +++ b/includes/MessageCache.php @@ -81,7 +81,7 @@ class MessageCache function loadFromDB() { $fname = "MessageCache::loadFromDB"; - $sql = "SELECT cur_title,cur_text FROM cur WHERE cur_namespace=" . NS_MEDIAWIKI; + $sql = "SELECT cur_title,cur_text FROM cur WHERE cur_is_redirect=0 AND cur_namespace=" . NS_MEDIAWIKI; $res = wfQuery( $sql, DB_READ, $fname ); $this->mCache = array(); diff --git a/includes/ObjectCache.php b/includes/ObjectCache.php index 00864c6b16b1..ce511ff37b10 100644 --- a/includes/ObjectCache.php +++ b/includes/ObjectCache.php @@ -1,4 +1,6 @@ <?php +# $Id$ +# # Copyright (C) 2003-2004 Brion Vibber <brion@pobox.com> # http://www.mediawiki.org/ # @@ -69,8 +71,10 @@ class /* abstract */ BagOStuff { } function add($key, $value, $exptime=0) { - if( $this->get($key) === false ) + if( $this->get($key) == false ) { $this->set($key, $value, $exptime); + return true; + } } function add_multi($hash, $exptime=0) { @@ -114,7 +118,7 @@ class /* abstract */ BagOStuff { function _debug($text) { if($this->debugmode) - echo "\ndebug: $text\n"; + wfDebug("BagOStuff debug: $text\n"); } } @@ -187,9 +191,9 @@ class /* abstract */ SqlBagOStuff extends BagOStuff { $this->_debug("get: ** error: " . $this->_dberror($res) . " **"); return false; } - if($arr = $this->_fetchrow($res)) { - $this->_debug("get: retrieved data; exp time is " . $arr['exptime']); - return unserialize($arr['value']); + if($row=$this->_fetchobject($res)) { + $this->_debug("get: retrieved data; exp time is " . $row->exptime); + return unserialize($row->value); } else { $this->_debug("get: no matching rows"); } @@ -208,8 +212,8 @@ class /* abstract */ SqlBagOStuff extends BagOStuff { } $this->delete( $key ); $this->_query( - "INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2',$exp)", - $key, serialize(&$value)); + "INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2','$exp')", + $key, serialize($value)); return true; /* ? */ } @@ -230,7 +234,7 @@ class /* abstract */ SqlBagOStuff extends BagOStuff { $sql); } $res = $this->_doquery($sql); - if($res === false) { + if($res == false) { $this->_debug("query failed: " . $this->_dberror($res)); } return $res; @@ -269,7 +273,8 @@ class /* abstract */ SqlBagOStuff extends BagOStuff { function expireall() { /* Remove any items that have expired */ - $this->_query( "DELETE FROM $0 WHERE exptime<=NOW()" ); + $now=$this->_fromunixtime(time()); + $this->_query( "DELETE FROM $0 WHERE exptime<'$now'" ); } function deleteall() { @@ -278,42 +283,27 @@ class /* abstract */ SqlBagOStuff extends BagOStuff { } } -class MysqlBagOStuff extends SqlBagOStuff { +class MediaWikiBagOStuff extends SqlBagOStuff { function _doquery($sql) { - return mysql_query($sql); + return wfQuery($sql, DB_READ, "MediaWikiBagOStuff:_doquery"); } - function _fetchrow($result) { - return mysql_fetch_array($result); + function _fetchobject($result) { + return wfFetchObject($result); } function _freeresult($result) { - return mysql_free_result($result); + return wfFreeResult($result); } function _dberror($result) { - if($result) - return mysql_error($result); - else - return mysql_error(); + return wfLastError(); } - function _maxdatetime() { - return "'9999-12-31 12:59:59'"; + return "9999-12-31 12:59:59"; } - function _fromunixtime($ts) { - return "FROM_UNIXTIME($ts)"; + return gmdate( "Y-m-d H:i:s", $ts ); } - function _strencode($s) { - return mysql_escape_string($s); - } -} - -class MediaWikiBagOStuff extends MysqlBagOStuff { - function _doquery($sql) { - return wfQuery($sql, DB_READ, "MediaWikiBagOStuff:_doquery"); - } - function _freeresult($result) { - return wfFreeResult($result); + return wfStrEncode($s); } } diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 7860a4228f23..50d0d38bfe48 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -181,10 +181,24 @@ class OutputPage { } function getLanguageLinks() { - global $wgTitle, $wgLanguageCode; - global $wgDBconnection, $wgDBname; return $this->mLanguageLinks; } + function addLanguageLinks($newLinkArray) { + $this->mLanguageLinks += $newLinkArray; + } + function setLanguageLinks($newLinkArray) { + $this->mLanguageLinks = $newLinkArray; + } + function getCategoryLinks() { + return $this->mCategoryLinks; + } + function addCategoryLinks($newLinkArray) { + $this->mCategoryLinks += $newLinkArray; + } + function setCategoryLinks($newLinkArray) { + $this->mCategoryLinks += $newLinkArray; + } + function suppressQuickbar() { $this->mSuppressQuickbar = true; } function isQuickbarSuppressed() { return $this->mSuppressQuickbar; } @@ -204,26 +218,30 @@ class OutputPage { function addWikiText( $text, $linestart = true, $cacheArticle = NULL ) { global $wgParser, $wgParserCache, $wgUser, $wgTitle; - - $parserOutput = false; + + $parserOutput = $wgParser->parse( $text, $wgTitle, $this->mParserOptions, $linestart ); if ( $cacheArticle ) { - $parserOutput = $wgParserCache->get( $cacheArticle, $wgUser ); - } - - if ( $parserOutput === false ) { - $parserOutput = $wgParser->parse( $text, $wgTitle, $this->mParserOptions, $linestart ); - if ( $cacheArticle ) { - $wgParserCache->save( $parserOutput, $cacheArticle, $wgUser ); - } + $wgParserCache->save( $parserOutput, $cacheArticle, $wgUser ); } $this->mLanguageLinks += $parserOutput->getLanguageLinks(); $this->mCategoryLinks += $parserOutput->getCategoryLinks(); - $this->addHTML( $parserOutput->getText() ); - } + function tryParserCache( $article, $user ) { + global $wgParserCache; + $parserOutput = $wgParserCache->get( $article, $user ); + if ( $parserOutput !== false ) { + $this->mLanguageLinks += $parserOutput->getLanguageLinks(); + $this->mCategoryLinks += $parserOutput->getCategoryLinks(); + $this->addHTML( $parserOutput->getText() ); + return true; + } else { + return false; + } + } + # Set the maximum cache time on the Squid in seconds function setSquidMaxage( $maxage ) { $this->mSquidMaxage = $maxage; @@ -407,8 +425,22 @@ class OutputPage { list( $usec, $sec ) = explode( " ", $wgRequestTime ); $start = (float)$sec + (float)$usec; $elapsed = $now - $start; - $com = sprintf( "<!-- Time since request: %01.2f secs. -->", - $elapsed ); + + # Use real server name if available, so we know which machine + # in a server farm generated the current page. + if ( function_exists( "posix_uname" ) ) { + $uname = @posix_uname(); + } else { + $uname = false; + } + if( is_array( $uname ) && isset( $uname['nodename'] ) ) { + $hostname = $uname['nodename']; + } else { + # This may be a virtual server. + $hostname = $_SERVER['SERVER_NAME']; + } + $com = sprintf( "<!-- Served by %s in %01.2f secs. -->", + $hostname, $elapsed ); return $com; } @@ -486,7 +518,7 @@ class OutputPage { $this->returnToMain(); # Flip back to the main page after 10 seconds. } - function databaseError( $fname, &$conn ) + function databaseError( $fname, $sql, $error, $errno ) { global $wgUser, $wgCommandLineMode; @@ -501,10 +533,10 @@ class OutputPage { $msg = wfMsgNoDB( "dberrortext" ); } - $msg = str_replace( "$1", htmlspecialchars( $conn->lastQuery() ), $msg ); + $msg = str_replace( "$1", htmlspecialchars( $sql ), $msg ); $msg = str_replace( "$2", htmlspecialchars( $fname ), $msg ); - $msg = str_replace( "$3", $conn->lastErrno(), $msg ); - $msg = str_replace( "$4", htmlspecialchars( $conn->lastError() ), $msg ); + $msg = str_replace( "$3", $errno, $msg ); + $msg = str_replace( "$4", htmlspecialchars( $error ), $msg ); if ( $wgCommandLineMode || !is_object( $wgUser )) { print "$msg\n"; @@ -586,6 +618,9 @@ class OutputPage { $this->fatalError( wfMsg( "filenotfound", $name ) ); } + // return from error messages or notes + // auto: automatically redirect the user after 10 seconds + // returnto: page title to return to. Default is Main Page. function returnToMain( $auto = true, $returnto = NULL ) { global $wgUser, $wgOut, $wgRequest; diff --git a/includes/PageHistory.php b/includes/PageHistory.php index 49b42f3f2a7e..3eeaa9d419fa 100644 --- a/includes/PageHistory.php +++ b/includes/PageHistory.php @@ -17,7 +17,7 @@ class PageHistory { function history() { - global $wgUser, $wgOut, $wgLang; + global $wgUser, $wgOut, $wgLang, $wgIsMySQL, $wgIsPg; # If page hasn't changed, client can cache this @@ -54,12 +54,14 @@ class PageHistory { $namespace = $this->mTitle->getNamespace(); $title = $this->mTitle->getText(); + $use_index=$wgIsMySQL?"USE INDEX (name_title_timestamp)":""; + $oldtable=$wgIsPg?'"old"':'old'; $sql = "SELECT old_id,old_user," . "old_comment,old_user_text,old_timestamp,old_minor_edit ". - "FROM old USE INDEX (name_title_timestamp) " . + "FROM $oldtable $use_index " . "WHERE old_namespace={$namespace} AND " . "old_title='" . wfStrencode( $this->mTitle->getDBkey() ) . "' " . - "ORDER BY inverse_timestamp LIMIT $rawoffset, $limitplus"; + "ORDER BY inverse_timestamp".wfLimitResult($limitplus,$rawoffset); $res = wfQuery( $sql, DB_READ, $fname ); $revs = wfNumRows( $res ); @@ -77,6 +79,12 @@ class PageHistory { $this->mTitle->getPrefixedText(), "action=history", $atend ); $s = $numbar; + if($this->linesonpage > 0) { + $submitpart1 = '<input class="historysubmit" type="submit" accesskey="'.wfMsg('accesskey-compareselectedversions'). + '" title="'.wfMsg('tooltip-compareselectedversions').'" value="'.wfMsg('compareselectedversions').'"'; + $this->submitbuttonhtml1 = $submitpart1 . ' />'; + $this->submitbuttonhtml2 = $submitpart1 . ' id="historysubmit" />'; + } $s .= $this->beginHistoryList(); $counter = 1; if( $offset == 0 ){ @@ -110,9 +118,10 @@ class PageHistory { global $wgTitle; $this->lastdate = $this->lastline = ""; $s = "\n<p>" . wfMsg( "histlegend" ).'</p>'; - $s .="\n<form id=\"pagehistory\" name=\"pagehistory\" action=\"" . $wgTitle->getFullURL("-") . "\" method=\"get\">"; - $s .= "<input type=\"hidden\" name=\"title\" value=\"".htmlspecialchars($wgTitle->getPrefixedDbKey())."\"/>\n"; - $s .= "" . "\n<ul>"; + $s .="\n<form action=\"" . $wgTitle->escapeLocalURL( '-' ) . "\" method=\"get\">"; + $s .= "<input type=\"hidden\" name=\"title\" value=\"".wfEscapeHTML($wgTitle->getPrefixedDbKey())."\"/>\n"; + $s .= !empty($this->submitbuttonhtml1) ? $this->submitbuttonhtml1."\n":''; + $s .= "" . "\n<ul id=\"pagehistory\" >"; return $s; } @@ -121,11 +130,8 @@ class PageHistory { $last = wfMsg( "last" ); $s = $skip ? "" : preg_replace( "/!OLDID![0-9]+!/", $last, $this->lastline ); - $s .= "</ul>\n"; - if( $this->linesonpage > 1) { - $s .= '<button type="submit" accesskey="'.wfMsg('accesskey-compareselectedversions'). - '" title="'.wfMsg('tooltip-compareselectedversions').'">'.wfMsg('compareselectedversions')."</button><br/><br/>\n"; - } + $s .= "</ul>"; + $s .= !empty($this->submitbuttonhtml2) ? $this->submitbuttonhtml2."\n":''; $s .= "</form>\n"; return $s; } @@ -156,10 +162,10 @@ class PageHistory { if ( 0 == $u ) { $ul = $this->mSkin->makeKnownLink( $wgLang->specialPage( "Contributions" ), - $ut, "target=" . $ut ); + htmlspecialchars( $ut ), "target=" . urlencode( $ut ) ); } else { $ul = $this->mSkin->makeLink( $wgLang->getNsText( - Namespace::getUser() ) . ":{$ut}", $ut ); + Namespace::getUser() ) . ":{$ut}", htmlspecialchars( $ut ) ); } $s = "<li>"; diff --git a/includes/Parser.php b/includes/Parser.php index c345e28eec22..31cb12554a6d 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -1,13 +1,6 @@ <?php -require_once('Tokenizer.php'); - -if( $GLOBALS['wgUseWikiHiero'] ){ - require_once('extensions/wikihiero/wikihiero.php'); -} -if( $GLOBALS['wgUseTimeline'] ){ - require_once('extensions/timeline/Timeline.php'); -} +// require_once('Tokenizer.php'); # PHP Parser # @@ -55,6 +48,9 @@ define( "UNIQ_PREFIX", "NaodW29"); class Parser { + # Persistent: + var $mTagHooks; + # Cleared with clearState(): var $mOutput, $mAutonumber, $mDTopen, $mStripState = array(); var $mVariables, $mIncludeCount, $mArgStack, $mLastSection, $mInPre; @@ -62,13 +58,12 @@ class Parser # Temporary: var $mOptions, $mTitle, $mOutputType; - function Parser() - { + function Parser() { + $this->mTagHooks = array(); $this->clearState(); } - function clearState() - { + function clearState() { $this->mOutput = new ParserOutput; $this->mAutonumber = 0; $this->mLastSection = ""; @@ -77,6 +72,7 @@ class Parser $this->mIncludeCount = array(); $this->mStripState = array(); $this->mArgStack = array(); + $this->mInPre = false; } # First pass--just handle <nowiki> sections, pass the rest off @@ -84,8 +80,7 @@ class Parser # # Returns a ParserOutput # - function parse( $text, &$title, $options, $linestart = true, $clearState = true ) - { + function parse( $text, &$title, $options, $linestart = true, $clearState = true ) { global $wgUseTidy; $fname = "Parser::parse"; wfProfileIn( $fname ); @@ -105,10 +100,15 @@ class Parser # Clean up special characters, only run once, next-to-last before doBlockLevels if(!$wgUseTidy) { $fixtags = array( - "/<hr *>/i" => '<hr/>', - "/<br *>/i" => '<br/>', - "/<center *>/i"=>'<div class="center">', - "/<\\/center *>/i" => '</div>', + # french spaces, last one Guillemet-left + # only if there is something before the space + '/(.) (\\?|:|!|\\302\\273)/i' => '\\1 \\2', + # french spaces, Guillemet-right + "/(\\302\\253) /i"=>"\\1 ", + '/<hr *>/i' => '<hr />', + '/<br *>/i' => '<br />', + '/<center *>/i' => '<div class="center">', + '/<\\/center *>/i' => '</div>', # Clean up spare ampersands; note that we probably ought to be # more careful about named entities. '/&(?!:amp;|#[Xx][0-9A-fa-f]+;|#[0-9]+;|[a-zA-Z0-9]+;)/' => '&' @@ -116,13 +116,18 @@ class Parser $text = preg_replace( array_keys($fixtags), array_values($fixtags), $text ); } else { $fixtags = array( - "/<center *>/i"=>'<div class="center">', - "/<\\/center *>/i" => '</div>' + # french spaces, last one Guillemet-left + '/ (\\?|:|!|\\302\\273)/i' => ' \\1', + # french spaces, Guillemet-right + '/(\\302\\253) /i' => '\\1 ', + '/<center *>/i' => '<div class="center">', + '/<\\/center *>/i' => '</div>' ); $text = preg_replace( array_keys($fixtags), array_values($fixtags), $text ); } # only once and last $text = $this->doBlockLevels( $text, $linestart ); + $text = $this->unstripNoWiki( $text, $this->mStripState ); if($wgUseTidy) { $text = $this->tidy($text); } @@ -131,8 +136,7 @@ class Parser return $this->mOutput; } - /* static */ function getRandomString() - { + /* static */ function getRandomString() { return dechex(mt_rand(0, 0x7fffffff)) . dechex(mt_rand(0, 0x7fffffff)); } @@ -152,24 +156,24 @@ class Parser $content = array( ); } $n = 1; - $stripped = ""; + $stripped = ''; - while ( "" != $text ) { + while ( '' != $text ) { if($tag==STRIP_COMMENTS) { - $p = preg_split( "/<!--/i", $text, 2 ); + $p = preg_split( '/<!--/i', $text, 2 ); } else { $p = preg_split( "/<\\s*$tag\\s*>/i", $text, 2 ); } $stripped .= $p[0]; - if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { - $text = ""; + if ( ( count( $p ) < 2 ) || ( '' == $p[1] ) ) { + $text = ''; } else { if($tag==STRIP_COMMENTS) { - $q = preg_split( "/-->/i", $p[1], 2 ); + $q = preg_split( '/-->/i', $p[1], 2 ); } else { $q = preg_split( "/<\\/\\s*$tag\\s*>/i", $p[1], 2 ); } - $marker = $rnd . sprintf("%08X", $n++); + $marker = $rnd . sprintf('%08X', $n++); $content[$marker] = $q[0]; $stripped .= $marker; $text = $q[1]; @@ -187,20 +191,21 @@ class Parser # will be stripped in addition to other tags. This is important # for section editing, where these comments cause confusion when # counting the sections in the wikisource - function strip( $text, &$state, $stripcomments = false ) - { + function strip( $text, &$state, $stripcomments = false ) { $render = ($this->mOutputType == OT_HTML); $nowiki_content = array(); - $hiero_content = array(); $math_content = array(); $pre_content = array(); $comment_content = array(); - + $ext_content = array(); + # Replace any instances of the placeholders $uniq_prefix = UNIQ_PREFIX; #$text = str_replace( $uniq_prefix, wfHtmlEscapeFirst( $uniq_prefix ), $text ); - $text = Parser::extractTags("nowiki", $text, $nowiki_content, $uniq_prefix); + + # nowiki + $text = Parser::extractTags('nowiki', $text, $nowiki_content, $uniq_prefix); foreach( $nowiki_content as $marker => $content ){ if( $render ){ $nowiki_content[$marker] = wfEscapeHTMLTagsOnly( $content ); @@ -209,16 +214,8 @@ class Parser } } - $text = Parser::extractTags("hiero", $text, $hiero_content, $uniq_prefix); - foreach( $hiero_content as $marker => $content ){ - if( $render && $GLOBALS['wgUseWikiHiero']){ - $hiero_content[$marker] = WikiHiero( $content, WH_MODE_HTML); - } else { - $hiero_content[$marker] = "<hiero>$content</hiero>"; - } - } - - $text = Parser::extractTags("math", $text, $math_content, $uniq_prefix); + # math + $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix); foreach( $math_content as $marker => $content ){ if( $render ) { if( $this->mOptions->getUseTeX() ) { @@ -231,14 +228,17 @@ class Parser } } - $text = Parser::extractTags("pre", $text, $pre_content, $uniq_prefix); + # pre + $text = Parser::extractTags('pre', $text, $pre_content, $uniq_prefix); foreach( $pre_content as $marker => $content ){ if( $render ){ - $pre_content[$marker] = "<pre>" . wfEscapeHTMLTagsOnly( $content ) . "</pre>"; + $pre_content[$marker] = '<pre>' . wfEscapeHTMLTagsOnly( $content ) . '</pre>'; } else { $pre_content[$marker] = "<pre>$content</pre>"; } } + + # Comments if($stripcomments) { $text = Parser::extractTags(STRIP_COMMENTS, $text, $comment_content, $uniq_prefix); foreach( $comment_content as $marker => $content ){ @@ -246,49 +246,75 @@ class Parser } } + # Extensions + foreach ( $this->mTagHooks as $tag => $callback ) { + $ext_contents[$tag] = array(); + $text = Parser::extractTags( $tag, $text, $ext_content[$tag], $uniq_prefix ); + foreach( $ext_content[$tag] as $marker => $content ) { + if ( $render ) { + $ext_content[$tag][$marker] = $callback( $content ); + } else { + $ext_content[$tag][$marker] = "<$tag>$content</$tag>"; + } + } + } + # Merge state with the pre-existing state, if there is one if ( $state ) { $state['nowiki'] = $state['nowiki'] + $nowiki_content; - $state['hiero'] = $state['hiero'] + $hiero_content; $state['math'] = $state['math'] + $math_content; $state['pre'] = $state['pre'] + $pre_content; $state['comment'] = $state['comment'] + $comment_content; + + foreach( $ext_content as $tag => $array ) { + if ( array_key_exists( $tag, $state ) ) { + $state[$tag] = $state[$tag] + $array; + } + } } else { $state = array( 'nowiki' => $nowiki_content, - 'hiero' => $hiero_content, 'math' => $math_content, 'pre' => $pre_content, - 'comment' => $comment_content - ); + 'comment' => $comment_content, + ) + $ext_content; } return $text; } - function unstrip( $text, &$state ) - { + # always call unstripNoWiki() after this one + function unstrip( $text, &$state ) { # Must expand in reverse order, otherwise nested tags will be corrupted $contentDict = end( $state ); for ( $contentDict = end( $state ); $contentDict !== false; $contentDict = prev( $state ) ) { - for ( $content = end( $contentDict ); $content !== false; $content = prev( $contentDict ) ) { - $text = str_replace( key( $contentDict ), $content, $text ); + if( key($state) != 'nowiki') { + for ( $content = end( $contentDict ); $content !== false; $content = prev( $contentDict ) ) { + $text = str_replace( key( $contentDict ), $content, $text ); + } } } return $text; } + # always call this after unstrip() to preserve the order + function unstripNoWiki( $text, &$state ) { + # Must expand in reverse order, otherwise nested tags will be corrupted + for ( $content = end($state['nowiki']); $content !== false; $content = prev( $state['nowiki'] ) ) { + $text = str_replace( key( $state['nowiki'] ), $content, $text ); + } + + return $text; + } # Add an item to the strip state # Returns the unique tag which must be inserted into the stripped text # The tag will be replaced with the original text in unstrip() - function insertStripItem( $text, &$state ) - { + function insertStripItem( $text, &$state ) { $rnd = UNIQ_PREFIX . '-item' . Parser::getRandomString(); if ( !$state ) { $state = array( 'nowiki' => array(), - 'hiero' => array(), 'math' => array(), 'pre' => array() ); @@ -297,9 +323,24 @@ class Parser return $rnd; } + # categoryMagic + # generate a list of subcategories and pages for a category + # depending on wfMsg("usenewcategorypage") it either calls the new + # or the old code. The new code will not work properly for some + # languages due to sorting issues, so they might want to turn it + # off. + function categoryMagic() { + $msg = wfMsg('usenewcategorypage'); + if ( '0' == @$msg[0] ) + { + return $this->oldCategoryMagic(); + } else { + return $this->newCategoryMagic(); + } + } + # This method generates the list of subcategories and pages for a category - function categoryMagic () - { + function oldCategoryMagic () { global $wgLang , $wgUser ; if ( !$this->mOptions->getUseCategoryMagic() ) return ; # Doesn't use categories at all @@ -339,66 +380,247 @@ class Parser # Showing subcategories if ( count ( $children ) > 0 ) { - $r .= "<h2>".wfMsg("subcategories")."</h2>\n" ; - $r .= implode ( ", " , $children ) ; + $r .= '<h2>'.wfMsg('subcategories')."</h2>\n" ; + $r .= implode ( ', ' , $children ) ; } # Showing pages in this category if ( count ( $articles ) > 0 ) { $ti = $this->mTitle->getText() ; - $h = wfMsg( "category_header", $ti ); + $h = wfMsg( 'category_header', $ti ); $r .= "<h2>{$h}</h2>\n" ; - $r .= implode ( ", " , $articles ) ; + $r .= implode ( ', ' , $articles ) ; } return $r ; } - function getHTMLattrs () - { + + + function newCategoryMagic () { + global $wgLang , $wgUser ; + if ( !$this->mOptions->getUseCategoryMagic() ) return ; # Doesn't use categories at all + + $cns = Namespace::getCategory() ; + if ( $this->mTitle->getNamespace() != $cns ) return '' ; # This ain't a category page + + $r = "<br style=\"clear:both;\"/>\n"; + + + $sk =& $wgUser->getSkin() ; + + $articles = array() ; + $articles_start_char = array(); + $children = array() ; + $children_start_char = array(); + $data = array () ; + $id = $this->mTitle->getArticleID() ; + + # FIXME: add limits + $t = wfStrencode( $this->mTitle->getDBKey() ); + $sql = "SELECT DISTINCT cur_title,cur_namespace,cl_sortkey FROM +cur,categorylinks WHERE cl_to='$t' AND cl_from=cur_id ORDER BY +cl_sortkey" ; + $res = wfQuery ( $sql, DB_READ ) ; + while ( $x = wfFetchObject ( $res ) ) + { + $t = $ns = $wgLang->getNsText ( $x->cur_namespace ) ; + if ( $t != '' ) $t .= ':' ; + $t .= $x->cur_title ; + + if ( $x->cur_namespace == $cns ) { + $ctitle = str_replace( '_',' ',$x->cur_title ); + array_push ( $children, $sk->makeKnownLink ( $t, $ctitle ) ) ; # Subcategory + + // If there's a link from Category:A to Category:B, the sortkey of the resulting + // entry in the categorylinks table is Category:A, not A, which it SHOULD be. + // Workaround: If sortkey == "Category:".$title, than use $title for sorting, + // else use sortkey... + if ( ($ns.":".$ctitle) == $x->cl_sortkey ) { + array_push ( $children_start_char, $wgLang->firstChar( $x->cur_title ) ); + } else { + array_push ( $children_start_char, $wgLang->firstChar( $x->cl_sortkey ) ) ; + } + } else { + array_push ( $articles , $sk->makeLink ( $t ) ) ; # Page in this category + array_push ( $articles_start_char, $wgLang->firstChar( $x->cl_sortkey ) ) ; + } + } + wfFreeResult ( $res ) ; + + $ti = $this->mTitle->getText() ; + + # Don't show subcategories section if there are none. + if ( count ( $children ) > 0 ) + { + # Showing subcategories + $r .= '<h2>' . wfMsg( 'subcategories' ) . "</h2>\n" + . wfMsg( 'subcategorycount', count( $children ) ); + if ( count ( $children ) > 6 ) { + + // divide list into three equal chunks + $chunk = (int) (count ( $children ) / 3); + + // get and display header + $r .= '<table width="100%"><tr valign="top">'; + + $startChunk = 0; + $endChunk = $chunk; + + // loop through the chunks + for($startChunk = 0, $endChunk = $chunk, $chunkIndex = 0; + $chunkIndex < 3; + $chunkIndex++, $startChunk = $endChunk, $endChunk += $chunk + 1) + { + + $r .= '<td><ul>'; + // output all subcategories to category + for ($index = $startChunk ; + $index < $endChunk && $index < count($children); + $index++ ) + { + // check for change of starting letter or begging of chunk + if ( ($children_start_char[$index] != $children_start_char[$index - 1]) + || ($index == $startChunk) ) + { + $r .= "</ul><h3>{$children_start_char[$index]}</h3>\n<ul>"; + } + + $r .= "<li>{$children[$index]}</li>"; + } + $r .= '</ul></td>'; + + + } + $r .= '</tr></table>'; + } else { + // for short lists of subcategories to category. + + $r .= "<h3>{$children_start_char[0]}</h3>\n"; + $r .= '<ul><li>'.$children[0].'</li>'; + for ($index = 1; $index < count($children); $index++ ) + { + if ($children_start_char[$index] != $children_start_char[$index - 1]) + { + $r .= "</ul><h3>{$children_start_char[$index]}</h3>\n<ul>"; + } + + $r .= "<li>{$children[$index]}</li>"; + } + $r .= '</ul>'; + } + } # END of if ( count($children) > 0 ) + + $r .= '<h2>' . wfMsg( 'category_header', $ti ) . "</h2>\n" . + wfMsg( 'categoryarticlecount', count( $articles ) ); + + # Showing articles in this category + if ( count ( $articles ) > 6) { + $ti = $this->mTitle->getText() ; + + // divide list into three equal chunks + $chunk = (int) (count ( $articles ) / 3); + + // get and display header + $r .= '<table width="100%"><tr valign="top">'; + + // loop through the chunks + for($startChunk = 0, $endChunk = $chunk, $chunkIndex = 0; + $chunkIndex < 3; + $chunkIndex++, $startChunk = $endChunk, $endChunk += $chunk + 1) + { + + $r .= '<td><ul>'; + + // output all articles in category + for ($index = $startChunk ; + $index < $endChunk && $index < count($articles); + $index++ ) + { + // check for change of starting letter or begging of chunk + if ( ($articles_start_char[$index] != $articles_start_char[$index - 1]) + || ($index == $startChunk) ) + { + $r .= "</ul><h3>{$articles_start_char[$index]}</h3>\n<ul>"; + } + + $r .= "<li>{$articles[$index]}</li>"; + } + $r .= '</ul></td>'; + + + } + $r .= '</tr></table>'; + } elseif ( count ( $articles ) > 0) { + // for short lists of articles in categories. + $ti = $this->mTitle->getText() ; + + $r .= '<h3>'.$articles_start_char[0]."</h3>\n"; + $r .= '<ul><li>'.$articles[0].'</li>'; + for ($index = 1; $index < count($articles); $index++ ) + { + if ($articles_start_char[$index] != $articles_start_char[$index - 1]) + { + $r .= "</ul><h3>{$articles_start_char[$index]}</h3>\n<ul>"; + } + + $r .= "<li>{$articles[$index]}</li>"; + } + $r .= '</ul>'; + } + + + return $r ; + } + + # Return allowed HTML attributes + function getHTMLattrs () { $htmlattrs = array( # Allowed attributes--no scripting, etc. - "title", "align", "lang", "dir", "width", "height", - "bgcolor", "clear", /* BR */ "noshade", /* HR */ - "cite", /* BLOCKQUOTE, Q */ "size", "face", "color", - /* FONT */ "type", "start", "value", "compact", + 'title', 'align', 'lang', 'dir', 'width', 'height', + 'bgcolor', 'clear', /* BR */ 'noshade', /* HR */ + 'cite', /* BLOCKQUOTE, Q */ 'size', 'face', 'color', + /* FONT */ 'type', 'start', 'value', 'compact', /* For various lists, mostly deprecated but safe */ - "summary", "width", "border", "frame", "rules", - "cellspacing", "cellpadding", "valign", "char", - "charoff", "colgroup", "col", "span", "abbr", "axis", - "headers", "scope", "rowspan", "colspan", /* Tables */ - "id", "class", "name", "style" /* For CSS */ + 'summary', 'width', 'border', 'frame', 'rules', + 'cellspacing', 'cellpadding', 'valign', 'char', + 'charoff', 'colgroup', 'col', 'span', 'abbr', 'axis', + 'headers', 'scope', 'rowspan', 'colspan', /* Tables */ + 'id', 'class', 'name', 'style' /* For CSS */ ); return $htmlattrs ; } - function fixTagAttributes ( $t ) - { - if ( trim ( $t ) == "" ) return "" ; # Saves runtime ;-) + # Remove non approved attributes and javascript in css + function fixTagAttributes ( $t ) { + if ( trim ( $t ) == '' ) return '' ; # Saves runtime ;-) $htmlattrs = $this->getHTMLattrs() ; # Strip non-approved attributes from the tag $t = preg_replace( - "/(\\w+)(\\s*=\\s*([^\\s\">]+|\"[^\">]*\"))?/e", + '/(\\w+)(\\s*=\\s*([^\\s\">]+|\"[^\">]*\"))?/e', "(in_array(strtolower(\"\$1\"),\$htmlattrs)?(\"\$1\".((\"x\$3\" != \"x\")?\"=\$3\":'')):'')", $t); # Strip javascript "expression" from stylesheets. Brute force approach: # If anythin offensive is found, all attributes of the HTML tag are dropped if( preg_match( - "/style\\s*=.*(expression|tps*:\/\/|url\\s*\().*/is", + '/style\\s*=.*(expression|tps*:\/\/|url\\s*\().*/is', wfMungeToUtf8( $t ) ) ) { - $t=""; + $t=''; } return trim ( $t ) ; } - /* interface with html tidy, used if $wgUseTidy = true */ + # interface with html tidy, used if $wgUseTidy = true function tidy ( $text ) { global $wgTidyConf, $wgTidyBin, $wgTidyOpts; global $wgInputEncoding, $wgOutputEncoding; + $fname = 'Parser::tidy'; + wfProfileIn( $fname ); + $cleansource = ''; switch(strtoupper($wgOutputEncoding)) { case 'ISO-8859-1': @@ -411,17 +633,17 @@ class Parser $wgTidyOpts .= ' -raw'; } - $text = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'. + $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'. ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>'. '<head><title>test</title></head><body>'.$text.'</body></html>'; $descriptorspec = array( - 0 => array("pipe", "r"), - 1 => array("pipe", "w"), - 2 => array("file", "/dev/null", "a") + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('file', '/dev/null', 'a') ); $process = proc_open("$wgTidyBin -config $wgTidyConf $wgTidyOpts", $descriptorspec, $pipes); if (is_resource($process)) { - fwrite($pipes[0], $text); + fwrite($pipes[0], $wrappedtext); fclose($pipes[0]); while (!feof($pipes[1])) { $cleansource .= fgets($pipes[1], 1024); @@ -429,15 +651,19 @@ class Parser fclose($pipes[1]); $return_value = proc_close($process); } + + wfProfileOut( $fname ); + if( $cleansource == '' && $text != '') { - return '<h2>'.wfMsg('seriousxhtmlerrors').'</h2><pre>'.htmlspecialchars($text).'</pre>'; + wfDebug( "Tidy error detected!\n" ); + return $text . "\n<!-- Tidy found serious XHTML errors -->\n"; } else { return $cleansource; } } - function doTableStuff ( $t ) - { + # parse the wiki syntax used to render tables + function doTableStuff ( $t ) { $t = explode ( "\n" , $t ) ; $td = array () ; # Is currently a td tag open? $ltd = array () ; # Was it TD or TH? @@ -447,20 +673,20 @@ class Parser { $x = trim ( $x ) ; $fc = substr ( $x , 0 , 1 ) ; - if ( "{|" == substr ( $x , 0 , 2 ) ) + if ( '{|' == substr ( $x , 0 , 2 ) ) { - $t[$k] = "\n<table " . $this->fixTagAttributes ( substr ( $x , 3 ) ) . ">" ; + $t[$k] = "\n<table " . $this->fixTagAttributes ( substr ( $x , 3 ) ) . '>' ; array_push ( $td , false ) ; - array_push ( $ltd , "" ) ; + array_push ( $ltd , '' ) ; array_push ( $tr , false ) ; - array_push ( $ltr , "" ) ; + array_push ( $ltr , '' ) ; } else if ( count ( $td ) == 0 ) { } # Don't do any of the following - else if ( "|}" == substr ( $x , 0 , 2 ) ) + else if ( '|}' == substr ( $x , 0 , 2 ) ) { $z = "</table>\n" ; $l = array_pop ( $ltd ) ; - if ( array_pop ( $tr ) ) $z = "</tr>" . $z ; + if ( array_pop ( $tr ) ) $z = '</tr>' . $z ; if ( array_pop ( $td ) ) $z = "</{$l}>" . $z ; array_pop ( $ltr ) ; $t[$k] = $z ; @@ -470,51 +696,51 @@ class Parser $z = trim ( substr ( $x , 2 ) ) ; $t[$k] = "<caption>{$z}</caption>\n" ; }*/ - else if ( "|-" == substr ( $x , 0 , 2 ) ) # Allows for |--------------- + else if ( '|-' == substr ( $x , 0 , 2 ) ) # Allows for |--------------- { $x = substr ( $x , 1 ) ; - while ( $x != "" && substr ( $x , 0 , 1 ) == '-' ) $x = substr ( $x , 1 ) ; - $z = "" ; + while ( $x != '' && substr ( $x , 0 , 1 ) == '-' ) $x = substr ( $x , 1 ) ; + $z = '' ; $l = array_pop ( $ltd ) ; - if ( array_pop ( $tr ) ) $z = "</tr>" . $z ; + if ( array_pop ( $tr ) ) $z = '</tr>' . $z ; if ( array_pop ( $td ) ) $z = "</{$l}>" . $z ; array_pop ( $ltr ) ; $t[$k] = $z ; array_push ( $tr , false ) ; array_push ( $td , false ) ; - array_push ( $ltd , "" ) ; + array_push ( $ltd , '' ) ; array_push ( $ltr , $this->fixTagAttributes ( $x ) ) ; } - else if ( "|" == $fc || "!" == $fc || "|+" == substr ( $x , 0 , 2 ) ) # Caption + else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) # Caption { - if ( "|+" == substr ( $x , 0 , 2 ) ) + if ( '|+' == substr ( $x , 0 , 2 ) ) { - $fc = "+" ; + $fc = '+' ; $x = substr ( $x , 1 ) ; } $after = substr ( $x , 1 ) ; - if ( $fc == "!" ) $after = str_replace ( "!!" , "||" , $after ) ; - $after = explode ( "||" , $after ) ; - $t[$k] = "" ; + if ( $fc == '!' ) $after = str_replace ( '!!' , '||' , $after ) ; + $after = explode ( '||' , $after ) ; + $t[$k] = '' ; foreach ( $after AS $theline ) { - $z = "" ; - if ( $fc != "+" ) + $z = '' ; + if ( $fc != '+' ) { $tra = array_pop ( $ltr ) ; if ( !array_pop ( $tr ) ) $z = "<tr {$tra}>\n" ; array_push ( $tr , true ) ; - array_push ( $ltr , "" ) ; + array_push ( $ltr , '' ) ; } $l = array_pop ( $ltd ) ; if ( array_pop ( $td ) ) $z = "</{$l}>" . $z ; - if ( $fc == "|" ) $l = "td" ; - else if ( $fc == "!" ) $l = "th" ; - else if ( $fc == "+" ) $l = "caption" ; - else $l = "" ; + if ( $fc == '|' ) $l = 'td' ; + else if ( $fc == '!' ) $l = 'th' ; + else if ( $fc == '+' ) $l = 'caption' ; + else $l = '' ; array_push ( $ltd , $l ) ; - $y = explode ( "|" , $theline , 2 ) ; + $y = explode ( '|' , $theline , 2 ) ; if ( count ( $y ) == 1 ) $y = "{$z}<{$l}>{$y[0]}" ; else $y = $y = "{$z}<{$l} ".$this->fixTagAttributes($y[0]).">{$y[1]}" ; $t[$k] .= $y ; @@ -526,9 +752,9 @@ class Parser # Closing open td, tr && table while ( count ( $td ) > 0 ) { - if ( array_pop ( $td ) ) $t[] = "</td>" ; - if ( array_pop ( $tr ) ) $t[] = "</tr>" ; - $t[] = "</table>" ; + if ( array_pop ( $td ) ) $t[] = '</td>' ; + if ( array_pop ( $tr ) ) $t[] = '</tr>' ; + $t[] = '</table>' ; } $t = implode ( "\n" , $t ) ; @@ -536,24 +762,38 @@ class Parser return $t ; } - function internalParse( $text, $linestart, $args = array(), $isMain=true ) + # Parses the text and adds the result to the strip state + # Returns the strip tag + function stripParse( $text, $newline, $args ) { - $fname = "Parser::internalParse"; + $text = $this->strip( $text, $this->mStripState ); + $text = $this->internalParse( $text, (bool)$newline, $args, false ); + return $newline.$this->insertStripItem( $text, $this->mStripState ); + } + + function internalParse( $text, $linestart, $args = array(), $isMain=true ) { + $fname = 'Parser::internalParse'; wfProfileIn( $fname ); $text = $this->removeHTMLtags( $text ); $text = $this->replaceVariables( $text, $args ); - # $text = preg_replace( "/(^|\n)-----*/", "\\1<hr>", $text ); + $text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text ); $text = $this->doHeadings( $text ); if($this->mOptions->getUseDynamicDates()) { global $wgDateFormatter; $text = $wgDateFormatter->reformat( $this->mOptions->getDateFormat(), $text ); } + $text = $this->doAllQuotes( $text ); + // $text = $this->doExponent( $text ); $text = $this->replaceExternalLinks( $text ); - $text = $this->doTokenizedParser ( $text ); + $text = $this->replaceInternalLinks ( $text ); + $text = $this->replaceInternalLinks ( $text ); + //$text = $this->doTokenizedParser ( $text ); $text = $this->doTableStuff ( $text ) ; + $text = $this->magicISBN( $text ); + $text = $this->magicRFC( $text ); $text = $this->formatHeadings( $text, $isMain ); $sk =& $this->mOptions->getSkin(); $text = $sk->transformContent( $text ); @@ -566,40 +806,110 @@ class Parser wfProfileOut( $fname ); return $text; } - - - /* private */ function doHeadings( $text ) + + # Parse ^^ tokens and return html + /* private */ function doExponent ( $text ) { + $fname = 'Parser::doExponent'; + wfProfileIn( $fname); + $text = preg_replace('/\^\^(.*)\^\^/','<small><sup>\\1</sup></small>', $text); + wfProfileOut( $fname); + return $text; + } + + # Parse headers and return html + /* private */ function doHeadings( $text ) { + $fname = 'Parser::doHeadings'; + wfProfileIn( $fname ); for ( $i = 6; $i >= 1; --$i ) { - $h = substr( "======", 0, $i ); + $h = substr( '======', 0, $i ); $text = preg_replace( "/^{$h}(.+){$h}(\\s|$)/m", "<h{$i}>\\1</h{$i}>\\2", $text ); } + wfProfileOut( $fname ); return $text; } + /* private */ function doAllQuotes( $text ) { + $fname = 'Parser::doAllQuotes'; + wfProfileIn( $fname ); + $outtext = ''; + $lines = explode( "\n", $text ); + foreach ( $lines as $line ) { + $outtext .= $this->doQuotes ( '', $line, '' ) . "\n"; + } + $outtext = substr($outtext, 0,-1); + wfProfileOut( $fname ); + return $outtext; + } + + /* private */ function doQuotes( $pre, $text, $mode ) { + if ( preg_match( "/^(.*)''(.*)$/sU", $text, $m ) ) { + $m1_strong = ($m[1] == "") ? "" : "<strong>{$m[1]}</strong>"; + $m1_em = ($m[1] == "") ? "" : "<em>{$m[1]}</em>"; + if ( substr ($m[2], 0, 1) == '\'' ) { + $m[2] = substr ($m[2], 1); + if ($mode == 'em') { + return $this->doQuotes ( $m[1], $m[2], ($m[1] == '') ? 'both' : 'emstrong' ); + } else if ($mode == 'strong') { + return $m1_strong . $this->doQuotes ( '', $m[2], '' ); + } else if (($mode == 'emstrong') || ($mode == 'both')) { + return $this->doQuotes ( '', $pre.$m1_strong.$m[2], 'em' ); + } else if ($mode == 'strongem') { + return "<strong>{$pre}{$m1_em}</strong>" . $this->doQuotes ( '', $m[2], 'em' ); + } else { + return $m[1] . $this->doQuotes ( '', $m[2], 'strong' ); + } + } else { + if ($mode == 'strong') { + return $this->doQuotes ( $m[1], $m[2], ($m[1] == '') ? 'both' : 'strongem' ); + } else if ($mode == 'em') { + return $m1_em . $this->doQuotes ( '', $m[2], '' ); + } else if ($mode == 'emstrong') { + return "<em>{$pre}{$m1_strong}</em>" . $this->doQuotes ( '', $m[2], 'strong' ); + } else if (($mode == 'strongem') || ($mode == 'both')) { + return $this->doQuotes ( '', $pre.$m1_em.$m[2], 'strong' ); + } else { + return $m[1] . $this->doQuotes ( '', $m[2], 'em' ); + } + } + } else { + $text_strong = ($text == '') ? '' : "<strong>{$text}</strong>"; + $text_em = ($text == '') ? '' : "<em>{$text}</em>"; + if ($mode == '') { + return $pre . $text; + } else if ($mode == 'em') { + return $pre . $text_em; + } else if ($mode == 'strong') { + return $pre . $text_strong; + } else if ($mode == 'strongem') { + return (($pre == '') && ($text == '')) ? '' : "<strong>{$pre}{$text_em}</strong>"; + } else { + return (($pre == '') && ($text == '')) ? '' : "<em>{$pre}{$text_strong}</em>"; + } + } + } + # Note: we have to do external links before the internal ones, # and otherwise take great care in the order of things here, so # that we don't end up interpreting some URLs twice. - /* private */ function replaceExternalLinks( $text ) - { - $fname = "Parser::replaceExternalLinks"; + /* private */ function replaceExternalLinks( $text ) { + $fname = 'Parser::replaceExternalLinks'; wfProfileIn( $fname ); - $text = $this->subReplaceExternalLinks( $text, "http", true ); - $text = $this->subReplaceExternalLinks( $text, "https", true ); - $text = $this->subReplaceExternalLinks( $text, "ftp", false ); - $text = $this->subReplaceExternalLinks( $text, "irc", false ); - $text = $this->subReplaceExternalLinks( $text, "gopher", false ); - $text = $this->subReplaceExternalLinks( $text, "news", false ); - $text = $this->subReplaceExternalLinks( $text, "mailto", false ); + $text = $this->subReplaceExternalLinks( $text, 'http', true ); + $text = $this->subReplaceExternalLinks( $text, 'https', true ); + $text = $this->subReplaceExternalLinks( $text, 'ftp', false ); + $text = $this->subReplaceExternalLinks( $text, 'irc', false ); + $text = $this->subReplaceExternalLinks( $text, 'gopher', false ); + $text = $this->subReplaceExternalLinks( $text, 'news', false ); + $text = $this->subReplaceExternalLinks( $text, 'mailto', false ); wfProfileOut( $fname ); return $text; } - /* private */ function subReplaceExternalLinks( $s, $protocol, $autonumber ) - { - $unique = "4jzAfzB8hNvf4sqyO9Edd8pSmk9rE2in0Tgw3"; + /* private */ function subReplaceExternalLinks( $s, $protocol, $autonumber ) { + $unique = '4jzAfzB8hNvf4sqyO9Edd8pSmk9rE2in0Tgw3'; $uc = "A-Za-z0-9_\\/~%\\-+&*#?!=()@\\x80-\\xFF"; # this is the list of separators that should be ignored if they @@ -608,8 +918,8 @@ class Parser # in this case, the last comma should not become part of the URL, # but in "www.foo.com/123,2342,32.htm" it should. $sep = ",;\.:"; - $fnc = "A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF"; - $images = "gif|png|jpg|jpeg"; + $fnc = 'A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF'; + $images = 'gif|png|jpg|jpeg'; # PLEASE NOTE: The curly braces { } are not part of the regex, # they are interpreted as part of the string (used to tell PHP @@ -621,13 +931,13 @@ class Parser $sk =& $this->mOptions->getSkin(); if ( $autonumber and $this->mOptions->getAllowExternalImages() ) { # Use img tags only for HTTP urls - $s = preg_replace( $e1, "\\1" . $sk->makeImage( "{$unique}:\\3" . - "/\\4.\\5", "\\4.\\5" ) . "\\6", $s ); + $s = preg_replace( $e1, '\\1' . $sk->makeImage( "{$unique}:\\3" . + '/\\4.\\5', '\\4.\\5' ) . '\\6', $s ); } - $s = preg_replace( $e2, "\\1" . "<a href=\"{$unique}:\\3\"" . + $s = preg_replace( $e2, '\\1' . "<a href=\"{$unique}:\\3\"" . $sk->getExternalLinkAttributes( "{$unique}:\\3", wfEscapeHTML( "{$unique}:\\3" ) ) . ">" . wfEscapeHTML( "{$unique}:\\3" ) . - "</a>\\5", $s ); + '</a>\\5', $s ); $s = str_replace( $unique, $protocol, $s ); $a = explode( "[{$protocol}:", " " . $s ); @@ -652,7 +962,7 @@ class Parser continue; } if( $link == $text || preg_match( "!$protocol://" . preg_quote( $text, "/" ) . "/?$!", $link ) ) { - $paren = ""; + $paren = ''; } else { # Expand the URL for printable version $paren = "<span class='urlexpansion'> (<i>" . htmlspecialchars ( $link ) . "</i>)</span>"; @@ -664,301 +974,31 @@ class Parser return $s; } - /* private */ function handle4Quotes( &$state, $token ) - { - /* This one makes some assumptions. - * '''Caesar''''s army => <strong>Caesar</strong>'s army - * ''''Caesar'''' was a roman emperor => '<strong>Caesar</strong>' was a roman emperor - * These assumptions might be wrong, but any other assumption might be wrong, too. - * So here we go */ - if ( $state["strong"] !== false ) { - return $this->handle3Quotes( $state, $token ) . "'"; - } else { - return "'" . $this->handle3Quotes( $state, $token ); - } - } - - - /* private */ function handle3Quotes( &$state, $token ) - { - if ( $state["strong"] !== false ) { - if ( $state["em"] !== false && $state["em"] > $state["strong"] ) - { - # ''' lala ''lala ''' - $s = "</em></strong><em>"; - } else { - $s = "</strong>"; - } - $state["strong"] = FALSE; - } else { - $s = "<strong>"; - $state["strong"] = $token["pos"]; - } - return $s; - } - - /* private */ function handle2Quotes( &$state, $token ) - { - if ( $state["em"] !== false ) { - if ( $state["strong"] !== false && $state["strong"] > $state["em"] ) - { - # ''lala'''lala'' ....''' - $s = "</strong></em><strong>"; - } else { - $s = "</em>"; - } - $state["em"] = FALSE; - } else { - $s = "<em>"; - $state["em"] = $token["pos"]; - - } - return $s; - } - - /* private */ function handle5Quotes( &$state, $token ) - { - $s = ""; - if ( $state["em"] !== false && $state["strong"] !== false ) { - if ( $state["em"] < $state["strong"] ) { - $s .= "</strong></em>"; - } else { - $s .= "</em></strong>"; - } - $state["strong"] = $state["em"] = FALSE; - } elseif ( $state["em"] !== false ) { - $s .= "</em><strong>"; - $state["em"] = FALSE; - $state["strong"] = $token["pos"]; - } elseif ( $state["strong"] !== false ) { - $s .= "</strong><em>"; - $state["strong"] = FALSE; - $state["em"] = $token["pos"]; - } else { # not $em and not $strong - $s .= "<strong><em>"; - $state["strong"] = $state["em"] = $token["pos"]; - } - return $s; - } - - /* private */ function doTokenizedParser( $str ) - { - global $wgLang; # for language specific parser hook - global $wgUploadDirectory, $wgUseTimeline; - - $tokenizer=Tokenizer::newFromString( $str ); - $tokenStack = array(); - - $s=""; - $state["em"] = FALSE; - $state["strong"] = FALSE; - $tagIsOpen = FALSE; - $threeopen = false; - - # The tokenizer splits the text into tokens and returns them one by one. - # Every call to the tokenizer returns a new token. - while ( $token = $tokenizer->nextToken() ) - { - switch ( $token["type"] ) - { - case "text": - # simple text with no further markup - $txt = $token["text"]; - break; - case "blank": - # Text that contains blanks that have to be converted to - # non-breakable spaces for French. - # U+202F NARROW NO-BREAK SPACE might be a better choice, but - # browser support for Unicode spacing is poor. - $txt = str_replace( " ", " ", $token["text"] ); - break; - case "[[[": - # remember the tag opened with 3 [ - $threeopen = true; - case "[[": - # link opening tag. - # FIXME : Treat orphaned open tags (stack not empty when text is over) - $tagIsOpen = TRUE; - array_push( $tokenStack, $token ); - $txt=""; - break; - - case "]]]": - case "]]": - # link close tag. - # get text from stack, glue it together, and call the code to handle a - # link - - if ( count( $tokenStack ) == 0 ) - { - # stack empty. Found a ]] without an opening [[ - $txt = "]]"; - } else { - $linkText = ""; - $lastToken = array_pop( $tokenStack ); - while ( !(($lastToken["type"] == "[[[") or ($lastToken["type"] == "[[")) ) - { - if( !empty( $lastToken["text"] ) ) { - $linkText = $lastToken["text"] . $linkText; - } - $lastToken = array_pop( $tokenStack ); - } - - $txt = $linkText ."]]"; - if( isset( $lastToken["text"] ) ) { - $prefix = $lastToken["text"]; - } else { - $prefix = ""; - } - $nextToken = $tokenizer->previewToken(); - if ( $nextToken["type"] == "text" ) - { - # Preview just looks at it. Now we have to fetch it. - $nextToken = $tokenizer->nextToken(); - $txt .= $nextToken["text"]; - } - $txt = $this->handleInternalLink( $this->unstrip($txt,$this->mStripState), $prefix ); - - # did the tag start with 3 [ ? - if($threeopen) { - # show the first as text - $txt = "[".$txt; - $threeopen=false; - } - - } - $tagIsOpen = (count( $tokenStack ) != 0); - break; - case "----": - $txt = "\n<hr />\n"; - break; - case "'''": - # This and the four next ones handle quotes - $txt = $this->handle3Quotes( $state, $token ); - break; - case "''": - $txt = $this->handle2Quotes( $state, $token ); - break; - case "'''''": - $txt = $this->handle5Quotes( $state, $token ); - break; - case "''''": - $txt = $this->handle4Quotes( $state, $token ); - break; - case "": - # empty token - $txt=""; - break; - case "h": - #heading- used to close all unbalanced bold or em tags in this section - $txt = ''; - if( $state['em'] !== false and - ( $state['strong'] === false or $state['em'] > $state['strong'] ) ) - { - $s .= '</em>'; - $state['em'] = false; - } - if ( $state['strong'] !== false ) $txt .= '</strong>'; - if ( $state['em'] !== false ) $txt .= '</em>'; - $state['strong'] = $state['em'] = false; - break; - case "RFC ": - if ( $tagIsOpen ) { - $txt = "RFC "; - } else { - $txt = $this->doMagicRFC( $tokenizer ); - } - break; - case "ISBN ": - if ( $tagIsOpen ) { - $txt = "ISBN "; - } else { - $txt = $this->doMagicISBN( $tokenizer ); - } - break; - case "<timeline>": - if ( $wgUseTimeline && - "" != ( $timelinesrc = $tokenizer->readAllUntil("</timeline>") ) ) - { - $txt = renderTimeline( $timelinesrc ); - } else { - $txt=$token["text"]; - } - break; - default: - # Call language specific Hook. - $txt = $wgLang->processToken( $token, $tokenStack ); - if ( NULL == $txt ) { - # An unkown token. Highlight. - $txt = "<font color=\"#FF0000\"><b>".$token["type"]."</b></font>"; - $txt .= "<font color=\"#FFFF00\"><b>".$token["text"]."</b></font>"; - } - break; - } - # If we're parsing the interior of a link, don't append the interior to $s, - # but push it to the stack so it can be processed when a ]] token is found. - if ( $tagIsOpen && $txt != "" ) { - $token["type"] = "text"; - $token["text"] = $txt; - array_push( $tokenStack, $token ); - } else { - $s .= $txt; - } - } #end while - - # make 100% sure all strong and em tags are closed - # doBlockLevels often messes the last bit up though, but invalid nesting is better than unclosed tags - # tidy solves this though - if( $state['em'] !== false and - ( $state['strong'] === false or $state['em'] > $state['strong'] ) ) - { - $s .= '</em>'; - $state['em'] = false; - } - if ( $state['strong'] !== false ) $s .= '</strong>'; - if ( $state['em'] !== false ) $s .= '</em>'; - - if ( count( $tokenStack ) != 0 ) - { - # still objects on stack. opened [[ tag without closing ]] tag. - $txt = ""; - while ( $lastToken = array_pop( $tokenStack ) ) - { - if ( $lastToken["type"] == "text" ) - { - $txt = $lastToken["text"] . $txt; - } else { - $txt = $lastToken["type"] . $txt; - } - } - $s .= $txt; - } - return $s; - } - - /* private */ function handleInternalLink( $line, $prefix ) - { + /* private */ function replaceInternalLinks( $s ) { global $wgLang, $wgLinkCache; global $wgNamespacesWithSubpages, $wgLanguageCode; - static $fname = "Parser::handleInternalLink" ; + static $fname = 'Parser::replaceInternalLinks' ; wfProfileIn( $fname ); - wfProfileIn( "$fname-setup" ); + wfProfileIn( $fname.'-setup' ); static $tc = FALSE; - if ( !$tc ) { $tc = Title::legalChars() . "#"; } + # the % is needed to support urlencoded titles as well + if ( !$tc ) { $tc = Title::legalChars() . '#%'; } $sk =& $this->mOptions->getSkin(); + $a = explode( '[[', ' ' . $s ); + $s = array_shift( $a ); + $s = substr( $s, 1 ); + # Match a link having the form [[namespace:link|alternate]]trail static $e1 = FALSE; if ( !$e1 ) { $e1 = "/^([{$tc}]+)(?:\\|([^]]+))?]](.*)\$/sD"; } # Match the end of a line for a word that's not followed by whitespace, # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched - #$e2 = "/^(.*)\\b(\\w+)\$/suD"; - #$e2 = "/^(.*\\s)(\\S+)\$/suD"; - static $e2 = '/^(.*\s)([a-zA-Z\x80-\xff]+)$/sD'; - + static $e2 = '/^(.*?)([a-zA-Z\x80-\xff]+)$/sD'; + $useLinkPrefixExtension = $wgLang->linkPrefixExtension(); # Special and Media are pseudo-namespaces; no pages actually exist in them static $image = FALSE; static $special = FALSE; @@ -971,120 +1011,148 @@ class Parser $nottalk = !Namespace::isTalk( $this->mTitle->getNamespace() ); - wfProfileOut( "$fname-setup" ); - $s = ""; - - if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt - $text = $m[2]; - $trail = $m[3]; - } else { # Invalid form; output directly - $s .= $prefix . "[[" . $line ; - return $s; + if ( $useLinkPrefixExtension ) { + if ( preg_match( $e2, $s, $m ) ) { + $first_prefix = $m[2]; + $s = $m[1]; + } else { + $first_prefix = false; + } + } else { + $prefix = ''; } - /* Valid link forms: - Foobar -- normal - :Foobar -- override special treatment of prefix (images, language links) - /Foobar -- convert to CurrentPage/Foobar - /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text - */ - $c = substr($m[1],0,1); - $noforce = ($c != ":"); - if( $c == "/" ) { # subpage - if(substr($m[1],-1,1)=="/") { # / at end means we don't want the slash to be shown - $m[1]=substr($m[1],1,strlen($m[1])-2); - $noslash=$m[1]; - } else { - $noslash=substr($m[1],1); + wfProfileOut( $fname.'-setup' ); + + foreach ( $a as $line ) { + wfProfileIn( $fname.'-prefixhandling' ); + if ( $useLinkPrefixExtension ) { + if ( preg_match( $e2, $s, $m ) ) { + $prefix = $m[2]; + $s = $m[1]; + } else { + $prefix=''; + } + # first link + if($first_prefix) { + $prefix = $first_prefix; + $first_prefix = false; + } } - if($wgNamespacesWithSubpages[$this->mTitle->getNamespace()]) { # subpages allowed here - $link = $this->mTitle->getPrefixedText(). "/" . trim($noslash); - if( "" == $text ) { - $text= $m[1]; - } # this might be changed for ugliness reasons + wfProfileOut( $fname.'-prefixhandling' ); + + if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt + $text = $m[2]; + # fix up urlencoded title texts + if(preg_match('/%/', $m[1] )) $m[1] = urldecode($m[1]); + $trail = $m[3]; + } else { # Invalid form; output directly + $s .= $prefix . '[[' . $line ; + continue; + } + + /* Valid link forms: + Foobar -- normal + :Foobar -- override special treatment of prefix (images, language links) + /Foobar -- convert to CurrentPage/Foobar + /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text + */ + $c = substr($m[1],0,1); + $noforce = ($c != ':'); + if( $c == '/' ) { # subpage + if(substr($m[1],-1,1)=='/') { # / at end means we don't want the slash to be shown + $m[1]=substr($m[1],1,strlen($m[1])-2); + $noslash=$m[1]; + } else { + $noslash=substr($m[1],1); + } + if(!empty($wgNamespacesWithSubpages[$this->mTitle->getNamespace()])) { # subpages allowed here + $link = $this->mTitle->getPrefixedText(). '/' . trim($noslash); + if( '' == $text ) { + $text= $m[1]; + } # this might be changed for ugliness reasons + } else { + $link = $noslash; # no subpage allowed, use standard link + } + } elseif( $noforce ) { # no subpage + $link = $m[1]; } else { - $link = $noslash; # no subpage allowed, use standard link + $link = substr( $m[1], 1 ); } - } elseif( $noforce ) { # no subpage - $link = $m[1]; - } else { - $link = substr( $m[1], 1 ); - } - $wasblank = ( "" == $text ); - if( $wasblank ) + $wasblank = ( '' == $text ); + if( $wasblank ) $text = $link; - $nt = Title::newFromText( $link ); - if( !$nt ) { - $s .= $prefix . "[[" . $line; - return $s; - } - $ns = $nt->getNamespace(); - $iw = $nt->getInterWiki(); - if( $noforce ) { - if( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgLang->getLanguageName( $iw ) ) { - array_push( $this->mOutput->mLanguageLinks, $nt->getPrefixedText() ); - $s .= $prefix . $trail ; - return (trim($s) == '')? '': $s; - } - if( $ns == $image ) { - $s .= $prefix . $sk->makeImageLinkObj( $nt, $text ) . $trail; - $wgLinkCache->addImageLinkObj( $nt ); - return $s; + $nt = Title::newFromText( $link ); + if( !$nt ) { + $s .= $prefix . '[[' . $line; + continue; } - if ( $ns == $category ) { - $t = $nt->getText() ; - $nnt = Title::newFromText ( Namespace::getCanonicalName($category).":".$t ) ; - - $wgLinkCache->suspend(); # Don't save in links/brokenlinks - $t = $sk->makeLinkObj( $nnt, $t, "", "" , $prefix ); - $wgLinkCache->resume(); - - $sortkey = $wasblank ? $this->mTitle->getPrefixedText() : $text; - $wgLinkCache->addCategoryLinkObj( $nt, $sortkey ); - $this->mOutput->mCategoryLinks[] = $t ; - $s .= $prefix . $trail ; - return $s ; + $ns = $nt->getNamespace(); + $iw = $nt->getInterWiki(); + if( $noforce ) { + if( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgLang->getLanguageName( $iw ) ) { + array_push( $this->mOutput->mLanguageLinks, $nt->getPrefixedText() ); + $tmp = $prefix . $trail ; + $s .= (trim($tmp) == '')? '': $tmp; + continue; + } + if ( $ns == $image ) { + $s .= $prefix . $sk->makeImageLinkObj( $nt, $text ) . $trail; + $wgLinkCache->addImageLinkObj( $nt ); + continue; + } + if ( $ns == $category ) { + $t = $nt->getText() ; + $nnt = Title::newFromText ( Namespace::getCanonicalName($category).":".$t ) ; + + $wgLinkCache->suspend(); # Don't save in links/brokenlinks + $t = $sk->makeLinkObj( $nnt, $t, '', '' , $prefix ); + $wgLinkCache->resume(); + + $sortkey = $wasblank ? $this->mTitle->getPrefixedText() : $text; + $wgLinkCache->addCategoryLinkObj( $nt, $sortkey ); + $this->mOutput->mCategoryLinks[] = $t ; + $s .= $prefix . $trail ; + continue; + } + } + if( ( $nt->getPrefixedText() == $this->mTitle->getPrefixedText() ) && + ( strpos( $link, '#' ) == FALSE ) ) { + # Self-links are handled specially; generally de-link and change to bold. + $s .= $prefix . $sk->makeSelfLinkObj( $nt, $text, '', $trail ); + continue; } - } - if( ( $nt->getPrefixedText() == $this->mTitle->getPrefixedText() ) && - ( strpos( $link, "#" ) == FALSE ) ) { - # Self-links are handled specially; generally de-link and change to bold. - $s .= $prefix . $sk->makeSelfLinkObj( $nt, $text, "", $trail ); - return $s; - } - if( $ns == $media ) { - $s .= $prefix . $sk->makeMediaLinkObj( $nt, $text ) . $trail; - $wgLinkCache->addImageLinkObj( $nt ); - return $s; - } elseif( $ns == $special ) { - $s .= $prefix . $sk->makeKnownLinkObj( $nt, $text, "", $trail ); - return $s; + if( $ns == $media ) { + $s .= $prefix . $sk->makeMediaLinkObj( $nt, $text ) . $trail; + $wgLinkCache->addImageLinkObj( $nt ); + continue; + } elseif( $ns == $special ) { + $s .= $prefix . $sk->makeKnownLinkObj( $nt, $text, '', $trail ); + continue; + } + $s .= $sk->makeLinkObj( $nt, $text, '', $trail, $prefix ); } - $s .= $sk->makeLinkObj( $nt, $text, "", $trail , $prefix ); - wfProfileOut( $fname ); return $s; } # Some functions here used by doBlockLevels() # - /* private */ function closeParagraph() - { - $result = ""; + /* private */ function closeParagraph() { + $result = ''; if ( '' != $this->mLastSection ) { - $result = "</" . $this->mLastSection . ">\n"; + $result = '</' . $this->mLastSection . ">\n"; } $this->mInPre = false; - $this->mLastSection = ""; + $this->mLastSection = ''; return $result; } # getCommon() returns the length of the longest common substring # of both arguments, starting at the beginning of both. # - /* private */ function getCommon( $st1, $st2 ) - { + /* private */ function getCommon( $st1, $st2 ) { $fl = strlen( $st1 ); $shorter = strlen( $st2 ); if ( $fl < $shorter ) { $shorter = $fl; } @@ -1101,53 +1169,51 @@ class Parser { $result = $this->closeParagraph(); - if ( "*" == $char ) { $result .= "<ul><li>"; } - else if ( "#" == $char ) { $result .= "<ol><li>"; } - else if ( ":" == $char ) { $result .= "<dl><dd>"; } - else if ( ";" == $char ) { - $result .= "<dl><dt>"; + if ( '*' == $char ) { $result .= '<ul><li>'; } + else if ( '#' == $char ) { $result .= '<ol><li>'; } + else if ( ':' == $char ) { $result .= '<dl><dd>'; } + else if ( ';' == $char ) { + $result .= '<dl><dt>'; $this->mDTopen = true; } - else { $result = "<!-- ERR 1 -->"; } + else { $result = '<!-- ERR 1 -->'; } return $result; } - /* private */ function nextItem( $char ) - { - if ( "*" == $char || "#" == $char ) { return "</li><li>"; } - else if ( ":" == $char || ";" == $char ) { + /* private */ function nextItem( $char ) { + if ( '*' == $char || '#' == $char ) { return '</li><li>'; } + else if ( ':' == $char || ';' == $char ) { $close = "</dd>"; - if ( $this->mDTopen ) { $close = "</dt>"; } - if ( ";" == $char ) { + if ( $this->mDTopen ) { $close = '</dt>'; } + if ( ';' == $char ) { $this->mDTopen = true; - return $close . "<dt>"; + return $close . '<dt>'; } else { $this->mDTopen = false; - return $close . "<dd>"; + return $close . '<dd>'; } } - return "<!-- ERR 2 -->"; + return '<!-- ERR 2 -->'; } - /* private */function closeList( $char ) - { - if ( "*" == $char ) { $text = "</li></ul>"; } - else if ( "#" == $char ) { $text = "</li></ol>"; } - else if ( ":" == $char ) { + /* private */function closeList( $char ) { + if ( '*' == $char ) { $text = '</li></ul>'; } + else if ( '#' == $char ) { $text = '</li></ol>'; } + else if ( ':' == $char ) { if ( $this->mDTopen ) { $this->mDTopen = false; - $text = "</dt></dl>"; + $text = '</dt></dl>'; } else { - $text = "</dd></dl>"; + $text = '</dd></dl>'; } } - else { return "<!-- ERR 3 -->"; } + else { return '<!-- ERR 3 -->'; } return $text."\n"; } /* private */ function doBlockLevels( $text, $linestart ) { - $fname = "Parser::doBlockLevels"; + $fname = 'Parser::doBlockLevels'; wfProfileIn( $fname ); # Parsing through the text line by line. The main thing @@ -1173,11 +1239,11 @@ class Parser } if ( !$this->mInPre ) { # Multiple prefixes may abut each other for nested lists. - $prefixLength = strspn( $oLine, "*#:;" ); + $prefixLength = strspn( $oLine, '*#:;' ); $pref = substr( $oLine, 0, $prefixLength ); # eh? - $pref2 = str_replace( ";", ":", $pref ); + $pref2 = str_replace( ';', ':', $pref ); $t = substr( $oLine, $prefixLength ); } else { # Don't interpret any other prefixes in preformatted text @@ -1200,7 +1266,7 @@ class Parser # FIXME: This is not foolproof. Something better in Tokenizer might help. if( preg_match( '/^(.*?(?:\s| )):(.*)$/', $t, $match ) ) { $term = $match[1]; - $output .= $term . $this->nextItem( ":" ); + $output .= $term . $this->nextItem( ':' ); $t = $match[2]; } } @@ -1220,7 +1286,7 @@ class Parser $char = substr( $pref, $commonPrefixLength, 1 ); $output .= $this->openList( $char ); - if ( ";" == $char ) { + if ( ';' == $char ) { # FIXME: This is dupe of code above if( preg_match( '/^(.*?(?:\s| )):(.*)$/', $t, $match ) ) { $term = $match[1]; @@ -1236,10 +1302,10 @@ class Parser # No prefix (not in list)--go to paragraph mode $uniq_prefix = UNIQ_PREFIX; // XXX: use a stack for nestable elements like span, table and div - $openmatch = preg_match("/(<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<div|<pre|<tr|<td|<p|<ul|<li)/i", $t ); + $openmatch = preg_match('/(<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<li|<\\/tr|<\\/td|<\\/th)/i', $t ); $closematch = preg_match( - "/(<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|". - "<\\/div|<hr|<\\/td|<\\/pre|<\\/p|".$uniq_prefix."-pre|<\\/li|<\\/ul)/i", $t ); + '/(<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'. + '<td|<th|<div|<\\/div|<hr|<\\/pre|<\\/p|'.$uniq_prefix.'-pre|<\\/li|<\\/ul)/i', $t ); if ( $openmatch or $closematch ) { $paragraphStack = false; $output .= $this->closeParagraph(); @@ -1251,7 +1317,7 @@ class Parser } else { $inBlockElem = true; } - } else if ( !$inBlockElem ) { + } else if ( !$inBlockElem && !$this->mInPre ) { if ( " " == $t{0} and trim($t) != '' ) { // pre if ($this->mLastSection != 'pre') { @@ -1263,14 +1329,14 @@ class Parser // paragraph if ( '' == trim($t) ) { if ( $paragraphStack ) { - $output .= $paragraphStack.'<br/>'; + $output .= $paragraphStack.'<br />'; $paragraphStack = false; $this->mLastSection = 'p'; } else { if ($this->mLastSection != 'p' ) { $output .= $this->closeParagraph(); $this->mLastSection = ''; - $paragraphStack = "<p>"; + $paragraphStack = '<p>'; } else { $paragraphStack = '</p><p>'; } @@ -1296,36 +1362,37 @@ class Parser $output .= $this->closeList( $pref2{$prefixLength-1} ); --$prefixLength; } - if ( "" != $this->mLastSection ) { - $output .= "</" . $this->mLastSection . ">"; - $this->mLastSection = ""; + if ( '' != $this->mLastSection ) { + $output .= '</' . $this->mLastSection . '>'; + $this->mLastSection = ''; } wfProfileOut( $fname ); return $output; } + # Return value of a magic variable (like PAGENAME) function getVariableValue( $index ) { global $wgLang, $wgSitename, $wgServer; switch ( $index ) { case MAG_CURRENTMONTH: - return date( "m" ); + return date( 'm' ); case MAG_CURRENTMONTHNAME: - return $wgLang->getMonthName( date("n") ); + return $wgLang->getMonthName( date('n') ); case MAG_CURRENTMONTHNAMEGEN: - return $wgLang->getMonthNameGen( date("n") ); + return $wgLang->getMonthNameGen( date('n') ); case MAG_CURRENTDAY: - return date("j"); + return date('j'); case MAG_PAGENAME: return $this->mTitle->getText(); case MAG_NAMESPACE: # return Namespace::getCanonicalName($this->mTitle->getNamespace()); return $wgLang->getNsText($this->mTitle->getNamespace()); // Patch by Dori case MAG_CURRENTDAYNAME: - return $wgLang->getWeekdayName( date("w")+1 ); + return $wgLang->getWeekdayName( date('w')+1 ); case MAG_CURRENTYEAR: - return date( "Y" ); + return date( 'Y' ); case MAG_CURRENTTIME: return $wgLang->time( wfTimestampNow(), false ); case MAG_NUMBEROFARTICLES: @@ -1339,8 +1406,8 @@ class Parser } } - function initialiseVariables() - { + # initialise the magic variables (like CURRENTMONTHNAME) + function initialiseVariables() { global $wgVariableIDs; $this->mVariables = array(); foreach ( $wgVariableIDs as $id ) { @@ -1349,11 +1416,10 @@ class Parser } } - /* private */ function replaceVariables( $text, $args = array() ) - { + /* private */ function replaceVariables( $text, $args = array() ) { global $wgLang, $wgScript, $wgArticlePath; - $fname = "Parser::replaceVariables"; + $fname = 'Parser::replaceVariables'; wfProfileIn( $fname ); $bail = false; @@ -1361,26 +1427,49 @@ class Parser $this->initialiseVariables(); } $titleChars = Title::legalChars(); - $regex = "/(\\n?){{([$titleChars]*?)(\\|.*?|)}}/s"; + $nonBraceChars = str_replace( array( '{', '}' ), array( '', '' ), $titleChars ); # This function is called recursively. To keep track of arguments we need a stack: array_push( $this->mArgStack, $args ); # PHP global rebinding syntax is a bit weird, need to use the GLOBALS array $GLOBALS['wgCurParser'] =& $this; - $text = preg_replace_callback( $regex, "wfBraceSubstitution", $text ); + + + if ( $this->mOutputType == OT_HTML ) { + # Variable substitution + $text = preg_replace_callback( "/{{([$nonBraceChars]*?)}}/", 'wfVariableSubstitution', $text ); + + # Argument substitution + $text = preg_replace_callback( "/(\\n?){{{([$titleChars]*?)}}}/", 'wfArgSubstitution', $text ); + } + # Template substitution + $regex = '/(\\n?){{(['.$nonBraceChars.']*)(\\|.*?|)}}/s'; + $text = preg_replace_callback( $regex, 'wfBraceSubstitution', $text ); array_pop( $this->mArgStack ); + wfProfileOut( $fname ); return $text; } - function braceSubstitution( $matches ) - { + function variableSubstitution( $matches ) { + if ( array_key_exists( $matches[1], $this->mVariables ) ) { + $text = $this->mVariables[$matches[1]]; + $this->mOutput->mContainsOldMagic = true; + } else { + $text = $matches[0]; + } + return $text; + } + + function braceSubstitution( $matches ) { global $wgLinkCache, $wgLang; - $fname = "Parser::braceSubstitution"; + $fname = 'Parser::braceSubstitution'; $found = false; $nowiki = false; + $noparse = false; + $title = NULL; # $newline is an optional newline character before the braces @@ -1390,26 +1479,36 @@ class Parser $newline = $matches[1]; $part1 = $matches[2]; # If the third subpattern matched anything, it will start with | - if ( $matches[3] !== "" ) { - $args = explode( "|", substr( $matches[3], 1 ) ); + if ( $matches[3] !== '' ) { + $args = explode( '|', substr( $matches[3], 1 ) ); } else { $args = array(); } $argc = count( $args ); + + # {{{}}} + if ( strpos( $matches[0], '{{{' ) !== false ) { + $text = $matches[0]; + $found = true; + $noparse = true; + } # SUBST - $mwSubst =& MagicWord::get( MAG_SUBST ); - if ( $mwSubst->matchStartAndRemove( $part1 ) ) { - if ( $this->mOutputType != OT_WIKI ) { - # Invalid SUBST not replaced at PST time - # Return without further processing + if ( !$found ) { + $mwSubst =& MagicWord::get( MAG_SUBST ); + if ( $mwSubst->matchStartAndRemove( $part1 ) ) { + if ( $this->mOutputType != OT_WIKI ) { + # Invalid SUBST not replaced at PST time + # Return without further processing + $text = $matches[0]; + $found = true; + $noparse= true; + } + } elseif ( $this->mOutputType == OT_WIKI ) { + # SUBST not found in PST pass, do nothing $text = $matches[0]; $found = true; } - } elseif ( $this->mOutputType == OT_WIKI ) { - # SUBST not found in PST pass, do nothing - $text = $matches[0]; - $found = true; } # MSG, MSGNW and INT @@ -1427,7 +1526,7 @@ class Parser # Check if it is an internal message $mwInt =& MagicWord::get( MAG_INT ); if ( $mwInt->matchStartAndRemove( $part1 ) ) { - if ( $this->incrementIncludeCount( "int:$part1" ) ) { + if ( $this->incrementIncludeCount( 'int:'.$part1 ) ) { $text = wfMsgReal( $part1, $args, true ); $found = true; } @@ -1484,14 +1583,14 @@ class Parser $found = true; $this->mOutput->mContainsOldMagic = true; } - +/* # Arguments input from the caller $inputArgs = end( $this->mArgStack ); if ( !$found && array_key_exists( $part1, $inputArgs ) ) { $text = $inputArgs[$part1]; $found = true; } - +*/ # Load from database if ( !$found ) { $title = Title::newFromText( $part1, NS_TEMPLATE ); @@ -1510,7 +1609,7 @@ class Parser # If the title is valid but undisplayable, make a link to it if ( $this->mOutputType == OT_HTML && !$found ) { - $text = "[[" . $title->getPrefixedText() . "]]"; + $text = '[[' . $title->getPrefixedText() . ']]'; $found = true; } } @@ -1520,19 +1619,19 @@ class Parser # Only for HTML output if ( $nowiki && $found && $this->mOutputType == OT_HTML ) { $text = wfEscapeWikiText( $text ); - } elseif ( $this->mOutputType == OT_HTML && $found ) { + } elseif ( $this->mOutputType == OT_HTML && $found && !$noparse) { # Clean up argument array $assocArgs = array(); $index = 1; foreach( $args as $arg ) { - $eqpos = strpos( $arg, "=" ); + $eqpos = strpos( $arg, '=' ); if ( $eqpos === false ) { $assocArgs[$index++] = $arg; } else { $name = trim( substr( $arg, 0, $eqpos ) ); $value = trim( substr( $arg, $eqpos+1 ) ); if ( $value === false ) { - $value = ""; + $value = ''; } if ( $name !== false ) { $assocArgs[$name] = $value; @@ -1546,13 +1645,7 @@ class Parser } # Run full parser on the included text - $text = $this->strip( $text, $this->mStripState ); - $text = $this->internalParse( $text, (bool)$newline, $assocArgs, false ); - if(!empty($newline)) $text = "\n".$text; - - # Add the result to the strip state for re-inclusion after - # the rest of the processing - $text = $this->insertStripItem( $text, $this->mStripState ); + $text = $this->stripParse( $text, $newline, $assocArgs ); # Resume the link cache and register the inclusion as a link if ( !is_null( $title ) ) { @@ -1568,9 +1661,22 @@ class Parser } } + # Triple brace replacement -- used for template arguments + function argSubstitution( $matches ) { + $newline = $matches[1]; + $arg = trim( $matches[2] ); + $text = $matches[0]; + $inputArgs = end( $this->mArgStack ); + + if ( array_key_exists( $arg, $inputArgs ) ) { + $text = $this->stripParse( $inputArgs[$arg], $newline, array() ); + } + + return $text; + } + # Returns true if the function is allowed to include this entity - function incrementIncludeCount( $dbk ) - { + function incrementIncludeCount( $dbk ) { if ( !array_key_exists( $dbk, $this->mIncludeCount ) ) { $this->mIncludeCount[$dbk] = 0; } @@ -1583,29 +1689,28 @@ class Parser # Cleans up HTML, removes dangerous tags and attributes - /* private */ function removeHTMLtags( $text ) - { + /* private */ function removeHTMLtags( $text ) { global $wgUseTidy, $wgUserHtml; - $fname = "Parser::removeHTMLtags"; + $fname = 'Parser::removeHTMLtags'; wfProfileIn( $fname ); if( $wgUserHtml ) { $htmlpairs = array( # Tags that must be closed - "b", "del", "i", "ins", "u", "font", "big", "small", "sub", "sup", "h1", - "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s", - "strike", "strong", "tt", "var", "div", "center", - "blockquote", "ol", "ul", "dl", "table", "caption", "pre", - "ruby", "rt" , "rb" , "rp", "p" + 'b', 'del', 'i', 'ins', 'u', 'font', 'big', 'small', 'sub', 'sup', 'h1', + 'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's', + 'strike', 'strong', 'tt', 'var', 'div', 'center', + 'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre', + 'ruby', 'rt' , 'rb' , 'rp', 'p' ); $htmlsingle = array( - "br", "hr", "li", "dt", "dd" + 'br', 'hr', 'li', 'dt', 'dd' ); $htmlnest = array( # Tags that can be nested--?? - "table", "tr", "td", "th", "div", "blockquote", "ol", "ul", - "dl", "font", "big", "small", "sub", "sup" + 'table', 'tr', 'td', 'th', 'div', 'blockquote', 'ol', 'ul', + 'dl', 'font', 'big', 'small', 'sub', 'sup' ); $tabletags = array( # Can only appear inside table - "td", "th", "tr" + 'td', 'th', 'tr' ); } else { $htmlpairs = array(); @@ -1620,15 +1725,15 @@ class Parser $htmlattrs = $this->getHTMLattrs () ; # Remove HTML comments - $text = preg_replace( "/(\\n *<!--.*--> *(?=\\n)|<!--.*-->)/sU", "$2", $text ); + $text = preg_replace( '/(\\n *<!--.*--> *(?=\\n)|<!--.*-->)/sU', '$2', $text ); - $bits = explode( "<", $text ); + $bits = explode( '<', $text ); $text = array_shift( $bits ); if(!$wgUseTidy) { $tagstack = array(); $tablestack = array(); foreach ( $bits as $x ) { $prev = error_reporting( E_ALL & ~( E_NOTICE | E_WARNING ) ); - preg_match( "/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/", + preg_match( '/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/', $x, $regs ); list( $qbar, $slash, $t, $params, $brace, $rest ) = $regs; error_reporting( $prev ); @@ -1639,25 +1744,25 @@ class Parser if ( $slash ) { # Closing a tag... if ( ! in_array( $t, $htmlsingle ) && - ( count($tagstack) && $ot = array_pop( $tagstack ) ) != $t ) { - if(!empty($ot)) array_push( $tagstack, $ot ); + ( $ot = @array_pop( $tagstack ) ) != $t ) { + @array_push( $tagstack, $ot ); $badtag = 1; } else { - if ( $t == "table" ) { + if ( $t == 'table' ) { $tagstack = array_pop( $tablestack ); } - $newparams = ""; + $newparams = ''; } } else { # Keep track for later if ( in_array( $t, $tabletags ) && - ! in_array( "table", $tagstack ) ) { + ! in_array( 'table', $tagstack ) ) { $badtag = 1; } else if ( in_array( $t, $tagstack ) && ! in_array ( $t , $htmlnest ) ) { $badtag = 1 ; } else if ( ! in_array( $t, $htmlsingle ) ) { - if ( $t == "table" ) { + if ( $t == 'table' ) { array_push( $tablestack, $tagstack ); $tagstack = array(); } @@ -1668,30 +1773,30 @@ class Parser } if ( ! $badtag ) { - $rest = str_replace( ">", ">", $rest ); + $rest = str_replace( '>', '>', $rest ); $text .= "<$slash$t $newparams$brace$rest"; continue; } } - $text .= "<" . str_replace( ">", ">", $x); + $text .= '<' . str_replace( '>', '>', $x); } # Close off any remaining tags - while ( $t = array_pop( $tagstack ) ) { + while ( is_array( $tagstack ) && ($t = array_pop( $tagstack )) ) { $text .= "</$t>\n"; - if ( $t == "table" ) { $tagstack = array_pop( $tablestack ); } + if ( $t == 'table' ) { $tagstack = array_pop( $tablestack ); } } } else { # this might be possible using tidy itself foreach ( $bits as $x ) { - preg_match( "/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/", + preg_match( '/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/', $x, $regs ); @list( $qbar, $slash, $t, $params, $brace, $rest ) = $regs; if ( in_array( $t = strtolower( $t ), $htmlelements ) ) { $newparams = $this->fixTagAttributes($params); - $rest = str_replace( ">", ">", $rest ); + $rest = str_replace( '>', '>', $rest ); $text .= "<$slash$t $newparams$brace$rest"; } else { - $text .= "<" . str_replace( ">", ">", $x); + $text .= '<' . str_replace( '>', '>', $x); } } } @@ -1713,8 +1818,7 @@ class Parser * */ - /* private */ function formatHeadings( $text, $isMain=true ) - { + /* private */ function formatHeadings( $text, $isMain=true ) { global $wgInputEncoding; $doNumberHeadings = $this->mOptions->getNumberHeadings(); @@ -1741,13 +1845,13 @@ class Parser # never add the TOC to the Main Page. This is an entry page that should not # be more than 1-2 screens large anyway - if( $this->mTitle->getPrefixedText() == wfMsg("mainpage") ) { + if( $this->mTitle->getPrefixedText() == wfMsg('mainpage') ) { $doShowToc = 0; } # Get all headlines for numbering them and adding funky stuff like [edit] # links - this is for later, but we need the number of headlines right now - $numMatches = preg_match_all( "/<H([1-6])(.*?" . ">)(.*?)<\/H[1-6]>/i", $text, $matches ); + $numMatches = preg_match_all( '/<H([1-6])(.*?' . '>)(.*?)<\/H[1-6]>/i', $text, $matches ); # if there are fewer than 4 headlines in the article, do not show TOC if( $numMatches < 4 ) { @@ -1771,14 +1875,14 @@ class Parser # Ugh .. the TOC should have neat indentation levels which can be # passed to the skin functions. These are determined here $toclevel = 0; - $toc = ""; - $full = ""; + $toc = ''; + $full = ''; $head = array(); $sublevelCount = array(); $level = 0; $prevlevel = 0; foreach( $matches[3] as $headline ) { - $numbering = ""; + $numbering = ''; if( $level ) { $prevlevel = $level; } @@ -1802,7 +1906,7 @@ class Parser for( $i = 1; $i <= $level; $i++ ) { if( !empty( $sublevelCount[$i] ) ) { if( $dot ) { - $numbering .= "."; + $numbering .= '.'; } $numbering .= $sublevelCount[$i]; $dot = 1; @@ -1813,13 +1917,17 @@ class Parser # The canonized header is a version of the header text safe to use for links # Avoid insertion of weird stuff like <math> by expanding the relevant sections $canonized_headline = $this->unstrip( $headline, $this->mStripState ); + $canonized_headline = $this->unstripNoWiki( $headline, $this->mStripState ); # strip out HTML - $canonized_headline = preg_replace( "/<.*?" . ">/","",$canonized_headline ); + $canonized_headline = preg_replace( '/<.*?' . '>/','',$canonized_headline ); $tocline = trim( $canonized_headline ); - $canonized_headline = preg_replace("/[ \\?&\\/<>\\(\\)\\[\\]=,+']+/", '_', urlencode( do_html_entity_decode( $tocline, ENT_COMPAT, $wgInputEncoding ) ) ); - # strip out urlencoded (inserted for french spaces, e.g. first space in 'something : something') - $canonized_headline = str_replace('%C2%A0','_', $canonized_headline); + $canonized_headline = urlencode( do_html_entity_decode( str_replace(' ', '_', $tocline), ENT_COMPAT, $wgInputEncoding ) ); + $replacearray = array( + '%3A' => ':', + '%' => '.' + ); + $canonized_headline = str_replace(array_keys($replacearray),array_values($replacearray),$canonized_headline); $refer[$headlineCount] = $canonized_headline; # count how many in assoc. array so we can track dupes in anchors @@ -1829,26 +1937,26 @@ class Parser # Prepend the number to the heading text if( $doNumberHeadings || $doShowToc ) { - $tocline = $numbering . " " . $tocline; + $tocline = $numbering . ' ' . $tocline; # Don't number the heading if it is the only one (looks silly) if( $doNumberHeadings && count( $matches[3] ) > 1) { # the two are different if the line contains a link - $headline=$numbering . " " . $headline; + $headline=$numbering . ' ' . $headline; } } # Create the anchor for linking from the TOC to the section $anchor = $canonized_headline; if($refcount[$headlineCount] > 1 ) { - $anchor .= "_" . $refcount[$headlineCount]; + $anchor .= '_' . $refcount[$headlineCount]; } if( $doShowToc ) { $toc .= $sk->tocLine($anchor,$tocline,$toclevel); } if( $showEditLink ) { if ( empty( $head[$headlineCount] ) ) { - $head[$headlineCount] = ""; + $head[$headlineCount] = ''; } $head[$headlineCount] .= $sk->editSectionLink($headlineCount+1); } @@ -1872,7 +1980,7 @@ class Parser # split up and insert constructed headlines - $blocks = preg_split( "/<H[1-6].*?" . ">.*?<\/H[1-6]>/i", $text ); + $blocks = preg_split( '/<H[1-6].*?' . '>.*?<\/H[1-6]>/i', $text ); $i = 0; foreach( $blocks as $block ) { @@ -1899,73 +2007,54 @@ class Parser return $full; } - /* private */ function doMagicISBN( &$tokenizer ) - { + # Return an HTML link for the "ISBN 123456" text + /* private */ function magicISBN( $text ) { global $wgLang; - # Check whether next token is a text token - # If yes, fetch it and convert the text into a - # Special::BookSources link - $token = $tokenizer->previewToken(); - while ( $token["type"] == "" ) - { - $tokenizer->nextToken(); - $token = $tokenizer->previewToken(); - } - if ( $token["type"] == "text" ) - { - $token = $tokenizer->nextToken(); - $x = $token["text"]; - $valid = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $a = split( 'ISBN ', " $text" ); + if ( count ( $a ) < 2 ) return $text; + $text = substr( array_shift( $a ), 1); + $valid = '0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $isbn = $blank = "" ; - while ( " " == $x{0} ) { - $blank .= " "; + foreach ( $a as $x ) { + $isbn = $blank = '' ; + while ( ' ' == $x{0} ) { + $blank .= ' '; $x = substr( $x, 1 ); } while ( strstr( $valid, $x{0} ) != false ) { $isbn .= $x{0}; $x = substr( $x, 1 ); } - $num = str_replace( "-", "", $isbn ); - $num = str_replace( " ", "", $num ); + $num = str_replace( '-', '', $isbn ); + $num = str_replace( ' ', '', $num ); - if ( "" == $num ) { - $text = "ISBN $blank$x"; + if ( '' == $num ) { + $text .= "ISBN $blank$x"; } else { - $titleObj = Title::makeTitle( NS_SPECIAL, "Booksources" ); - $text = "<a href=\"" . + $titleObj = Title::makeTitle( NS_SPECIAL, 'Booksources' ); + $text .= '<a href="' . $titleObj->escapeLocalUrl( "isbn={$num}" ) . "\" class=\"internal\">ISBN $isbn</a>"; $text .= $x; } - } else { - $text = "ISBN "; } return $text; } - /* private */ function doMagicRFC( &$tokenizer ) - { + + # Return an HTML link for the "RFC 1234" text + /* private */ function magicRFC( $text ) { global $wgLang; - # Check whether next token is a text token - # If yes, fetch it and convert the text into a - # link to an RFC source - $token = $tokenizer->previewToken(); - while ( $token["type"] == "" ) - { - $tokenizer->nextToken(); - $token = $tokenizer->previewToken(); - } - if ( $token["type"] == "text" ) - { - $token = $tokenizer->nextToken(); - $x = $token["text"]; - $valid = "0123456789"; + $a = split( 'RFC ', ' '.$text ); + if ( count ( $a ) < 2 ) return $text; + $text = substr( array_shift( $a ), 1); + $valid = '0123456789'; - $rfc = $blank = "" ; - while ( " " == $x{0} ) { - $blank .= " "; + foreach ( $a as $x ) { + $rfc = $blank = '' ; + while ( ' ' == $x{0} ) { + $blank .= ' '; $x = substr( $x, 1 ); } while ( strstr( $valid, $x{0} ) != false ) { @@ -1973,23 +2062,20 @@ class Parser $x = substr( $x, 1 ); } - if ( "" == $rfc ) { + if ( '' == $rfc ) { $text .= "RFC $blank$x"; } else { - $url = wfmsg( "rfcurl" ); - $url = str_replace( "$1", $rfc, $url); + $url = wfmsg( 'rfcurl' ); + $url = str_replace( '$1', $rfc, $url); $sk =& $this->mOptions->getSkin(); $la = $sk->getExternalLinkAttributes( $url, "RFC {$rfc}" ); - $text = "<a href='{$url}'{$la}>RFC {$rfc}</a>{$x}"; + $text .= "<a href='{$url}'{$la}>RFC {$rfc}</a>{$x}"; } - } else { - $text = "RFC "; } return $text; } - function preSaveTransform( $text, &$title, &$user, $options, $clearState = true ) - { + function preSaveTransform( $text, &$title, &$user, $options, $clearState = true ) { $this->mOptions = $options; $this->mTitle =& $title; $this->mOutputType = OT_WIKI; @@ -2004,19 +2090,21 @@ class Parser ); $text = str_replace(array_keys($pairs), array_values($pairs), $text); // now with regexes + /* $pairs = array( "/<br.+(clear|break)=[\"']?(all|both)[\"']?\\/?>/i" => '<br style="clear:both;"/>', - "/<br *?>/i" => "<br/>", + "/<br *?>/i" => "<br />", ); $text = preg_replace(array_keys($pairs), array_values($pairs), $text); + */ $text = $this->strip( $text, $stripState, false ); $text = $this->pstPass2( $text, $user ); $text = $this->unstrip( $text, $stripState ); + $text = $this->unstripNoWiki( $text, $stripState ); return $text; } - /* private */ function pstPass2( $text, &$user ) - { + /* private */ function pstPass2( $text, &$user ) { global $wgLang, $wgLocaltimezone, $wgCurParser; # Variable replacement @@ -2026,20 +2114,20 @@ class Parser # Signatures # $n = $user->getName(); - $k = $user->getOption( "nickname" ); - if ( "" == $k ) { $k = $n; } + $k = $user->getOption( 'nickname' ); + if ( '' == $k ) { $k = $n; } if(isset($wgLocaltimezone)) { - $oldtz = getenv("TZ"); putenv("TZ=$wgLocaltimezone"); + $oldtz = getenv('TZ'); putenv('TZ='.$wgLocaltimezone); } /* Note: this is an ugly timezone hack for the European wikis */ - $d = $wgLang->timeanddate( date( "YmdHis" ), false ) . - " (" . date( "T" ) . ")"; - if(isset($wgLocaltimezone)) putenv("TZ=$oldtz"); + $d = $wgLang->timeanddate( date( 'YmdHis' ), false ) . + ' (' . date( 'T' ) . ')'; + if(isset($wgLocaltimezone)) putenv('TZ='.$oldtzs); - $text = preg_replace( "/~~~~~/", $d, $text ); - $text = preg_replace( "/~~~~/", "[[" . $wgLang->getNsText( + $text = preg_replace( '/~~~~~/', $d, $text ); + $text = preg_replace( '/~~~~/', '[[' . $wgLang->getNsText( Namespace::getUser() ) . ":$n|$k]] $d", $text ); - $text = preg_replace( "/~~~/", "[[" . $wgLang->getNsText( + $text = preg_replace( '/~~~/', '[[' . $wgLang->getNsText( Namespace::getUser() ) . ":$n|$k]]", $text ); # Context links: [[|name]] and [[name (context)|]] @@ -2059,12 +2147,12 @@ class Parser if ( preg_match( $conpat, $t, $m ) ) { $context = $m[2]; } - $text = preg_replace( $p4, "[[\\1:\\2 (\\3)|\\2]]", $text ); - $text = preg_replace( $p1, "[[\\1 (\\2)|\\1]]", $text ); - $text = preg_replace( $p3, "[[\\1:\\2|\\2]]", $text ); + $text = preg_replace( $p4, '[[\\1:\\2 (\\3)|\\2]]', $text ); + $text = preg_replace( $p1, '[[\\1 (\\2)|\\1]]', $text ); + $text = preg_replace( $p3, '[[\\1:\\2|\\2]]', $text ); - if ( "" == $context ) { - $text = preg_replace( $p2, "[[\\1]]", $text ); + if ( '' == $context ) { + $text = preg_replace( $p2, '[[\\1]]', $text ); } else { $text = preg_replace( $p2, "[[\\1 ({$context})|\\1]]", $text ); } @@ -2088,8 +2176,7 @@ class Parser # Set up some variables which are usually set up in parse() # so that an external function can call some class members with confidence - function startExternalParse( &$title, $options, $outputType, $clearState = true ) - { + function startExternalParse( &$title, $options, $outputType, $clearState = true ) { $this->mTitle =& $title; $this->mOptions = $options; $this->mOutputType = $outputType; @@ -2117,11 +2204,21 @@ class Parser $executing = false; return $text; } + + # Create an HTML-style tag, e.g. <yourtag>special text</yourtag> + # Callback will be called with the text within + # Transform and return the text within + function setHook( $tag, $callback ) { + $oldVal = @$this->mTagHooks[$tag]; + $this->mTagHooks[$tag] = $callback; + return $oldVal; + } } class ParserOutput { var $mText, $mLanguageLinks, $mCategoryLinks, $mContainsOldMagic; + var $mCacheTime; # Used in ParserCache function ParserOutput( $text = "", $languageLinks = array(), $categoryLinks = array(), $containsOldMagic = false ) @@ -2130,16 +2227,19 @@ class ParserOutput $this->mLanguageLinks = $languageLinks; $this->mCategoryLinks = $categoryLinks; $this->mContainsOldMagic = $containsOldMagic; + $this->mCacheTime = ""; } function getText() { return $this->mText; } function getLanguageLinks() { return $this->mLanguageLinks; } function getCategoryLinks() { return $this->mCategoryLinks; } + function getCacheTime() { return $this->mCacheTime; } function containsOldMagic() { return $this->mContainsOldMagic; } function setText( $text ) { return wfSetVar( $this->mText, $text ); } function setLanguageLinks( $ll ) { return wfSetVar( $this->mLanguageLinks, $ll ); } function setCategoryLinks( $cl ) { return wfSetVar( $this->mCategoryLinks, $cl ); } function setContainsOldMagic( $com ) { return wfSetVar( $this->mContainsOldMagic, $com ); } + function setCacheTime( $t ) { return wfSetVar( $this->mCacheTime, $t ); } function merge( $other ) { $this->mLanguageLinks = array_merge( $this->mLanguageLinks, $other->mLanguageLinks ); @@ -2164,39 +2264,38 @@ class ParserOptions var $mNumberHeadings; # Automatically number headings var $mShowToc; # Show table of contents - function getUseTeX() { return $this->mUseTeX; } - function getUseCategoryMagic() { return $this->mUseCategoryMagic; } - function getUseDynamicDates() { return $this->mUseDynamicDates; } - function getInterwikiMagic() { return $this->mInterwikiMagic; } - function getAllowExternalImages() { return $this->mAllowExternalImages; } - function getSkin() { return $this->mSkin; } - function getDateFormat() { return $this->mDateFormat; } - function getEditSection() { return $this->mEditSection; } - function getEditSectionOnRightClick() { return $this->mEditSectionOnRightClick; } - function getNumberHeadings() { return $this->mNumberHeadings; } - function getShowToc() { return $this->mShowToc; } - - function setUseTeX( $x ) { return wfSetVar( $this->mUseTeX, $x ); } - function setUseCategoryMagic( $x ) { return wfSetVar( $this->mUseCategoryMagic, $x ); } - function setUseDynamicDates( $x ) { return wfSetVar( $this->mUseDynamicDates, $x ); } - function setInterwikiMagic( $x ) { return wfSetVar( $this->mInterwikiMagic, $x ); } - function setAllowExternalImages( $x ) { return wfSetVar( $this->mAllowExternalImages, $x ); } - function setSkin( $x ) { return wfSetRef( $this->mSkin, $x ); } - function setDateFormat( $x ) { return wfSetVar( $this->mDateFormat, $x ); } - function setEditSection( $x ) { return wfSetVar( $this->mEditSection, $x ); } - function setEditSectionOnRightClick( $x ) { return wfSetVar( $this->mEditSectionOnRightClick, $x ); } - function setNumberHeadings( $x ) { return wfSetVar( $this->mNumberHeadings, $x ); } - function setShowToc( $x ) { return wfSetVar( $this->mShowToc, $x ); } - - /* static */ function newFromUser( &$user ) - { + function getUseTeX() { return $this->mUseTeX; } + function getUseCategoryMagic() { return $this->mUseCategoryMagic; } + function getUseDynamicDates() { return $this->mUseDynamicDates; } + function getInterwikiMagic() { return $this->mInterwikiMagic; } + function getAllowExternalImages() { return $this->mAllowExternalImages; } + function getSkin() { return $this->mSkin; } + function getDateFormat() { return $this->mDateFormat; } + function getEditSection() { return $this->mEditSection; } + function getEditSectionOnRightClick() { return $this->mEditSectionOnRightClick; } + function getNumberHeadings() { return $this->mNumberHeadings; } + function getShowToc() { return $this->mShowToc; } + + function setUseTeX( $x ) { return wfSetVar( $this->mUseTeX, $x ); } + function setUseCategoryMagic( $x ) { return wfSetVar( $this->mUseCategoryMagic, $x ); } + function setUseDynamicDates( $x ) { return wfSetVar( $this->mUseDynamicDates, $x ); } + function setInterwikiMagic( $x ) { return wfSetVar( $this->mInterwikiMagic, $x ); } + function setAllowExternalImages( $x ) { return wfSetVar( $this->mAllowExternalImages, $x ); } + function setDateFormat( $x ) { return wfSetVar( $this->mDateFormat, $x ); } + function setEditSection( $x ) { return wfSetVar( $this->mEditSection, $x ); } + function setEditSectionOnRightClick( $x ) { return wfSetVar( $this->mEditSectionOnRightClick, $x ); } + function setNumberHeadings( $x ) { return wfSetVar( $this->mNumberHeadings, $x ); } + function setShowToc( $x ) { return wfSetVar( $this->mShowToc, $x ); } + + function setSkin( &$x ) { $this->mSkin =& $x; } + + /* static */ function newFromUser( &$user ) { $popts = new ParserOptions; $popts->initialiseFromUser( $user ); return $popts; } - function initialiseFromUser( &$userInput ) - { + function initialiseFromUser( &$userInput ) { global $wgUseTeX, $wgUseCategoryMagic, $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages; if ( !$userInput ) { @@ -2212,11 +2311,11 @@ class ParserOptions $this->mInterwikiMagic = $wgInterwikiMagic; $this->mAllowExternalImages = $wgAllowExternalImages; $this->mSkin =& $user->getSkin(); - $this->mDateFormat = $user->getOption( "date" ); - $this->mEditSection = $user->getOption( "editsection" ); - $this->mEditSectionOnRightClick = $user->getOption( "editsectiononrightclick" ); - $this->mNumberHeadings = $user->getOption( "numberheadings" ); - $this->mShowToc = $user->getOption( "showtoc" ); + $this->mDateFormat = $user->getOption( 'date' ); + $this->mEditSection = $user->getOption( 'editsection' ); + $this->mEditSectionOnRightClick = $user->getOption( 'editsectiononrightclick' ); + $this->mNumberHeadings = $user->getOption( 'numberheadings' ); + $this->mShowToc = $user->getOption( 'showtoc' ); } @@ -2229,4 +2328,16 @@ function wfBraceSubstitution( $matches ) return $wgCurParser->braceSubstitution( $matches ); } +function wfArgSubstitution( $matches ) +{ + global $wgCurParser; + return $wgCurParser->argSubstitution( $matches ); +} + +function wfVariableSubstitution( $matches ) +{ + global $wgCurParser; + return $wgCurParser->variableSubstitution( $matches ); +} + ?> diff --git a/includes/ParserCache.php b/includes/ParserCache.php index 70b994365caf..8634a3b7d657 100644 --- a/includes/ParserCache.php +++ b/includes/ParserCache.php @@ -2,67 +2,62 @@ class ParserCache { - function get( &$article, &$user ){ + function getKey( &$article, &$user ) { + global $wgDBname; $hash = $user->getPageRenderingHash(); - $pageid = intval( $id ); - $res = wfQuery("SELECT pc_data FROM parsercache WHERE pc_pageid = {$pageid} ". - " AND pc_prefhash = '{$hash}' AND pc_expire > NOW()", DB_WRITE); - $row = wfFetchObject ( $res ); - if( $row ){ - $retVal = unserialize( gzuncompress($row->pc_data) ); - wfProfileOut( $fname ); - } else { - $retVal = false; - } - return $retVal; + $pageid = intval( $article->getID() ); + $key = "$wgDBname:pcache:idhash:$pageid-$hash"; + return $key; } + + function get( &$article, &$user ) { + global $wgMemc, $wgCacheEpoch; + $fname = "ParserCache::get"; + wfProfileIn( $fname ); - function save( $parserOutput, &$article, &$user ){ $hash = $user->getPageRenderingHash(); $pageid = intval( $article->getID() ); - $title = wfStrencode( $article->mTitle->getPrefixedDBKey() ); - $ser = addslashes( gzcompress( serialize( $parserOutput ) ) ); - if( $parserOutput->containsOldMagic() ){ - $expire = "1 HOUR"; + $key = $this->getKey( $article, $user ); + wfDebug( "Trying parser cache $key\n" ); + $value = $wgMemc->get( $key ); + if ( $value ) { + wfDebug( "Found.\n" ); + # Delete if article has changed since the cache was made + $canCache = $article->checkTouched(); + $cacheTime = $value->getCacheTime(); + $touched = $article->mTouched; + if ( !$canCache || $value->getCacheTime() <= $touched || $cacheTime < $wgCacheEpoch ) { + if ( !$canCache ) { + wfDebug( "Invalid cached redirect, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" ); + } else { + wfDebug( "Key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" ); + } + $wgMemc->delete( $key ); + $value = false; + } } else { - $expire = "7 DAY"; + $value = false; } - wfQuery("REPLACE INTO parsercache (pc_prefhash,pc_pageid,pc_title,pc_data, pc_expire) ". - "VALUES('{$hash}', {$pageid}, '{$title}', '{$ser}', ". - "DATE_ADD(NOW(), INTERVAL {$expire}))", DB_WRITE); - - if( rand() % 50 == 0 ){ // more efficient to just do it sometimes - $this->purge(); - } + wfProfileOut( $fname ); + return $value; } - function purge(){ - wfQuery("DELETE FROM parsercache WHERE pc_expire < NOW() LIMIT 250", DB_WRITE); - } + function save( $parserOutput, &$article, &$user ){ + global $wgMemc; - function clearLinksTo( $pid ){ - $pid = intval( $pid ); - wfQuery("DELETE parsercache FROM parsercache,links ". - "WHERE pc_pageid=links.l_from AND l_to={$pid}", DB_WRITE); - wfQuery("DELETE FROM parsercache WHERE pc_pageid='{$pid}'", DB_WRITE); - } + $key = $this->getKey( $article, $user ); + $now = wfTimestampNow(); + $parserOutput->setCacheTime( $now ); + $parserOutput->mText .= "\n<!-- Saved in parser cache with key $key and timestamp $now -->\n"; - # $title is a prefixed db title, for example like Title->getPrefixedDBkey() returns. - function clearBrokenLinksTo( $title ){ - $title = wfStrencode( $title ); - wfQuery("DELETE parsercache FROM parsercache,brokenlinks ". - "WHERE pc_pageid=bl_from AND bl_to='{$title}'", DB_WRITE); - } - - # $pid is a page id - function clearPage( $pid, $namespace ){ - $pid = intval( $pid ); - if( $namespace == NS_MEDIAWIKI ){ - $this->clearLinksTo( $pid ); + if( $parserOutput->containsOldMagic() ){ + $expire = 3600; # 1 hour } else { - wfQuery("DELETE FROM parsercache WHERE pc_pageid='{$pid}'", DB_WRITE); + $expire = 86400; # 1 day } + + $wgMemc->set( $key, $parserOutput, $expire ); } } diff --git a/includes/Profiling.php b/includes/Profiling.php index 392ca38f1247..ed58bf08d80a 100755 --- a/includes/Profiling.php +++ b/includes/Profiling.php @@ -82,6 +82,7 @@ class Profiler if( !count( $this->mStack ) ) { return "No profiling output\n"; } + $this->close(); $width = 125; $format = "%-" . ($width - 28) . "s %6d %6.3f %6.3f %6.3f%%\n"; $titleFormat = "%-" . ($width - 28) . "s %9s %9s %9s %9s\n"; @@ -173,5 +174,4 @@ class Profiler $wgProfiler = new Profiler(); $wgProfiler->profileIn( "-total" ); - ?> diff --git a/includes/QueryPage.php b/includes/QueryPage.php index 6ffd11662326..43804cee26e8 100644 --- a/includes/QueryPage.php +++ b/includes/QueryPage.php @@ -37,7 +37,7 @@ class QueryPage { function getOrderLimit( $offset, $limit ) { return " ORDER BY value " . ($this->sortDescending() ? "DESC" : "") - . " LIMIT {$offset}, {$limit}"; + . wfLimitResult($limit,$offset); } # Is this query expensive (for some definition of expensive)? Then we diff --git a/includes/RawPage.php b/includes/RawPage.php index b218612a9637..4116f005667c 100644 --- a/includes/RawPage.php +++ b/includes/RawPage.php @@ -8,36 +8,74 @@ class RawPage { function RawPage( $article ) { - global $wgRequest, $wgInputEncoding; + global $wgRequest, $wgInputEncoding, $wgSquidMaxage; $allowedCTypes = array('text/x-wiki', 'text/javascript', 'text/css', 'application/x-zope-edit'); $this->mArticle =& $article; $this->mTitle =& $article->mTitle; + $ctype = $wgRequest->getText( 'ctype' ); + $charset = $wgRequest->getText( 'charset' ); + $smaxage = $wgRequest->getText( 'smaxage' ); + $maxage = $wgRequest->getText( 'maxage' ); + $this->mOldId = $wgRequest->getInt( 'oldid' ); + # special case for 'generated' raw things: user css/js + $gen = $wgRequest->getText( 'gen' ); + if($gen == 'css') { + $this->mGen = $gen; + if($smaxage == '') $smaxage = $wgSquidMaxage; + if($ctype == '') $ctype = 'text/css'; + } else if ($gen == 'js') { + $this->mGen = $gen; + if($smaxage == '') $smaxage = $wgSquidMaxage; + if($ctype == '') $ctype = 'text/javascript'; + } else { + $this->mGen = false; + } + $this->mCharset = !empty($charset) ? $charset : $wgInputEncoding; + $this->mSmaxage = ($smaxage != '') ? $smaxage : 0; + $this->mMaxage = ($maxage != '') ? $maxage : 86400; if(empty($ctype) or !in_array($ctype, $allowedCTypes)) { $this->mContentType = 'text/x-wiki'; } else { $this->mContentType = $ctype; } - - $charset = $wgRequest->getText( 'charset' ); - $this->mCharset = !empty($charset) ? $charset : $wgInputEncoding; - $this->mOldId = $wgRequest->getInt( 'oldid' ); } function view() { + global $wgUser, $wgOut; header( "Content-type: ".$this->mContentType.'; charset='.$this->mCharset ); # allow the client to cache this for 24 hours - header( 'Cache-Control: s-maxage=0, max-age=86400' ); - echo $this->getrawtext(); + header( 'Cache-Control: s-maxage='.$this->mSmaxage.', max-age='.$this->mMaxage ); + if($this->mGen) { + $sk = $wgUser->getSkin(); + $sk->initPage($wgOut); + if($this->mGen == 'css') { + echo $sk->getUserStylesheet(); + } else if($this->mGen == 'js') { + echo $sk->getUserJs(); + } + } else { + echo $this->getrawtext(); + } wfAbruptExit(); } function getrawtext () { - global $wgInputEncoding, $wgLang; + global $wgInputEncoding, $wgLang, $wgIsPg; if( !$this->mTitle ) return ''; $t = wfStrencode( $this->mTitle->getDBKey() ); $ns = $this->mTitle->getNamespace(); + # special case + if($ns == NS_MEDIAWIKI) { + $rawtext = wfMsg($t); + if($wgInputEncoding != $this->mCharset) + $rawtext = $wgLang->iconv( $wgInputEncoding, $this->mCharset, $rawtext ); + return $rawtext; + } + # else get it from the DB if(!empty($this->mOldId)) { - $sql = "SELECT old_text as text,old_timestamp as timestamp,old_user as user,old_flags as flags FROM old " . + $oldtable=$wgIsPg?'"old"':'old'; + $sql = "SELECT old_text AS text,old_timestamp AS timestamp,". + "old_user AS user,old_flags AS flags FROM $oldtable " . "WHERE old_id={$this->mOldId}"; } else { $sql = "SELECT cur_id as id,cur_timestamp as timestamp,cur_user as user,cur_user_text as user_text," . diff --git a/includes/RecentChange.php b/includes/RecentChange.php index fb385bca24b1..ed64ee213cad 100644 --- a/includes/RecentChange.php +++ b/includes/RecentChange.php @@ -5,6 +5,8 @@ define( "RC_EDIT", 0); define( "RC_NEW", 1); define( "RC_MOVE", 2); define( "RC_LOG", 3); +define( "RC_MOVE_OVER_REDIRECT", 4); + /* mAttributes: @@ -21,6 +23,7 @@ mAttributes: rc_this_oldid old_id associated with this entry (or zero) rc_last_oldid old_id associated with the entry before this one (or zero) rc_bot is bot, hidden + rc_ip IP address of the user in dotted quad notation rc_new obsolete, use rc_type==RC_NEW mExtra: @@ -82,7 +85,7 @@ class RecentChange # Writes the data in this object to the database function save() { - global $wgUseRCQueue, $wgRCQueueID, $wgLocalInterwiki; + global $wgUseRCQueue, $wgRCQueueID, $wgLocalInterwiki, $wgPutIPinRC; $fname = "RecentChange::save"; if ( !is_array($this->mExtra) ) { @@ -90,6 +93,10 @@ class RecentChange } $this->mExtra['lang'] = $wgLocalInterwiki; + if ( !$wgPutIPinRC ) { + $this->mAttribs['rc_ip'] = ''; + } + # Insert new row wfInsertArray( "recentchanges", $this->mAttribs, $fname ); @@ -126,12 +133,17 @@ class RecentChange # Makes an entry in the database corresponding to an edit /*static*/ function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, - $oldId, $lastTimestamp, $bot = "default" ) + $oldId, $lastTimestamp, $bot = "default", $ip = '' ) { if ( $bot == "default " ) { $bot = $user->isBot(); } + if ( !$ip ) { + global $wgIP; + $ip = empty( $wgIP ) ? '' : $wgIP; + } + $rc = new RecentChange; $rc->mAttribs = array( 'rc_timestamp' => $timestamp, @@ -149,6 +161,7 @@ class RecentChange 'rc_bot' => $bot ? 1 : 0, 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', + 'rc_ip' => $ip, 'rc_new' => 0 # obsolete ); @@ -161,28 +174,34 @@ class RecentChange # Makes an entry in the database corresponding to page creation # Note: the title object must be loaded with the new id using resetArticleID() - /*static*/ function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot = "default" ) + /*static*/ function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot = "default", $ip='' ) { + if ( !$ip ) { + global $wgIP; + $ip = empty( $wgIP ) ? '' : $wgIP; + } if ( $bot == "default" ) { $bot = $user->isBot(); } + $rc = new RecentChange; $rc->mAttribs = array( - 'rc_timestamp' => $timestamp, - 'rc_cur_time' => $timestamp, - 'rc_namespace' => $title->getNamespace(), - 'rc_title' => $title->getDBkey(), - 'rc_type' => RC_NEW, - 'rc_minor' => $minor ? 1 : 0, - 'rc_cur_id' => $title->getArticleID(), - 'rc_user' => $user->getID(), - 'rc_user_text' => $user->getName(), - 'rc_comment' => $comment, - 'rc_this_oldid' => 0, - 'rc_last_oldid' => 0, - 'rc_bot' => $bot ? 1 : 0, - 'rc_moved_to_ns' => 0, - 'rc_moved_to_title' => '', + 'rc_timestamp' => $timestamp, + 'rc_cur_time' => $timestamp, + 'rc_namespace' => $title->getNamespace(), + 'rc_title' => $title->getDBkey(), + 'rc_type' => RC_NEW, + 'rc_minor' => $minor ? 1 : 0, + 'rc_cur_id' => $title->getArticleID(), + 'rc_user' => $user->getID(), + 'rc_user_text' => $user->getName(), + 'rc_comment' => $comment, + 'rc_this_oldid' => 0, + 'rc_last_oldid' => 0, + 'rc_bot' => $bot ? 1 : 0, + 'rc_moved_to_ns' => 0, + 'rc_moved_to_title' => '', + 'rc_ip' => $ip, 'rc_new' => 1 # obsolete ); @@ -194,15 +213,19 @@ class RecentChange } # Makes an entry in the database corresponding to a rename - /*static*/ function notifyMove( $timestamp, &$oldTitle, &$newTitle, &$user, $comment ) + /*static*/ function notifyMove( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='', $overRedir = false ) { + if ( !$ip ) { + global $wgIP; + $ip = empty( $wgIP ) ? '' : $wgIP; + } $rc = new RecentChange; $rc->mAttribs = array( 'rc_timestamp' => $timestamp, 'rc_cur_time' => $timestamp, 'rc_namespace' => $oldTitle->getNamespace(), 'rc_title' => $oldTitle->getDBkey(), - 'rc_type' => RC_MOVE, + 'rc_type' => $overRedir ? RC_MOVE_OVER_REDIRECT : RC_MOVE, 'rc_minor' => 0, 'rc_cur_id' => $oldTitle->getArticleID(), 'rc_user' => $user->getID(), @@ -213,6 +236,7 @@ class RecentChange 'rc_bot' => $user->isBot() ? 1 : 0, 'rc_moved_to_ns' => $newTitle->getNamespace(), 'rc_moved_to_title' => $newTitle->getDBkey(), + 'rc_ip' => $ip, 'rc_new' => 0 # obsolete ); @@ -224,10 +248,22 @@ class RecentChange $rc->save(); } + /* static */ function notifyMoveToNew( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='' ) { + RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip, false ); + } + + /* static */ function notifyMoveOverRedirect( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='' ) { + RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip='', true ); + } + # A log entry is different to an edit in that previous revisions are # not kept - /*static*/ function notifyLog( $timestamp, &$title, &$user, $comment ) + /*static*/ function notifyLog( $timestamp, &$title, &$user, $comment, $ip='' ) { + if ( !$ip ) { + global $wgIP; + $ip = empty( $wgIP ) ? '' : $wgIP; + } $rc = new RecentChange; $rc->mAttribs = array( 'rc_timestamp' => $timestamp, @@ -245,6 +281,7 @@ class RecentChange 'rc_bot' => 0, 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', + 'rc_ip' => $ip, 'rc_new' => 0 # obsolete ); $rc->mExtra = array( @@ -280,6 +317,7 @@ class RecentChange 'rc_bot' => 0, 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', + 'rc_ip' => '', 'rc_new' => $row->cur_is_new # obsolete ); diff --git a/includes/SearchEngine.php b/includes/SearchEngine.php index 19a081b302f7..53d9e691591b 100644 --- a/includes/SearchEngine.php +++ b/includes/SearchEngine.php @@ -296,6 +296,8 @@ class SearchEngine { # Use cleaner boolean search if available return $this->parseQuery4(); } + # on non mysql4 database: get list of words we don't want to search for + require_once( "FulltextStoplist.php" ); $lc = SearchEngine::legalSearchChars() . "()"; $q = preg_replace( "/([()])/", " \\1 ", $this->mUsertext ); @@ -485,8 +487,13 @@ class SearchEngine { $wgOut->redirect( $t->getFullURL( "action=edit" ) ); return; } - - $wgOut->addHTML( "<p>" . wfMsg("nogomatch", $t->escapeLocalURL( "action=edit" ) ) . "</p>\n" ); + + if( $t ) { + $editurl = $t->escapeLocalURL( "action=edit" ); + } else { + $editurl = ""; # ?? + } + $wgOut->addHTML( "<p>" . wfMsg("nogomatch", $editurl ) . "</p>\n" ); # Try a fuzzy title search $anyhit = false; diff --git a/includes/SearchUpdate.php b/includes/SearchUpdate.php index 08f66eab88ed..c7b9c6103c32 100644 --- a/includes/SearchUpdate.php +++ b/includes/SearchUpdate.php @@ -1,4 +1,5 @@ <?php +# $Id$ # See deferred.doc class SearchUpdate { @@ -24,7 +25,7 @@ class SearchUpdate { function doUpdate() { - global $wgDBminWordLen, $wgLang, $wgDisableSearchUpdate; + global $wgDBminWordLen, $wgLang, $wgDisableSearchUpdate, $wgIsMySQL; if( $wgDisableSearchUpdate || !$this->mId ) { return false; @@ -32,7 +33,8 @@ class SearchUpdate { $lc = SearchEngine::legalSearchChars() . "&#;"; if( $this->mText == false ) { # Just update the title - $sql = "UPDATE LOW_PRIORITY searchindex SET si_title='" . + $lowpri=$wgIsMySQL?"LOW_PRIORITY":""; + $sql = "UPDATE $lowpri searchindex SET si_title='" . wfStrencode( Title::indexTitle( $this->mNamespace, $this->mTitle ) ) . "' WHERE si_page={$this->mId}"; wfQuery( $sql, DB_WRITE, "SearchUpdate::doUpdate" ); @@ -75,7 +77,7 @@ class SearchUpdate { # Strip wiki '' and ''' $text = preg_replace( "/''[']*/", " ", $text ); - $sql = "REPLACE DELAYED INTO searchindex (si_page,si_title,si_text) VALUES ({$this->mId},'" . + $sql = "REPLACE INTO searchindex (si_page,si_title,si_text) VALUES ({$this->mId},'" . wfStrencode( Title::indexTitle( $this->mNamespace, $this->mTitle ) ) . "','" . wfStrencode( $text ) . "')"; wfQuery( $sql, DB_WRITE, "SearchUpdate::doUpdate" ); diff --git a/includes/Setup.php b/includes/Setup.php index 7a668080fa0a..21d5ef39315e 100644 --- a/includes/Setup.php +++ b/includes/Setup.php @@ -11,72 +11,73 @@ if( !isset( $wgProfiling ) ) $wgProfiling = false; if ( $wgProfiling and (0 == rand() % $wgProfileSampleRate ) ) { - require_once( "Profiling.php" ); + require_once( 'Profiling.php' ); } else { - function wfProfileIn( $fn ) {} - function wfProfileOut( $fn = "" ) {} + function wfProfileIn( $fn = '' ) {} + function wfProfileOut( $fn = '' ) {} function wfGetProfilingOutput( $s, $e ) {} function wfProfileClose() {} } /* collect the originating ips */ -if( $wgUseSquid && isset( $_SERVER["HTTP_X_FORWARDED_FOR"] ) ) { +if( $wgUseSquid && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { # If the web server is behind a reverse proxy, we need to find # out where our requests are really coming from. - $hopips = array_map( "trim", explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) ); + $hopips = array_map( 'trim', explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) ); while(in_array(trim(end($hopips)), $wgSquidServers)){ array_pop($hopips); } $wgIP = trim(end($hopips)); } else { - $wgIP = getenv("REMOTE_ADDR"); + $wgIP = getenv('REMOTE_ADDR'); } -$fname = "Setup.php"; +$fname = 'Setup.php'; wfProfileIn( $fname ); global $wgUseDynamicDates; -wfProfileIn( "$fname-includes" ); - -require_once( "GlobalFunctions.php" ); -require_once( "Namespace.php" ); -require_once( "RecentChange.php" ); -require_once( "Skin.php" ); -require_once( "OutputPage.php" ); -require_once( "User.php" ); -require_once( "LinkCache.php" ); -require_once( "Title.php" ); -require_once( "Article.php" ); -require_once( "MagicWord.php" ); -require_once( "memcached-client.php" ); -require_once( "Block.php" ); -require_once( "SearchEngine.php" ); -require_once( "DifferenceEngine.php" ); -require_once( "MessageCache.php" ); -require_once( "BlockCache.php" ); -require_once( "Parser.php" ); -require_once( "ParserCache.php" ); -require_once( "WebRequest.php" ); -require_once( "SpecialPage.php" ); +wfProfileIn( $fname.'-includes' ); + +require_once( 'GlobalFunctions.php' ); +require_once( 'Namespace.php' ); +require_once( 'RecentChange.php' ); +require_once( 'User.php' ); +require_once( 'Skin.php' ); +require_once( 'OutputPage.php' ); +require_once( 'LinkCache.php' ); +require_once( 'Title.php' ); +require_once( 'Article.php' ); +require_once( 'MagicWord.php' ); +require_once( 'memcached-client.php' ); +require_once( 'Block.php' ); +require_once( 'SearchEngine.php' ); +require_once( 'DifferenceEngine.php' ); +require_once( 'MessageCache.php' ); +require_once( 'BlockCache.php' ); +require_once( 'Parser.php' ); +require_once( 'ParserCache.php' ); +require_once( 'WebRequest.php' ); +require_once( 'LoadBalancer.php' ); $wgRequest = new WebRequest(); -wfProfileOut( "$fname-includes" ); -wfProfileIn( "$fname-memcached" ); +wfProfileOut( $fname.'-includes' ); +wfProfileIn( $fname.'-memcached' ); global $wgUser, $wgLang, $wgOut, $wgTitle; global $wgArticle, $wgDeferredUpdateList, $wgLinkCache; global $wgMemc, $wgMagicWords, $wgMwRedir, $wgDebugLogFile; global $wgMessageCache, $wgUseMemCached, $wgUseDatabaseMessages; global $wgMsgCacheExpiry, $wgDBname, $wgCommandLineMode; -global $wgBlockCache, $wgParserCache, $wgParser; +global $wgBlockCache, $wgParserCache, $wgParser, $wgDBConnections; +global $wgLoadBalancer, $wgDBservers, $wgDBloads, $wgDBuser, $wgDBpassword; # Useful debug output if ( $wgCommandLineMode ) { # wfDebug( '"' . implode( '" "', $argv ) . '"' ); -} elseif ( function_exists( "getallheaders" ) ) { +} elseif ( function_exists( 'getallheaders' ) ) { wfDebug( "\nStart request\n" ); wfDebug( $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . "\n" ); $headers = getallheaders(); @@ -126,7 +127,7 @@ if( $wgUseMemCached ) { # Test it to see if it's working # This is necessary because otherwise wfMsg would be extremely inefficient - if ( !$wgMemc->set( "test", "", 0 ) ) { + if ( !$wgMemc->set( 'test', '', 0 ) ) { wfDebug( "Memcached failed setup test - connection error?\n" ); $wgUseMemCached = false; $wgMemc = new FakeMemCachedClient(); @@ -137,43 +138,80 @@ if( $wgUseMemCached ) { # Give the message cache a separate cache in the DB. # This is a speedup over separately querying every message used - require_once( "ObjectCache.php" ); - $messageMemc = new MediaWikiBagOStuff("objectcache"); + require_once( 'ObjectCache.php' ); + $messageMemc = new MediaWikiBagOStuff('objectcache'); } -wfProfileOut( "$fname-memcached" ); -wfProfileIn( "$fname-misc" ); +wfProfileOut( $fname.'-memcached' ); +wfProfileIn( $fname.'-database' ); -require_once( "languages/Language.php" ); +if ( !$wgDBservers ) { + $wgDBservers = array( $wgDBserver ); + $wgDBloads = array( 1 ); +} +$wgLoadBalancer = LoadBalancer::newFromParams( $wgDBservers, $wgDBloads, $wgDBuser, $wgDBpassword, $wgDBname ); +$wgLoadBalancer->force(0); + +wfProfileOut( $fname.'-database' ); +wfProfileIn( $fname.'-language' ); +require_once( 'languages/Language.php' ); $wgMessageCache = new MessageCache; -$wgLangClass = "Language" . ucfirst( $wgLanguageCode ); -if( ! class_exists( $wgLangClass ) || ($wgLanguageCode == "en" && strcasecmp( $wgInputEncoding, "utf-8" ) == 0 ) ) { - require_once( "languages/LanguageUtf8.php" ); - $wgLangClass = "LanguageUtf8"; +$wgLangClass = 'Language' . ucfirst( $wgLanguageCode ); +if( ! class_exists( $wgLangClass ) || ($wgLanguageCode == 'en' && !$wgUseLatin1) ) { + # Default to English/UTF-8 + require_once( 'languages/LanguageUtf8.php' ); + $wgLangClass = 'LanguageUtf8'; } $wgLang = new $wgLangClass(); if ( !is_object($wgLang) ) { print "No language class ($wgLang)\N"; } + +if( $wgUseLatin1 && $wgLanguageCode != 'en' ) { + # For non-UTF-8 non-English. + require_once( 'languages/LanguageLatin1.php' ); + $xxx = new LanguageLatin1( $wgLang ); + unset( $wgLang ); + $wgLang = $xxx; +} +wfProfileOut( $fname.'-language' ); +wfProfileIn( $fname.'-MessageCache' ); + $wgMessageCache->initialise( $messageMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $wgDBname ); +wfProfileOut( $fname.'-MessageCache' ); +wfProfileIn( $fname.'-OutputPage' ); + $wgOut = new OutputPage(); wfDebug( "\n\n" ); +wfProfileOut( $fname.'-OutputPage' ); +wfProfileIn( $fname.'-DateFormatter' ); + if ( $wgUseDynamicDates ) { - require_once( "DateFormatter.php" ); + require_once( 'DateFormatter.php' ); global $wgDateFormatter; $wgDateFormatter = new DateFormatter; } -if( !$wgCommandLineMode && ( isset( $_COOKIE[ini_get("session.name")] ) || isset( $_COOKIE["{$wgDBname}Password"] ) ) ) { +wfProfileOut( $fname.'-DateFormatter' ); +wfProfileIn( $fname.'-SetupSession' ); + +if( !$wgCommandLineMode && ( isset( $_COOKIE[ini_get('session.name')] ) || isset( $_COOKIE[$wgDBname.'Password'] ) ) ) { User::SetupSession(); } +wfProfileOut( $fname.'-SetupSession' ); +wfProfileIn( $fname.'-BlockCache' ); + $wgBlockCache = new BlockCache( true ); + +wfProfileOut( $fname.'-BlockCache' ); +wfProfileIn( $fname.'-User' ); + if( $wgCommandLineMode ) { # Used for some maintenance scripts; user session cookies can screw things up # when the database is in an in-between state. @@ -181,6 +219,10 @@ if( $wgCommandLineMode ) { } else { $wgUser = User::loadFromSession(); } + +wfProfileOut( $fname.'-User' ); +wfProfileIn( $fname.'-misc' ); + $wgDeferredUpdateList = array(); $wgLinkCache = new LinkCache(); $wgMagicWords = array(); @@ -188,10 +230,14 @@ $wgMwRedir =& MagicWord::get( MAG_REDIRECT ); $wgParserCache = new ParserCache(); $wgParser = new Parser(); $wgOut->setParserOptions( ParserOptions::newFromUser( $wgUser ) ); +$wgDBConnections = array(); -if ( !$wgAllowSysopQueries ) { - SpecialPage::removePage( "Asksql" ); -} +# Placeholders in case of DB error +$wgTitle = Title::newFromText( wfMsg( 'badtitle' ) ); +$wgArticle = new Article($wgTitle); + +wfProfileOut( $fname.'-misc' ); +wfProfileIn( $fname.'-extensions' ); # Extension setup functions # Entries should be added to this variable during the inclusion @@ -201,7 +247,7 @@ foreach ( $wgExtensionFunctions as $func ) { $func(); } -wfProfileOut( "$fname-misc" ); +wfProfileOut( $fname.'-extensions' ); wfProfileOut( $fname ); diff --git a/includes/SiteConfiguration.php b/includes/SiteConfiguration.php new file mode 100644 index 000000000000..aa0a6b56aa55 --- /dev/null +++ b/includes/SiteConfiguration.php @@ -0,0 +1,65 @@ +<?php + +# This file is used to configure the live Wikimedia wikis. The file that includes +# it contains passwords and other sensitive data, and there's currently no public +# equivalent. + +class SiteConfiguration { + var $suffixes, $wikis, $settings; + var $localDatabases; + + function get( $setting, $wiki, $suffix, $params = array() ) { + if ( array_key_exists( $wiki, $this->settings[$setting] ) ) { + $retval = $this->settings[$setting][$wiki]; + } elseif ( array_key_exists( $suffix, $this->settings[$setting] ) ) { + $retval = $this->settings[$setting][$suffix]; + } elseif ( array_key_exists( "default", $this->settings[$setting] ) ) { + $retval = $this->settings[$setting]['default']; + } else { + $retval = NULL; + } + if ( !is_null( $retval ) && count( $params ) ) { + foreach ( $params as $key => $value ) { + $retval = str_replace( '$' . $key, $value, $retval ); + } + } + return $retval; + } + + function getBool( $setting, $wiki, $suffix ) { + return (bool)($this->get( $setting, $wiki, $suffix )); + } + + function &getLocalDatabases() { + return $this->localDatabases(); + } + + function initialise() { + foreach ( $this->wikis as $db ) { + $this->localDatabases[$db] = $db; + } + } + + function extractVar( $setting, $wiki, $suffix, &$var, $params ) { + $value = $this->get( $setting, $wiki, $suffix, $params ); + if ( !is_null( $value ) ) { + $var = $value; + } + } + + function extractGlobal( $setting, $wiki, $suffix, $params ) { + $value = $this->get( $setting, $wiki, $suffix, $params ); + if ( !is_null( $value ) ) { + $GLOBALS[$setting] = $value; + } + } + + function extractAllGlobals( $wiki, $suffix, $params ) { + foreach ( $this->settings as $varName => $setting ) { + $this->extractGlobal( $varName, $wiki, $suffix, $params ); + } + } +} + + +?> diff --git a/includes/SiteStatsUpdate.php b/includes/SiteStatsUpdate.php index 4c4b32cde084..900956b6398d 100644 --- a/includes/SiteStatsUpdate.php +++ b/includes/SiteStatsUpdate.php @@ -1,4 +1,5 @@ <?php +# $Id$ # See deferred.doc class SiteStatsUpdate { @@ -14,6 +15,7 @@ class SiteStatsUpdate { function doUpdate() { + global $wgIsMySQL; $a = array(); if ( $this->mViews < 0 ) { $m = "-1"; } @@ -30,8 +32,8 @@ class SiteStatsUpdate { else if ( $this->mGood > 0 ) { $m = "+1"; } else $m = ""; array_push( $a, "ss_good_articles=(ss_good_articles$m)" ); - - $sql = "UPDATE LOW_PRIORITY site_stats SET " . implode ( ",", $a ) . + $lowpri=$wgIsMySQL?"LOW_PRIORITY":""; + $sql = "UPDATE $lowpri site_stats SET " . implode ( ",", $a ) . " WHERE ss_row_id=1"; wfQuery( $sql, DB_WRITE, "SiteStatsUpdate::doUpdate" ); } diff --git a/includes/Skin.php b/includes/Skin.php index 91faf5b5d590..37d6d479e446 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -1,33 +1,33 @@ <?php - -require_once( "Feed.php" ); -require_once( "Image.php" ); - # See skin.doc +require_once( 'Feed.php' ); // should not be called if the actual page isn't feed enabled +require_once( 'Image.php' ); + # These are the INTERNAL names, which get mapped # directly to class names. For display purposes, the # Language class has internationalized names # /* private */ $wgValidSkinNames = array( - 'standard' => "Standard", - 'nostalgia' => "Nostalgia", - 'cologneblue' => "CologneBlue" + 'standard' => 'Standard', + 'nostalgia' => 'Nostalgia', + 'cologneblue' => 'CologneBlue' ); if( $wgUsePHPTal ) { - #$wgValidSkinNames[] = "PHPTal"; - #$wgValidSkinNames['davinci'] = "DaVinci"; - #$wgValidSkinNames['mono'] = "Mono"; - $wgValidSkinNames['monobook'] = "MonoBook"; - #$wgValidSkinNames['monobookminimal'] = "MonoBookMinimal"; + #$wgValidSkinNames[] = 'PHPTal'; + #$wgValidSkinNames['davinci'] = 'DaVinci'; + #$wgValidSkinNames['mono'] = 'Mono'; + $wgValidSkinNames['monobook'] = 'MonoBook'; + $wgValidSkinNames['myskin'] = 'MySkin'; + #$wgValidSkinNames['monobookminimal'] = 'MonoBookMinimal'; } -require_once( "RecentChange.php" ); +require_once( 'RecentChange.php' ); class RCCacheEntry extends RecentChange { var $secureName, $link; - var $curlink , $lastlink , $usertalklink , $versionlink ; + var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ; var $userlink, $timestamp, $watched; function newFromParent( $rc ) @@ -49,7 +49,7 @@ class Skin { function Skin() { - $this->linktrail = wfMsg("linktrail"); + $this->linktrail = wfMsg('linktrail'); } function getSkinNames() @@ -60,7 +60,10 @@ class Skin { function getStylesheet() { - return "wikistandard.css"; + return 'wikistandard.css'; + } + function getSkinName() { + return "standard"; } function qbSetting() @@ -68,17 +71,17 @@ class Skin { global $wgOut, $wgUser; if ( $wgOut->isQuickbarSuppressed() ) { return 0; } - $q = $wgUser->getOption( "quickbar" ); - if ( "" == $q ) { $q = 0; } + $q = $wgUser->getOption( 'quickbar' ); + if ( '' == $q ) { $q = 0; } return $q; } function initPage( &$out ) { - $fname = "Skin::initPage"; + $fname = 'Skin::initPage'; wfProfileIn( $fname ); - $out->addLink( array( "rel" => "shortcut icon", "href" => "/favicon.ico" ) ); + $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) ); $this->addMetadataLinks($out); @@ -95,16 +98,16 @@ class Skin { $out->addMetadataLink( array( 'title' => 'Creative Commons', 'type' => 'application/rdf+xml', - 'href' => $wgTitle->getLocalURL( "action=creativecommons") ) ); + 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) ); } if( $wgEnableDublinCoreRdf ) { $out->addMetadataLink( array( 'title' => 'Dublin Core', 'type' => 'application/rdf+xml', - 'href' => $wgTitle->getLocalURL( "action=dublincore" ) ) ); + 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) ); } } - $copyright = ""; + $copyright = ''; if( $wgRightsPage ) { $copy = Title::newFromText( $wgRightsPage ); if( $copy ) { @@ -116,15 +119,15 @@ class Skin { } if( $copyright ) { $out->addLink( array( - "rel" => "copyright", - "href" => $copyright ) ); + 'rel' => 'copyright', + 'href' => $copyright ) ); } } function outputPage( &$out ) { global $wgDebugComments; - wfProfileIn( "Skin::outputPage" ); + wfProfileIn( 'Skin::outputPage' ); $this->initPage( $out ); $out->out( $out->headElement() ); @@ -151,20 +154,45 @@ class Skin { } function getHeadScripts() { - global $wgStylePath; + global $wgStylePath, $wgUser, $wgLang; $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/wikibits.js\"></script>\n"; + if( $wgUser->getID() != 0 ) { # logged in + $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName(); + $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript')); + $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n"; + } return $r; } + # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way) + function getUserStylesheet() { + global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle; + $sheet = $this->getStylesheet(); + $action = $wgRequest->getText('action'); + $s = "@import \"$wgStylePath/$sheet\";\n"; + if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common_rtl.css\";\n"; + if( $wgUser->getID() != 0 ) { # logged in + if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) { + $s .= $wgRequest->getText('wpTextbox1'); + } else { + $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName(); + $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n"; + } + } + $s .= $this->doGetUserStyles(); + return $s."\n"; + } + # placeholder, returns generated js in monobook + function getUserJs() { + return; + } + function getUserStyles() { global $wgOut, $wgStylePath, $wgLang; - $sheet = $this->getStylesheet(); $s = "<style type='text/css'>\n"; $s .= "/*/*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac - $s .= "@import url(\"$wgStylePath/$sheet\");\n"; - if($wgLang->isRTL()) $s .= "@import url(\"$wgStylePath/common_rtl.css\");\n"; - $s .= $this->doGetUserStyles(); + $s .= $this->getUserStylesheet(); $s .= "/* */\n"; $s .= "</style>\n"; return $s; @@ -174,19 +202,19 @@ class Skin { { global $wgUser; - $s = ""; - if ( 1 == $wgUser->getOption( "underline" ) ) { + $s = ''; + if ( 1 == $wgUser->getOption( 'underline' ) ) { # Don't override browser settings } else { # CHECK MERGE @@@ # Force no underline - $s .= "a { " . + $s .= 'a { ' . "text-decoration: none; }\n"; } - if ( 1 == $wgUser->getOption( "highlightbroken" ) ) { + if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) { $s .= "a.new, #quickbar a.new { color: #CC2200; }\n"; } - if ( 1 == $wgUser->getOption( "justify" ) ) { + if ( 1 == $wgUser->getOption( 'justify' ) ) { $s .= "#article { text-align: justify; }\n"; } return $s; @@ -199,13 +227,13 @@ class Skin { extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) ); if ( 0 != $wgTitle->getNamespace() ) { - $a = array( "bgcolor" => "#ffffec" ); + $a = array( 'bgcolor' => '#ffffec' ); } - else $a = array( "bgcolor" => "#FFFFFF" ); - if($wgOut->isArticle() && $wgUser->getOption("editondblclick") && + else $a = array( 'bgcolor' => '#FFFFFF' ); + if($wgOut->isArticle() && $wgUser->getOption('editondblclick') && (!$wgTitle->isProtected() || $wgUser->isSysop()) ) { - $t = wfMsg( "editthispage" ); - $oid = $red = ""; + $t = wfMsg( 'editthispage' ); + $oid = $red = ''; if ( !empty($redirect) ) { $red = "&redirect={$redirect}"; } @@ -213,26 +241,26 @@ class Skin { $oid = "&oldid={$oldid}"; } $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" ); - $s = "document.location = \"" .$s ."\";"; - $a += array ("ondblclick" => $s); + $s = 'document.location = "' .$s .'";'; + $a += array ('ondblclick' => $s); } $a['onload'] = $wgOut->getOnloadHandler(); return $a; } - function getExternalLinkAttributes( $link, $text ) + function getExternalLinkAttributes( $link, $text, $class='' ) { global $wgUser, $wgOut, $wgLang; $link = urldecode( $link ); $link = $wgLang->checkTitleEncoding( $link ); - $link = str_replace( "_", " ", $link ); + $link = str_replace( '_', ' ', $link ); $link = wfEscapeHTML( $link ); - $r = " class='external'"; + $r = ($class != '') ? " class='$class'" : " class='external'"; - if ( 1 == $wgUser->getOption( "hover" ) ) { + if ( 1 == $wgUser->getOption( 'hover' ) ) { $r .= " title=\"{$link}\""; } return $r; @@ -243,18 +271,18 @@ class Skin { global $wgUser, $wgOut; $link = urldecode( $link ); - $link = str_replace( "_", " ", $link ); + $link = str_replace( '_', ' ', $link ); $link = wfEscapeHTML( $link ); - if ( $broken == "stub" ) { - $r = " class='stub'"; - } else if ( $broken == "yes" ) { - $r = " class='new'"; + if ( $broken == 'stub' ) { + $r = ' class="stub"'; + } else if ( $broken == 'yes' ) { + $r = ' class="new"'; } else { - $r = ""; + $r = ''; } - if ( 1 == $wgUser->getOption( "hover" ) ) { + if ( 1 == $wgUser->getOption( 'hover' ) ) { $r .= " title=\"{$link}\""; } return $r; @@ -264,15 +292,15 @@ class Skin { { global $wgUser, $wgOut; - if ( $broken == "stub" ) { - $r = " class='stub'"; - } else if ( $broken == "yes" ) { - $r = " class='new'"; + if ( $broken == 'stub' ) { + $r = ' class="stub"'; + } else if ( $broken == 'yes' ) { + $r = ' class="new"'; } else { - $r = ""; + $r = ''; } - if ( 1 == $wgUser->getOption( "hover" ) ) { + if ( 1 == $wgUser->getOption( 'hover' ) ) { $r .= ' title ="' . $nt->getEscapedText() . '"'; } return $r; @@ -292,9 +320,9 @@ class Skin { global $wgUser, $wgOut, $wgSiteNotice; if( $wgSiteNotice ) { - $note = "\n<div id='notice' style='font-weight: bold; color: red; text-align: center'>$wgSiteNotice</div>\n"; + $note = "\n<div id='siteNotice'>$wgSiteNotice</div>\n"; } else { - $note = ""; + $note = ''; } return $this->doBeforeContent() . $note; } @@ -302,19 +330,19 @@ class Skin { function doBeforeContent() { global $wgUser, $wgOut, $wgTitle, $wgLang; - $fname = "Skin::doBeforeContent"; + $fname = 'Skin::doBeforeContent'; wfProfileIn( $fname ); - $s = ""; + $s = ''; $qb = $this->qbSetting(); if( $langlinks = $this->otherLanguages() ) { $rows = 2; - $borderhack = ""; + $borderhack = ''; } else { $rows = 1; $langlinks = false; - $borderhack = "class='top'"; + $borderhack = 'class="top"'; } $s .= "\n<div id='content'>\n<div id='topbar'>\n" . @@ -326,11 +354,11 @@ class Skin { if ( !$shove ) { $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" . - $this->logoText() . "</td>"; + $this->logoText() . '</td>'; } elseif( $left ) { $s .= $this->getQuickbarCompensator( $rows ); } - $l = $wgLang->isRTL() ? "right" : "left"; + $l = $wgLang->isRTL() ? 'right' : 'left'; $s .= "<td {$borderhack} align='$l' valign='top'>\n"; $s .= $this->topLinks() ; @@ -358,18 +386,35 @@ class Skin { return $s; } - function getCategories () { + function getCategoryLinks () { global $wgOut, $wgTitle, $wgUser, $wgParser; - global $wgUseCategoryMagic; - if( !$wgUseCategoryMagic ) return "" ; - if( count( $wgOut->mCategoryLinks ) == 0 ) return ""; - if( !$wgOut->isArticle() ) return ""; + global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang; + + if( !$wgUseCategoryMagic ) return '' ; + if( count( $wgOut->mCategoryLinks ) == 0 ) return ''; + + # Taken out so that they will be displayed in previews -- TS + #if( !$wgOut->isArticle() ) return ''; + + $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ; + $s = $this->makeKnownLink( 'Special:Categories', + wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) ) + . ': ' . $t; + + if($wgUseCategoryBrowser) { + $s .= '<br/><hr/>'; + $catstack = array(); + $s.= $wgTitle->getAllParentCategories($catstack); + } - $t = implode ( " | " , $wgOut->mCategoryLinks ) ; - $s = $this->makeKnownLink( "Special:Categories", - wfMsg( "categories" ), "article=" . urlencode( $wgTitle->getPrefixedDBkey() ) ) - . ": " . $t; - return "<p class='catlinks'>$s</p>"; + return $s; + } + + function getCategories() { + $catlinks=$this->getCategoryLinks(); + if(!empty($catlinks)) { + return "<p class='catlinks'>{$catlinks}</p>"; + } } function getQuickbarCompensator( $rows = 1 ) @@ -398,16 +443,16 @@ class Skin { function doAfterContent() { global $wgUser, $wgOut, $wgLang; - $fname = "Skin::doAfterContent"; + $fname = 'Skin::doAfterContent'; wfProfileIn( $fname ); - wfProfileIn( "$fname-1" ); + wfProfileIn( $fname.'-1' ); $s = "\n</div><br style=\"clear:both\" />\n"; $s .= "\n<div id='footer'>"; - $s .= "<table border='0' cellspacing='0'><tr>"; + $s .= '<table border="0" cellspacing="0"><tr>'; - wfProfileOut( "$fname-1" ); - wfProfileIn( "$fname-2" ); + wfProfileOut( $fname.'-1' ); + wfProfileIn( $fname.'-2' ); $qb = $this->qbSetting(); $shove = ($qb != 0); @@ -417,17 +462,17 @@ class Skin { if ( $shove && $left ) { # Left $s .= $this->getQuickbarCompensator(); } - wfProfileOut( "$fname-2" ); - wfProfileIn( "$fname-3" ); - $l = $wgLang->isRTL() ? "right" : "left"; + wfProfileOut( $fname.'-2' ); + wfProfileIn( $fname.'-3' ); + $l = $wgLang->isRTL() ? 'right' : 'left'; $s .= "<td class='bottom' align='$l' valign='top'>"; $s .= $this->bottomLinks(); $s .= "\n<br />" . $this->mainPageLink() - . " | " . $this->aboutLink() - . " | " . $this->specialLink( "recentchanges" ) - . " | " . $this->searchForm() - . "<br /><span id='pagestats'>" . $this->pageStats() . "</span>"; + . ' | ' . $this->aboutLink() + . ' | ' . $this->specialLink( 'recentchanges' ) + . ' | ' . $this->searchForm() + . '<br /><span id="pagestats">' . $this->pageStats() . '</span>'; $s .= "</td>"; if ( $shove && !$left ) { # Right @@ -435,10 +480,10 @@ class Skin { } $s .= "</tr></table>\n</div>\n</div>\n"; - wfProfileOut( "$fname-3" ); - wfProfileIn( "$fname-4" ); + wfProfileOut( $fname.'-3' ); + wfProfileIn( $fname.'-4' ); if ( 0 != $qb ) { $s .= $this->quickBar(); } - wfProfileOut( "$fname-4" ); + wfProfileOut( $fname.'-4' ); wfProfileOut( $fname ); return $s; } @@ -451,7 +496,7 @@ class Skin { $action = $wgRequest->getText( 'action' ); $s = $this->printableLink(); - if ( wfMsg ( "disclaimers" ) != "-" ) $s .= " | " . $this->makeKnownLink( wfMsg( "disclaimerpage" ), wfMsg( "disclaimers" ) ) ; + if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ; if ( $wgOut->isArticleRelated() ) { if ( $wgTitle->getNamespace() == Namespace::getImage() ) { @@ -464,16 +509,16 @@ class Skin { if ( isset ( $wgUseApproval ) && $wgUseApproval ) { $t = $wgTitle->getDBkey(); - $name = "Approve this article" ; + $name = 'Approve this article' ; $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ; #wfEscapeHTML( wfImageUrl( $name ) ); $style = $this->getExternalLinkAttributes( $link, $name ); $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ; } } - if ( "history" == $action || isset( $diff ) || isset( $oldid ) ) { - $s .= " | " . $this->makeKnownLink( $wgTitle->getPrefixedText(), - wfMsg( "currentrev" ) ); + if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) { + $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(), + wfMsg( 'currentrev' ) ); } if ( $wgUser->getNewtalk() ) { @@ -485,35 +530,45 @@ class Skin { $n =$wgUser->getName(); $tl = $this->makeKnownLink( $wgLang->getNsText( Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}", - wfMsg("newmessageslink") ); - $s.=" | <strong>". wfMsg( "newmessages", $tl ) . "</strong>"; + wfMsg('newmessageslink') ); + $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>'; } } - if( $wgUser->isSysop() && - (($wgTitle->getArticleId() == 0) || ($action == "history")) && - ($n = $wgTitle->isDeleted() ) ) { - $s .= " | " . wfMsg( "thisisdeleted", - $this->makeKnownLink( - $wgLang->SpecialPage( "Undelete/" . $wgTitle->getPrefixedDBkey() ), - wfMsg( "restorelink", $n ) ) ); + + $undelete = $this->getUndeleteLink(); + if( !empty( $undelete ) ) { + $s .= ' | '.$undelete; } return $s; } + function getUndeleteLink() { + global $wgUser, $wgTitle, $wgLang, $action; + if( $wgUser->isSysop() && + (($wgTitle->getArticleId() == 0) || ($action == "history")) && + ($n = $wgTitle->isDeleted() ) ) { + return wfMsg( 'thisisdeleted', + $this->makeKnownLink( + $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ), + wfMsg( 'restorelink', $n ) ) ); + } + return ''; + } + function printableLink() { global $wgOut, $wgFeedClasses, $wgRequest; $baseurl = $_SERVER['REQUEST_URI']; - if( strpos( "?", $baseurl ) == false ) { - $baseurl .= "?"; + if( strpos( '?', $baseurl ) == false ) { + $baseurl .= '?'; } else { - $baseurl .= "&"; + $baseurl .= '&'; } $baseurl = htmlspecialchars( $baseurl ); - $printurl = $wgRequest->escapeAppendQuery( "printable=yes" ); + $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' ); - $s = "<a href=\"$printurl\">" . wfMsg( "printableversion" ) . "</a>"; + $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>'; if( $wgOut->isSyndicated() ) { foreach( $wgFeedClasses as $format => $class ) { $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" ); @@ -527,8 +582,8 @@ class Skin { { global $wgOut, $wgTitle, $wgUser; - $s = "<h1 class='pagetitle'>" . htmlspecialchars( $wgOut->getPageTitle() ) . "</h1>"; - if($wgUser->getOption("editsectiononrightclick") && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);} + $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>'; + if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);} return $s; } @@ -537,9 +592,9 @@ class Skin { global $wgOut; $sub = $wgOut->getSubtitle(); - if ( "" == $sub ) { + if ( '' == $sub ) { global $wgExtraSubtitle; - $sub = wfMsg( "fromwikipedia" ) . $wgExtraSubtitle; + $sub = wfMsg( 'fromwikipedia' ) . $wgExtraSubtitle; } $subpages = $this->subPageSubtitle(); $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":''; @@ -553,23 +608,23 @@ class Skin { $subpages = ''; if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) { $ptext=$wgTitle->getPrefixedText(); - if(preg_match("/\//",$ptext)) { - $links=explode("/",$ptext); - $c=0; - $growinglink=""; + if(preg_match('/\//',$ptext)) { + $links = explode('/',$ptext); + $c = 0; + $growinglink = ''; foreach($links as $link) { $c++; if ($c<count($links)) { $growinglink .= $link; $getlink = $this->makeLink( $growinglink, $link ); - if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time + if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time if ($c>1) { - $subpages .= " | "; + $subpages .= ' | '; } else { - $subpages .="< "; + $subpages .= '< '; } $subpages .= $getlink; - $growinglink.="/"; + $growinglink .= '/'; } } } @@ -581,30 +636,30 @@ class Skin { { global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP; - $li = $wgLang->specialPage( "Userlogin" ); - $lo = $wgLang->specialPage( "Userlogout" ); + $li = $wgLang->specialPage( 'Userlogin' ); + $lo = $wgLang->specialPage( 'Userlogout' ); - $s = ""; + $s = ''; if ( 0 == $wgUser->getID() ) { - if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) { + if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) { $n = $wgIP; $tl = $this->makeKnownLink( $wgLang->getNsText( Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}", $wgLang->getNsText( Namespace::getTalk( 0 ) ) ); - $s .= $n . " (".$tl.")"; + $s .= $n . ' ('.$tl.')'; } else { - $s .= wfMsg("notloggedin"); + $s .= wfMsg('notloggedin'); } $rt = $wgTitle->getPrefixedURL(); if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) { - $q = ""; + $q = ''; } else { $q = "returnto={$rt}"; } $s .= "\n<br />" . $this->makeKnownLink( $li, - wfMsg( "login" ), $q ); + wfMsg( 'login' ), $q ); } else { $n = $wgUser->getName(); $rt = $wgTitle->getPrefixedURL(); @@ -616,18 +671,18 @@ class Skin { $s .= $this->makeKnownLink( $wgLang->getNsText( Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" . - $this->makeKnownLink( $lo, wfMsg( "logout" ), - "returnto={$rt}" ) . " | " . - $this->specialLink( "preferences" ); + $this->makeKnownLink( $lo, wfMsg( 'logout' ), + "returnto={$rt}" ) . ' | ' . + $this->specialLink( 'preferences' ); } - $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ), - wfMsg( "help" ) ); + $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ), + wfMsg( 'help' ) ); return $s; } function getSearchLink() { - $searchPage =& Title::makeTitle( NS_SPECIAL, "Search" ); + $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' ); return $searchPage->getLocalURL(); } @@ -640,12 +695,12 @@ class Skin { global $wgRequest; $search = $wgRequest->getText( 'search' ); - $s = "<form name='search' class='inline' method='post' action=\"" + $s = '<form name="search" class="inline" method="post" action="' . $this->escapeSearchLink() . "\">\n" - . "<input type='text' name=\"search\" size='19' value=\"" + . '<input type="text" name="search" size="19" value="' . htmlspecialchars(substr($search,0,256)) . "\" />\n" - . "<input type='submit' name=\"go\" value=\"" . wfMsg ("go") . "\" /> " - . "<input type='submit' name=\"fulltext\" value=\"" . wfMsg ("search") . "\" />\n</form>"; + . '<input type="submit" name="go" value="' . wfMsg ('go') . '" /> ' + . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>"; return $s; } @@ -656,7 +711,7 @@ class Skin { $sep = " |\n"; $s = $this->mainPageLink() . $sep - . $this->specialLink( "recentchanges" ); + . $this->specialLink( 'recentchanges' ); if ( $wgOut->isArticleRelated() ) { $s .= $sep . $this->editThisPage() @@ -673,9 +728,9 @@ class Skin { global $wgOut, $wgUser, $wgTitle; $sep = " |\n"; - $s = ""; + $s = ''; if ( $wgOut->isArticleRelated() ) { - $s .= "<strong>" . $this->editThisPage() . "</strong>"; + $s .= '<strong>' . $this->editThisPage() . '</strong>'; if ( 0 != $wgUser->getID() ) { $s .= $sep . $this->watchThisPage(); } @@ -716,21 +771,21 @@ class Skin { global $wgDisableCounters; extract( $wgRequest->getValues( 'oldid', 'diff' ) ); - if ( ! $wgOut->isArticle() ) { return ""; } - if ( isset( $oldid ) || isset( $diff ) ) { return ""; } - if ( 0 == $wgArticle->getID() ) { return ""; } + if ( ! $wgOut->isArticle() ) { return ''; } + if ( isset( $oldid ) || isset( $diff ) ) { return ''; } + if ( 0 == $wgArticle->getID() ) { return ''; } - $s = ""; + $s = ''; if ( !$wgDisableCounters ) { $count = $wgLang->formatNum( $wgArticle->getCount() ); if ( $count ) { - $s = wfMsg( "viewcount", $count ); + $s = wfMsg( 'viewcount', $count ); } } - $s .= " " . $this->getCredits(); + $s .= ' ' . $this->getCredits(); - return $s . " " . $this->getCopyright(); + return $s . ' ' . $this->getCopyright(); } function getCredits() { @@ -743,7 +798,7 @@ class Skin { } else { $s = $this->getAuthorCredits(); if ($wgMaxCredits > 1) { - $s .= " " . $this->getContributorCredits(); + $s .= ' ' . $this->getContributorCredits(); } } @@ -756,13 +811,13 @@ class Skin { $last_author = $wgArticle->getUser(); if ($last_author == 0) { - $author_credit = wfMsg("anonymous"); + $author_credit = wfMsg('anonymous'); } else { $real_name = User::whoIsReal($last_author); if (!empty($real_name)) { $author_credit = $real_name; } else { - $author_credit = wfMsg("siteuser", User::whoIs($last_author)); + $author_credit = wfMsg('siteuser', User::whoIs($last_author)); } } @@ -770,9 +825,9 @@ class Skin { if ( $timestamp ) { $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true ); } else { - $d = ""; + $d = ''; } - return wfMsg("lastmodifiedby", $d, $author_credit); + return wfMsg('lastmodifiedby', $d, $author_credit); } function getContributorCredits() { @@ -802,23 +857,34 @@ class Skin { $user = $wgLang->listToText(array_values($user_names)); if (!empty($user)) { - $user = wfMsg("siteusers", $user); + $user = wfMsg('siteusers', $user); } if ($contributors[0] && $contributors[0][0] > 0) { - $anon = wfMsg("anonymous"); + $anon = wfMsg('anonymous'); } else { $anon = ''; } $creds = $wgLang->listToText(array($real, $user, $anon)); - return wfMsg("othercontribs", $creds); + return wfMsg('othercontribs', $creds); } function getCopyright() { - global $wgRightsPage, $wgRightsUrl, $wgRightsText; - $out = ""; + global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest; + + + $oldid = $wgRequest->getVal( 'oldid' ); + $diff = $wgRequest->getVal( 'diff' ); + + if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) { + $msg = 'history_copyright'; + } else { + $msg = 'copyright'; + } + + $out = ''; if( $wgRightsPage ) { $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText ); } elseif( $wgRightsUrl ) { @@ -827,23 +893,23 @@ class Skin { # Give up now return $out; } - $out .= wfMsg( "copyright", $link ); + $out .= wfMsg( $msg, $link ); return $out; } function getCopyrightIcon() { global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon; - $out = ""; + $out = ''; if( $wgRightsIcon ) { $icon = htmlspecialchars( $wgRightsIcon ); if( $wgRightsUrl ) { $url = htmlspecialchars( $wgRightsUrl ); - $out .= "<a href=\"$url\">"; + $out .= '<a href="'.$url.'">'; } $text = htmlspecialchars( $wgRightsText ); $out .= "<img src=\"$icon\" alt='$text' />"; if( $wgRightsUrl ) { - $out .= "</a>"; + $out .= '</a>'; } } return $out; @@ -852,7 +918,7 @@ class Skin { function getPoweredBy() { global $wgStylePath; $url = htmlspecialchars( "$wgStylePath/images/poweredby_mediawiki_88x31.png" ); - $img = "<a href='http://www.mediawiki.org/'><img src='$url' alt='MediaWiki' /></a>"; + $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>'; return $img; } @@ -863,23 +929,23 @@ class Skin { $timestamp = $wgArticle->getTimestamp(); if ( $timestamp ) { $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true ); - $s = " " . wfMsg( "lastmodified", $d ); + $s = ' ' . wfMsg( 'lastmodified', $d ); } else { - $s = ""; + $s = ''; } return $s; } - function logoText( $align = "" ) + function logoText( $align = '' ) { - if ( "" != $align ) { $a = " align='{$align}'"; } - else { $a = ""; } + if ( '' != $align ) { $a = ' align="'.$align.'"'; } + else { $a = ''; } - $mp = wfMsg( "mainpage" ); + $mp = wfMsg( 'mainpage' ); $titleObj = Title::newFromText( $mp ); - $s = "<a href=\"" . $titleObj->escapeLocalURL() - . "\"><img{$a} src=\"" - . $this->getLogo() . "\" alt=\"" . "[{$mp}]\" /></a>"; + $s = '<a href="' . $titleObj->escapeLocalURL() + . '"><img'.$a.' src="' + . $this->getLogo() . '" alt="' . "[{$mp}]\" /></a>"; return $s; } @@ -888,7 +954,7 @@ class Skin { global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang; global $wgDisableUploads, $wgRemoteUploads; - $fname = "Skin::quickBar"; + $fname = 'Skin::quickBar'; wfProfileIn( $fname ); $action = $wgRequest->getText( 'action' ); @@ -900,69 +966,69 @@ class Skin { $sep = "\n<br />"; $s .= $this->mainPageLink() - . $sep . $this->specialLink( "recentchanges" ) - . $sep . $this->specialLink( "randompage" ); + . $sep . $this->specialLink( 'recentchanges' ) + . $sep . $this->specialLink( 'randompage' ); if ($wgUser->getID()) { - $s.= $sep . $this->specialLink( "watchlist" ) ; - $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ), - wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) ); + $s.= $sep . $this->specialLink( 'watchlist' ) ; + $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ), + wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) ); } // only show watchlist link if logged in - if ( wfMsg ( "currentevents" ) != "-" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ; + if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ; $s .= "\n<br /><hr class='sep' />"; $articleExists = $wgTitle->getArticleId(); - if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) { + if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) { if($wgOut->isArticle()) { - $s .= "<strong>" . $this->editThisPage() . "</strong>"; + $s .= '<strong>' . $this->editThisPage() . '</strong>'; } else { # backlink to the article in edit or history mode if($articleExists){ # no backlink if no article switch($tns) { case 0: - $text = wfMsg("articlepage"); + $text = wfMsg('articlepage'); break; case 1: - $text = wfMsg("viewtalkpage"); + $text = wfMsg('viewtalkpage'); break; case 2: - $text = wfMsg("userpage"); + $text = wfMsg('userpage'); break; case 3: - $text = wfMsg("viewtalkpage"); + $text = wfMsg('viewtalkpage'); break; case 4: - $text = wfMsg("wikipediapage"); + $text = wfMsg('wikipediapage'); break; case 5: - $text = wfMsg("viewtalkpage"); + $text = wfMsg('viewtalkpage'); break; case 6: - $text = wfMsg("imagepage"); + $text = wfMsg('imagepage'); break; case 7: - $text = wfMsg("viewtalkpage"); + $text = wfMsg('viewtalkpage'); break; default: - $text= wfMsg("articlepage"); + $text= wfMsg('articlepage'); } $link = $wgTitle->getText(); if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary - $link = $nstext . ":" . $link ; + $link = $nstext . ':' . $link ; } $s .= $this->makeLink( $link, $text ); } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) { # we just throw in a "New page" text to tell the user that he's in edit mode, # and to avoid messing with the separator that is prepended to the next item - $s .= "<strong>" . wfMsg("newpage") . "</strong>"; + $s .= '<strong>' . wfMsg('newpage') . '</strong>'; } } - if( $tns%2 && $action!="edit" && !$wpPreview) { - $s.="<br />".$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("postcomment"),"action=edit§ion=new"); + if( $tns%2 && $action!='edit' && !$wpPreview) { + $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit§ion=new'); } /* @@ -972,7 +1038,7 @@ class Skin { unwatched. Therefore we do not show the "Watch this page" link in edit mode */ if ( 0 != $wgUser->getID() && $articleExists) { - if($action!="edit" && $action != "submit" ) + if($action!='edit' && $action != 'submit' ) { $s .= $sep . $this->watchThisPage(); } @@ -984,7 +1050,7 @@ class Skin { $sep . $this->protectThisPage(); } $s .= $sep . $this->talkLink(); - if ($articleExists && $action !="history") { + if ($articleExists && $action !='history') { $s .= $sep . $this->historyLink(); } $s.=$sep . $this->whatLinksHere(); @@ -1013,15 +1079,15 @@ class Skin { } if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) { - $s .= $this->specialLink( "upload" ) . $sep; + $s .= $this->specialLink( 'upload' ) . $sep; } - $s .= $this->specialLink( "specialpages" ) + $s .= $this->specialLink( 'specialpages' ) . $sep . $this->bugReportsLink(); global $wgSiteSupportPage; if( $wgSiteSupportPage ) { $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) . - "\" class=\"internal\">" . wfMsg( "sitesupport" ) . "</a>"; + '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>'; } $s .= "\n<br /></div>\n"; @@ -1032,30 +1098,31 @@ class Skin { function specialPagesList() { global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript; + require_once('SpecialPage.php'); $a = array(); $pages = SpecialPage::getPages(); - foreach ( $pages[""] as $name => $page ) { + foreach ( $pages[''] as $name => $page ) { $a[$name] = $page->getDescription(); } if ( $wgUser->isSysop() ) { - foreach ( $pages["sysop"] as $name => $page ) { + foreach ( $pages['sysop'] as $name => $page ) { $a[$name] = $page->getDescription(); } } if ( $wgUser->isDeveloper() ) { - foreach ( $pages["developer"] as $name => $page ) { + foreach ( $pages['developer'] as $name => $page ) { $a[$name] = $page->getDescription() ; } } - $go = wfMsg( "go" ); - $sp = wfMsg( "specialpages" ); - $spp = $wgLang->specialPage( "Specialpages" ); + $go = wfMsg( 'go' ); + $sp = wfMsg( 'specialpages' ); + $spp = $wgLang->specialPage( 'Specialpages' ); - $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " . - "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n"; + $s = '<form id="specialpages" method="get" class="inline" ' . + 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n"; $s .= "<select name=\"wpDropdown\">\n"; $s .= "<option value=\"{$spp}\">{$sp}</option>\n"; @@ -1071,30 +1138,30 @@ class Skin { function mainPageLink() { - $mp = wfMsg( "mainpage" ); + $mp = wfMsg( 'mainpage' ); $s = $this->makeKnownLink( $mp, $mp ); return $s; } function copyrightLink() { - $s = $this->makeKnownLink( wfMsg( "copyrightpage" ), - wfMsg( "copyrightpagename" ) ); + $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ), + wfMsg( 'copyrightpagename' ) ); return $s; } function aboutLink() { - $s = $this->makeKnownLink( wfMsg( "aboutpage" ), - wfMsg( "aboutwikipedia" ) ); + $s = $this->makeKnownLink( wfMsg( 'aboutpage' ), + wfMsg( 'aboutwikipedia' ) ); return $s; } function disclaimerLink() { - $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ), - wfMsg( "disclaimers" ) ); + $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ), + wfMsg( 'disclaimers' ) ); return $s; } @@ -1107,16 +1174,16 @@ class Skin { $redirect = $wgRequest->getVal( 'redirect' ); if ( ! $wgOut->isArticleRelated() ) { - $s = wfMsg( "protectedpage" ); + $s = wfMsg( 'protectedpage' ); } else { $n = $wgTitle->getPrefixedText(); if ( $wgTitle->userCanEdit() ) { - $t = wfMsg( "editthispage" ); + $t = wfMsg( 'editthispage' ); } else { #$t = wfMsg( "protectedpage" ); - $t = wfMsg( "viewsource" ); + $t = wfMsg( 'viewsource' ); } - $oid = $red = ""; + $oid = $red = ''; if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; } if ( $oldid && ! isset( $diff ) ) { @@ -1134,11 +1201,11 @@ class Skin { $diff = $wgRequest->getVal( 'diff' ); if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) { $n = $wgTitle->getPrefixedText(); - $t = wfMsg( "deletethispage" ); + $t = wfMsg( 'deletethispage' ); - $s = $this->makeKnownLink( $n, $t, "action=delete" ); + $s = $this->makeKnownLink( $n, $t, 'action=delete' ); } else { - $s = ""; + $s = ''; } return $s; } @@ -1152,15 +1219,15 @@ class Skin { $n = $wgTitle->getPrefixedText(); if ( $wgTitle->isProtected() ) { - $t = wfMsg( "unprotectthispage" ); - $q = "action=unprotect"; + $t = wfMsg( 'unprotectthispage' ); + $q = 'action=unprotect'; } else { - $t = wfMsg( "protectthispage" ); - $q = "action=protect"; + $t = wfMsg( 'protectthispage' ); + $q = 'action=protect'; } $s = $this->makeKnownLink( $n, $t, $q ); } else { - $s = ""; + $s = ''; } return $s; } @@ -1173,15 +1240,15 @@ class Skin { $n = $wgTitle->getPrefixedText(); if ( $wgTitle->userIsWatching() ) { - $t = wfMsg( "unwatchthispage" ); - $q = "action=unwatch"; + $t = wfMsg( 'unwatchthispage' ); + $q = 'action=unwatch'; } else { - $t = wfMsg( "watchthispage" ); - $q = "action=watch"; + $t = wfMsg( 'watchthispage' ); + $q = 'action=watch'; } $s = $this->makeKnownLink( $n, $t, $q ); } else { - $s = wfMsg( "notanarticle" ); + $s = wfMsg( 'notanarticle' ); } return $s; } @@ -1191,8 +1258,8 @@ class Skin { global $wgTitle, $wgLang; if ( $wgTitle->userCanEdit() ) { - $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ), - wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() ); + $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ), + wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() ); } // no message if page is protected - would be redundant return $s; } @@ -1202,7 +1269,7 @@ class Skin { global $wgTitle; $s = $this->makeKnownLink( $wgTitle->getPrefixedText(), - wfMsg( "history" ), "action=history" ); + wfMsg( 'history' ), 'action=history' ); return $s; } @@ -1210,8 +1277,8 @@ class Skin { { global $wgTitle, $wgLang; - $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ), - wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() ); + $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ), + wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() ); return $s; } @@ -1219,8 +1286,8 @@ class Skin { { global $wgTitle, $wgLang; - $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ), - wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() ); + $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ), + wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() ); return $s; } @@ -1228,8 +1295,8 @@ class Skin { { global $wgTitle, $wgLang; - $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ), - wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() ); + $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ), + wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() ); return $s; } @@ -1238,11 +1305,11 @@ class Skin { global $wgOut, $wgTitle, $wgLang; if ( ! $wgOut->isArticleRelated() ) { - $s = "(" . wfMsg( "notanarticle" ) . ")"; + $s = '(' . wfMsg( 'notanarticle' ) . ')'; } else { $s = $this->makeKnownLink( $wgLang->specialPage( - "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ), - "target=" . $wgTitle->getPrefixedURL() ); + 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ), + 'target=' . $wgTitle->getPrefixedURL() ); } return $s; } @@ -1253,56 +1320,56 @@ class Skin { $a = $wgOut->getLanguageLinks(); if ( 0 == count( $a ) ) { - if ( !$wgUseNewInterlanguage ) return ""; + if ( !$wgUseNewInterlanguage ) return ''; $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ; - if ( $ns != 0 AND $ns != 1 ) return "" ; - $pn = "Intl" ; - $x = "mode=addlink&xt=".$wgTitle->getDBkey() ; + if ( $ns != 0 AND $ns != 1 ) return '' ; + $pn = 'Intl' ; + $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ; return $this->makeKnownLink( $wgLang->specialPage( $pn ), - wfMsg( "intl" ) , $x ); + wfMsg( 'intl' ) , $x ); } if ( !$wgUseNewInterlanguage ) { - $s = wfMsg( "otherlanguages" ) . ": "; + $s = wfMsg( 'otherlanguages' ) . ': '; } else { global $wgLanguageCode ; - $x = "mode=zoom&xt=".$wgTitle->getDBkey() ; - $x .= "&xl=".$wgLanguageCode ; - $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ), - wfMsg( "otherlanguages" ) , $x ) . ": " ; + $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ; + $x .= '&xl='.$wgLanguageCode ; + $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ), + wfMsg( 'otherlanguages' ) , $x ) . ': ' ; } - $s = wfMsg( "otherlanguages" ) . ": "; + $s = wfMsg( 'otherlanguages' ) . ': '; $first = true; - if($wgLang->isRTL()) $s .= "<span dir='LTR'>"; + if($wgLang->isRTL()) $s .= '<span dir="LTR">'; foreach( $a as $l ) { - if ( ! $first ) { $s .= " | "; } + if ( ! $first ) { $s .= ' | '; } $first = false; $nt = Title::newFromText( $l ); $url = $nt->getFullURL(); $text = $wgLang->getLanguageName( $nt->getInterwiki() ); - if ( "" == $text ) { $text = $l; } + if ( '' == $text ) { $text = $l; } $style = $this->getExternalLinkAttributes( $l, $text ); $s .= "<a href=\"{$url}\"{$style}>{$text}</a>"; } - if($wgLang->isRTL()) $s .= "</span>"; + if($wgLang->isRTL()) $s .= '</span>'; return $s; } function bugReportsLink() { - $s = $this->makeKnownLink( wfMsg( "bugreportspage" ), - wfMsg( "bugreports" ) ); + $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ), + wfMsg( 'bugreports' ) ); return $s; } function dateLink() { global $wgLinkCache; - $t1 = Title::newFromText( gmdate( "F j" ) ); - $t2 = Title::newFromText( gmdate( "Y" ) ); + $t1 = Title::newFromText( gmdate( 'F j' ) ); + $t2 = Title::newFromText( gmdate( 'Y' ) ); $wgLinkCache->suspend(); $id = $t1->getArticleID(); @@ -1313,7 +1380,7 @@ class Skin { } else { $s = $this->makeKnownLink( $t1->getText() ); } - $s .= ", "; + $s .= ', '; $wgLinkCache->suspend(); $id = $t2->getArticleID(); @@ -1332,27 +1399,27 @@ class Skin { global $wgLang, $wgTitle, $wgLinkCache; $tns = $wgTitle->getNamespace(); - if ( -1 == $tns ) { return ""; } + if ( -1 == $tns ) { return ''; } $pn = $wgTitle->getText(); - $tp = wfMsg( "talkpage" ); + $tp = wfMsg( 'talkpage' ); if ( Namespace::isTalk( $tns ) ) { $lns = Namespace::getSubject( $tns ); switch($tns) { case 1: - $text = wfMsg("articlepage"); + $text = wfMsg('articlepage'); break; case 3: - $text = wfMsg("userpage"); + $text = wfMsg('userpage'); break; case 5: - $text = wfMsg("wikipediapage"); + $text = wfMsg('wikipediapage'); break; case 7: - $text = wfMsg("imagepage"); + $text = wfMsg('imagepage'); break; default: - $text= wfMsg("articlepage"); + $text= wfMsg('articlepage'); } } else { @@ -1360,8 +1427,8 @@ class Skin { $text=$tp; } $n = $wgLang->getNsText( $lns ); - if ( "" == $n ) { $link = $pn; } - else { $link = "{$n}:{$pn}"; } + if ( '' == $n ) { $link = $pn; } + else { $link = $n.':'.$pn; } $wgLinkCache->suspend(); $s = $this->makeLink( $link, $text ); @@ -1375,7 +1442,7 @@ class Skin { global $wgLang, $wgTitle, $wgLinkCache; $tns = $wgTitle->getNamespace(); - if ( -1 == $tns ) { return ""; } + if ( -1 == $tns ) { return ''; } $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns ); @@ -1384,10 +1451,10 @@ class Skin { $n = $wgLang->getNsText( $lns ); $pn = $wgTitle->getText(); - $link = "{$n}:{$pn}"; + $link = $n.':'.$pn; $wgLinkCache->suspend(); - $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit§ion=new"); + $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit§ion=new'); $wgLinkCache->resume(); return $s; @@ -1404,63 +1471,63 @@ class Skin { # Note: This function MUST call getArticleID() on the link, # otherwise the cache won't get updated properly. See LINKCACHE.DOC. # - function makeLink( $title, $text = "", $query = "", $trail = "" ) { - wfProfileIn( "Skin::makeLink" ); + function makeLink( $title, $text = '', $query = '', $trail = '' ) { + wfProfileIn( 'Skin::makeLink' ); $nt = Title::newFromText( $title ); if ($nt) { $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail ); } else { - wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" ); + wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" ); $result = $text == "" ? $title : $text; } - wfProfileOut( "Skin::makeLink" ); + wfProfileOut( 'Skin::makeLink' ); return $result; } - function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') { + function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') { $nt = Title::newFromText( $title ); if ($nt) { return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops ); } else { - wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" ); - return $text == "" ? $title : $text; + wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" ); + return $text == '' ? $title : $text; } } - function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) { + function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) { $nt = Title::newFromText( $title ); if ($nt) { return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail ); } else { - wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" ); - return $text == "" ? $title : $text; + wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" ); + return $text == '' ? $title : $text; } } - function makeStubLink( $title, $text = "", $query = "", $trail = "" ) { + function makeStubLink( $title, $text = '', $query = '', $trail = '' ) { $nt = Title::newFromText( $title ); if ($nt) { return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail ); } else { - wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" ); - return $text == "" ? $title : $text; + wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" ); + return $text == '' ? $title : $text; } } # Pass a title object, not a title string - function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" ) + function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) { global $wgOut, $wgUser; if ( $nt->isExternal() ) { $u = $nt->getFullURL(); $link = $nt->getPrefixedURL(); - if ( "" == $text ) { $text = $nt->getPrefixedText(); } - $style = $this->getExternalLinkAttributes( $link, $text ); + if ( '' == $text ) { $text = $nt->getPrefixedText(); } + $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' ); - $inside = ""; - if ( "" != $trail ) { - if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) { + $inside = ''; + if ( '' != $trail ) { + if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) { $inside = $m[1]; $trail = $m[2]; } @@ -1476,7 +1543,7 @@ class Skin { if ( 0 == $aid ) { $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix ); } else { - $threshold = $wgUser->getOption("stubthreshold") ; + $threshold = $wgUser->getOption('stubthreshold') ; if ( $threshold > 0 ) { $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ; @@ -1504,33 +1571,41 @@ class Skin { } # Pass a title object, not a title string - function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '') + function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '') { - global $wgOut, $wgTitle; + global $wgOut, $wgTitle, $wgInputEncoding; - $fname = "Skin::makeKnownLinkObj"; + $fname = 'Skin::makeKnownLinkObj'; wfProfileIn( $fname ); + if ( !is_object( $nt ) ) { + return $text; + } $link = $nt->getPrefixedURL(); - if ( "" == $link ) { - $u = ""; - if ( "" == $text ) { + if ( '' == $link ) { + $u = ''; + if ( '' == $text ) { $text = htmlspecialchars( $nt->getFragment() ); } } else { $u = $nt->escapeLocalURL( $query ); } - if ( "" != $nt->getFragment() ) { - $u .= "#" . htmlspecialchars( $nt->getFragment() ); + if ( '' != $nt->getFragment() ) { + $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) ); + $replacearray = array( + '%3A' => ':', + '%' => '.' + ); + $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor); } - if ( "" == $text ) { + if ( '' == $text ) { $text = htmlspecialchars( $nt->getPrefixedText() ); } $style = $this->getInternalLinkAttributesObj( $nt, $text ); - $inside = ""; - if ( "" != $trail ) { + $inside = ''; + if ( '' != $trail ) { if ( preg_match( $this->linktrail, $trail, $m ) ) { $inside = $m[1]; $trail = $m[2]; @@ -1542,33 +1617,33 @@ class Skin { } # Pass a title object, not a title string - function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" ) + function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) { global $wgOut, $wgUser; - $fname = "Skin::makeBrokenLinkObj"; + $fname = 'Skin::makeBrokenLinkObj'; wfProfileIn( $fname ); - if ( "" == $query ) { - $q = "action=edit"; + if ( '' == $query ) { + $q = 'action=edit'; } else { - $q = "action=edit&{$query}"; + $q = 'action=edit&'.$query; } $u = $nt->escapeLocalURL( $q ); - if ( "" == $text ) { + if ( '' == $text ) { $text = htmlspecialchars( $nt->getPrefixedText() ); } $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" ); - $inside = ""; - if ( "" != $trail ) { + $inside = ''; + if ( '' != $trail ) { if ( preg_match( $this->linktrail, $trail, $m ) ) { $inside = $m[1]; $trail = $m[2]; } } - if ( $wgUser->getOption( "highlightbroken" ) ) { + if ( $wgUser->getOption( 'highlightbroken' ) ) { $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}"; } else { $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}"; @@ -1579,7 +1654,7 @@ class Skin { } # Pass a title object, not a title string - function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" ) + function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) { global $wgOut, $wgUser; @@ -1587,19 +1662,19 @@ class Skin { $u = $nt->escapeLocalURL( $query ); - if ( "" == $text ) { + if ( '' == $text ) { $text = htmlspecialchars( $nt->getPrefixedText() ); } - $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" ); + $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' ); - $inside = ""; - if ( "" != $trail ) { + $inside = ''; + if ( '' != $trail ) { if ( preg_match( $this->linktrail, $trail, $m ) ) { $inside = $m[1]; $trail = $m[2]; } } - if ( $wgUser->getOption( "highlightbroken" ) ) { + if ( $wgUser->getOption( 'highlightbroken' ) ) { $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}"; } else { $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}"; @@ -1607,14 +1682,14 @@ class Skin { return $s; } - function makeSelfLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" ) + function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) { $u = $nt->escapeLocalURL( $query ); - if ( "" == $text ) { + if ( '' == $text ) { $text = htmlspecialchars( $nt->getPrefixedText() ); } - $inside = ""; - if ( "" != $trail ) { + $inside = ''; + if ( '' != $trail ) { if ( preg_match( $this->linktrail, $trail, $m ) ) { $inside = $m[1]; $trail = $m[2]; @@ -1651,6 +1726,12 @@ class Skin { $this->checkTitle($title, $name); return $title->getLocalURL( $urlaction ); } + # this can be passed the NS number as defined in Language.php + /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) { + $title = Title::makeTitle( $namespace, $name ); + $this->checkTitle($title, $name); + return $title->getLocalURL( $urlaction ); + } /* these return an array with the 'href' and boolean 'exists' */ /*static*/ function makeUrlDetails ( $name, $urlaction='' ) { @@ -1693,40 +1774,40 @@ class Skin { if(!is_object($title)) { $title = Title::newFromText( $name ); if(!is_object($title)) { - $title = Title::newFromText( '<error: link target missing>' ); + $title = Title::newFromText( '--error: link target missing--' ); } } } function fnamePart( $url ) { - $basename = strrchr( $url, "/" ); + $basename = strrchr( $url, '/' ); if ( false === $basename ) { $basename = $url; } else { $basename = substr( $basename, 1 ); } return wfEscapeHTML( $basename ); } - function makeImage( $url, $alt = "" ) + function makeImage( $url, $alt = '' ) { global $wgOut; - if ( "" == $alt ) { $alt = $this->fnamePart( $url ); } - $s = "<img src=\"{$url}\" alt=\"{$alt}\" />"; + if ( '' == $alt ) { $alt = $this->fnamePart( $url ); } + $s = '<img src="'.$url.'" alt="'.$alt.'" />'; return $s; } - function makeImageLink( $name, $url, $alt = "" ) { + function makeImageLink( $name, $url, $alt = '' ) { $nt = Title::makeTitle( Namespace::getImage(), $name ); return $this->makeImageLinkObj( $nt, $alt ); } - function makeImageLinkObj( $nt, $alt = "" ) { + function makeImageLinkObj( $nt, $alt = '' ) { global $wgLang, $wgUseImageResize; $img = Image::newFromTitle( $nt ); $url = $img->getURL(); - $align = ""; - $prefix = $postfix = ""; + $align = ''; + $prefix = $postfix = ''; if ( $wgUseImageResize ) { # Check if the alt text is of the form "options|alt text" @@ -1739,7 +1820,7 @@ class Skin { # * center center the image # * framed Keep original image size, no magnify-button. - $part = explode( "|", $alt); + $part = explode( '|', $alt); $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL ); $mwLeft =& MagicWord::get( MAG_IMG_LEFT ); @@ -1757,19 +1838,19 @@ class Skin { $thumb=true; } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) { # remember to set an alignment, don't render immediately - $align = "right"; + $align = 'right'; } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) { # remember to set an alignment, don't render immediately - $align = "left"; + $align = 'left'; } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) { # remember to set an alignment, don't render immediately - $align = "center"; + $align = 'center'; } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) { # remember to set an alignment, don't render immediately - $align = "none"; + $align = 'none'; } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) { # $match is the image width in pixels - if ( preg_match( "/^([0-9]*)x([0-9]*)$/", $match, $m ) ) { + if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) { $width = intval( $m[1] ); $height = intval( $m[2] ); } else { @@ -1779,11 +1860,11 @@ class Skin { $framed=true; } } - if ( "center" == $align ) + if ( 'center' == $align ) { $prefix = '<span style="text-align: center">'; $postfix = '</span>'; - $align = "none"; + $align = 'none'; } if ( $thumb || $framed ) { @@ -1795,8 +1876,8 @@ class Skin { # # If thumbnail width has not been provided, it is set # here to 180 pixels - if ( $align == "" ) { - $align = $wgLang->isRTL() ? "left" : "right"; + if ( $align == '' ) { + $align = $wgLang->isRTL() ? 'left' : 'right'; } if ( ! isset($width) ) { $width = 180; @@ -1811,7 +1892,7 @@ class Skin { if ( ( ! $height === false ) && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) { print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n"; - print "rescaling by factor ". $height / $img->getHeight() . "<br>\n"; + print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n"; $width = $img->getWidth() * $height / $img->getHeight(); } $url = $img->createThumb( $width ); @@ -1824,28 +1905,28 @@ class Skin { $alt = htmlspecialchars( $alt ); $u = $nt->escapeLocalURL(); - if ( $url == "" ) + if ( $url == '' ) { - $s = str_replace( "$1", $img->getName(), wfMsg("missingimage") ); + $s = str_replace( "$1", $img->getName(), wfMsg('missingimage') ); $s .= "<br>{$alt}<br>{$url}<br>\n"; } else { - $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" . - "<img src=\"{$url}\" alt=\"{$alt}\" /></a>"; + $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' . + '<img src="'.$url.'" alt="'.$alt.'" /></a>'; } - if ( "" != $align ) { - $s = "<div class=\"float{$align}\"><span>{$s}</span>\n</div>"; + if ( '' != $align ) { + $s = "<div class=\"float{$align}\"><span>{$s}</span></div>"; } - return $prefix.$s.$postfix; + return str_replace("\n", ' ',$prefix.$s.$postfix); } - function makeThumbLinkObj( $img, $label = "", $align = "right", $boxwidth = 180, $boxheight=false, $framed=false ) { + function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false ) { global $wgStylePath, $wgLang; # $image = Title::makeTitle( Namespace::getImage(), $name ); $url = $img->getURL(); #$label = htmlspecialchars( $label ); - $alt = preg_replace( "/<[^>]*>/", "", $label); + $alt = preg_replace( '/<[^>]*>/', '', $label); $alt = htmlspecialchars( $alt ); if ( $img->exists() ) @@ -1876,13 +1957,13 @@ class Skin { $u = $img->getEscapeLocalURL(); - $more = htmlspecialchars( wfMsg( "thumbnail-more" ) ); - $magnifyalign = $wgLang->isRTL() ? "left" : "right"; - $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : ""; + $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) ); + $magnifyalign = $wgLang->isRTL() ? 'left' : 'right'; + $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : ''; $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">"; - if ( $thumbUrl == "" ) { - $s .= str_replace( "$1", $img->getName(), wfMsg("missingimage") ); + if ( $thumbUrl == '' ) { + $s .= str_replace( "$1", $img->getName(), wfMsg('missingimage') ); $zoomicon = ''; } else { $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'. @@ -1897,8 +1978,8 @@ class Skin { 'width="15" height="11" alt="'.$more.'" /></a></div>'; } } - $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div>\n</div>"; - return $s; + $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>"; + return str_replace("\n", ' ', $s); } function makeMediaLink( $name, $url, $alt = "" ) { @@ -1908,14 +1989,20 @@ class Skin { function makeMediaLinkObj( $nt, $alt = "" ) { - $name = $nt->getDBKey(); - $url = Image::wfImageUrl( $name ); - if ( empty( $alt ) ) { - $alt = preg_replace( '/\.(.+?)^/', '', $name ); + if ( ! isset( $nt ) ) + { + ### HOTFIX. Instead of breaking, return empry string. + $s = $alt; + } else { + $name = $nt->getDBKey(); + $url = Image::wfImageUrl( $name ); + if ( empty( $alt ) ) { + $alt = preg_replace( '/\.(.+?)^/', '', $name ); + } + + $u = htmlspecialchars( $url ); + $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>"; } - - $u = htmlspecialchars( $url ); - $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>"; return $s; } @@ -1923,7 +2010,7 @@ class Skin { { global $wgLang; - if ( "" == $key ) { $key = strtolower( $name ); } + if ( '' == $key ) { $key = strtolower( $name ); } $pn = $wgLang->ucfirst( $name ); return $this->makeKnownLink( $wgLang->specialPage( $pn ), wfMsg( $key ) ); @@ -1935,7 +2022,7 @@ class Skin { if( $escape ) { $text = htmlspecialchars( $text ); } - return "<a href=\"$url\"$style>$text</a>"; + return '<a href="'.$url.'"'.$style.'>'.$text.'</a>'; } # Called by history lists and recent changes @@ -1947,15 +2034,15 @@ class Skin { $this->rc_cache = array() ; $this->rcMoveIndex = 0; $this->rcCacheIndex = 0 ; - $this->lastdate = ""; + $this->lastdate = ''; $this->rclistOpen = false; - return ""; + return ''; } function beginImageHistoryList() { - $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" . - "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>"; + $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" . + "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">'; return $s; } @@ -1977,57 +2064,58 @@ class Skin { # Get rc_xxxx variables extract( $rcObj->mAttribs ) ; - $curIdEq = "curid=$rc_cur_id"; + $curIdEq = 'curid='.$rc_cur_id; # Spacer image - $r = "" ; + $r = '' ; - $r .= "<img src='{$wgStylePath}/images/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ; + $r .= '<img src="'.$wgStylePath.'/images/Arr_.png" width="12" height="12" border="0" />' ; + $r .= '<tt>' ; - if ( $rc_type == RC_MOVE ) { - $r .= " "; + if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + $r .= ' '; } else { # M & N (minor & new) - $M = wfMsg( "minoreditletter" ); - $N = wfMsg( "newpageletter" ); + $M = wfMsg( 'minoreditletter' ); + $N = wfMsg( 'newpageletter' ); if ( $rc_type == RC_NEW ) { $r .= $N ; } else { - $r .= " " ; + $r .= ' ' ; } if ( $rc_minor ) { $r .= $M ; } else { - $r .= " " ; + $r .= ' ' ; } } # Timestamp - $r .= " ".$rcObj->timestamp." " ; - $r .= "</tt>" ; + $r .= ' '.$rcObj->timestamp.' ' ; + $r .= '</tt>' ; # Article link $link = $rcObj->link ; - if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ; + if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ; $r .= $link ; - # Cur - $r .= " (" ; - $r .= $rcObj->curlink ; - $r .= "; " ; + # Diff + $r .= ' (' ; + $r .= $rcObj->difflink ; + $r .= '; ' ; # Hist - $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" ); + $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' ); # User/talk - $r .= ") . . ".$rcObj->userlink ; + $r .= ') . . '.$rcObj->userlink ; $r .= $rcObj->usertalklink ; # Comment - if ( $rc_comment != "" && $rc_type != RC_MOVE ) { + if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) { $rc_comment=$this->formatComment($rc_comment); - $r .= $wgLang->emphasize( " (".$rc_comment.")" ); + $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ); } $r .= "<br />\n" ; @@ -2039,9 +2127,9 @@ class Skin { { global $wgStylePath, $wgLang ; - $r = "" ; - $M = wfMsg( "minoreditletter" ); - $N = wfMsg( "newpageletter" ); + $r = '' ; + $M = wfMsg( 'minoreditletter' ); + $N = wfMsg( 'newpageletter' ); # Collate list of users $isnew = false ; @@ -2063,86 +2151,86 @@ class Skin { if ( $count > 1 ) $text .= " ({$count}×)" ; array_push ( $users , $text ) ; } - $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ; + $users = ' <font size="-1">['.implode('; ',$users).']</font>' ; # Arrow - $rci = "RCI{$this->rcCacheIndex}" ; - $rcl = "RCL{$this->rcCacheIndex}" ; - $rcm = "RCM{$this->rcCacheIndex}" ; - $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ; - $arrowdir = $wgLang->isRTL() ? "l" : "r"; - $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ; - $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_d.png' width='12' height='12' /></a></span>" ; + $rci = 'RCI'.$this->rcCacheIndex ; + $rcl = 'RCL'.$this->rcCacheIndex ; + $rcm = 'RCM'.$this->rcCacheIndex ; + $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ; + $arrowdir = $wgLang->isRTL() ? 'l' : 'r'; + $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ; + $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/images/Arr_d.png" width="12" height="12" /></a></span>' ; $r .= $tl ; # Main line # M/N - $r .= "<tt>" ; + $r .= '<tt>' ; if ( $isnew ) $r .= $N ; - else $r .= " " ; - $r .= " " ; # Minor + else $r .= ' ' ; + $r .= ' ' ; # Minor # Timestamp - $r .= " ".$block[0]->timestamp." " ; - $r .= "</tt>" ; + $r .= ' '.$block[0]->timestamp.' ' ; + $r .= '</tt>' ; # Article link $link = $block[0]->link ; - if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ; + if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ; $r .= $link ; - $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id']; + $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id']; if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) { # Changes - $r .= " (".count($block)." " ; - if ( $isnew ) $r .= wfMsg("changes"); - else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") , - "{$curIdEq}&diff=0&oldid=".$oldid ) ; - $r .= "; " ; + $r .= ' ('.count($block).' ' ; + if ( $isnew ) $r .= wfMsg('changes'); + else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') , + $curIdEq.'&diff=0&oldid='.$oldid ) ; + $r .= '; ' ; # History - $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" ); - $r .= ")" ; + $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' ); + $r .= ')' ; } $r .= $users ; $r .= "<br />\n" ; # Sub-entries - $r .= "<div id='{$rci}' style='display:none'>" ; + $r .= '<div id="'.$rci.'" style="display:none">' ; foreach ( $block AS $rcObj ) { # Get rc_xxxx variables extract( $rcObj->mAttribs ); - $r .= "<img src='{$wgStylePath}/images/Arr_.png' width=12 height=12 />"; - $r .= "<tt> " ; + $r .= '<img src="'.$wgStylePath.'/images/Arr_.png" width="12" height="12" />'; + $r .= '<tt> ' ; if ( $rc_new ) $r .= $N ; - else $r .= " " ; + else $r .= ' ' ; if ( $rc_minor ) $r .= $M ; - else $r .= " " ; - $r .= "</tt>" ; + else $r .= ' ' ; + $r .= '</tt>' ; - $o = "" ; + $o = '' ; if ( $rc_last_oldid != 0 ) { - $o = "oldid=".$rc_last_oldid ; + $o = 'oldid='.$rc_last_oldid ; } if ( $rc_type == RC_LOG ) { $link = $rcObj->timestamp ; } else { $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ; } - $link = "<tt>{$link}</tt>" ; + $link = '<tt>'.$link.'</tt>' ; $r .= $link ; - $r .= " (" ; + $r .= ' (' ; $r .= $rcObj->curlink ; - $r .= "; " ; + $r .= '; ' ; $r .= $rcObj->lastlink ; - $r .= ") . . ".$rcObj->userlink ; + $r .= ') . . '.$rcObj->userlink ; $r .= $rcObj->usertalklink ; - if ( $rc_comment != "" ) { + if ( $rc_comment != '' ) { $rc_comment=$this->formatComment($rc_comment); - $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ; + $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ; } $r .= "<br />\n" ; } @@ -2157,8 +2245,8 @@ class Skin { function recentChangesBlock () { global $wgStylePath ; - if ( count ( $this->rc_cache ) == 0 ) return "" ; - $blockOut = ""; + if ( count ( $this->rc_cache ) == 0 ) return '' ; + $blockOut = ''; foreach ( $this->rc_cache AS $secureName => $block ) { if ( count ( $block ) < 2 ) { $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ; @@ -2167,7 +2255,7 @@ class Skin { } } - return "<div>{$blockOut}</div>" ; + return '<div>'.$blockOut.'</div>' ; } # Called in a loop over all displayed RC entries @@ -2175,7 +2263,7 @@ class Skin { function recentChangesLine( &$rc, $watched = false ) { global $wgUser ; - $usenew = $wgUser->getOption( "usenewrc" ); + $usenew = $wgUser->getOption( 'usenewrc' ); if ( $usenew ) $line = $this->recentChangesLineNew ( $rc, $watched ) ; else @@ -2189,70 +2277,73 @@ class Skin { # Extract DB fields into local scope extract( $rc->mAttribs ); - $curIdEq = "curid=" . $rc_cur_id; + $curIdEq = 'curid=' . $rc_cur_id; # Make date header if necessary $date = $wgLang->date( $rc_timestamp, true); - $s = ""; + $s = ''; if ( $date != $this->lastdate ) { - if ( "" != $this->lastdate ) { $s .= "</ul>\n"; } + if ( '' != $this->lastdate ) { $s .= "</ul>\n"; } $s .= "<h4>{$date}</h4>\n<ul class='special'>"; $this->lastdate = $date; $this->rclistOpen = true; } - $s .= "<li> "; + $s .= '<li> '; - if ( $rc_type == RC_MOVE ) { + if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { # Diff - $s .= "(" . wfMsg( "diff" ) . ") ("; + $s .= '(' . wfMsg( 'diff' ) . ') ('; # Hist - $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) . - ") . . "; + $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) . + ') . . '; # "[[x]] moved to [[y]]" - - $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ), - $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) ); - + if ( $rc_type == RC_MOVE ) { + $msg = '1movedto2'; + } else { + $msg = '1movedto2_redir'; + } + $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), + $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); } else { # Diff link if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) { - $diffLink = wfMsg( "diff" ); + $diffLink = wfMsg( 'diff' ); } else { - $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ), - "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"'); + $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ), + $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid ,'' ,'' , ' tabindex="'.$rc->counter.'"'); } - $s .= "($diffLink) ("; + $s .= '('.$diffLink.') ('; # History link - $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" ); - $s .= ") . . "; + $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' ); + $s .= ') . . '; # M and N (minor and new) - $M = wfMsg( "minoreditletter" ); - $N = wfMsg( "newpageletter" ); - if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; } - if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; } + $M = wfMsg( 'minoreditletter' ); + $N = wfMsg( 'newpageletter' ); + if ( $rc_minor ) { $s .= ' <strong>'.$M.'</strong>'; } + if ( $rc_type == RC_NEW ) { $s .= '<strong>'.$N.'</strong>'; } # Article link - $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" ); + $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' ); if ( $watched ) { - $articleLink = "<strong>{$articleLink}</strong>"; + $articleLink = '<strong>'.$articleLink.'</strong>'; } - $s .= " $articleLink"; + $s .= ' '.$articleLink; } # Timestamp - $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . "; + $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . '; # User link (or contributions for unregistered users) if ( 0 == $rc_user ) { - $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ), - $rc_user_text, "target=" . $rc_user_text ); + $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ), + $rc_user_text, 'target=' . $rc_user_text ); } else { - $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text ); + $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text ); } $s .= $userLink; @@ -2260,28 +2351,28 @@ class Skin { $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name global $wgDisableAnonTalk; if( 0 == $rc_user && $wgDisableAnonTalk ) { - $userTalkLink = ""; + $userTalkLink = ''; } else { $utns=$wgLang->getNsText(NS_USER_TALK); - $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname ); + $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname ); } # Block link - $blockLink=""; + $blockLink=''; if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) { $blockLink = $this->makeKnownLink( $wgLang->specialPage( - "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" ); + 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text ); } if($blockLink) { - if($userTalkLink) $userTalkLink .= " | "; + if($userTalkLink) $userTalkLink .= ' | '; $userTalkLink .= $blockLink; } - if($userTalkLink) $s.=" ({$userTalkLink})"; + if($userTalkLink) $s.=' ('.$userTalkLink.')'; # Add comment - if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) { + if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) { $rc_comment=$this->formatComment($rc_comment); - $s .= $wgLang->emphasize(" (" . $rc_comment . ")"); + $s .= $wgLang->emphasize(' (' . $rc_comment . ')'); } $s .= "</li>\n"; @@ -2298,11 +2389,11 @@ class Skin { # Extract fields from DB into the function scope (rc_xxxx variables) extract( $rc->mAttribs ); - $curIdEq = "curid=" . $rc_cur_id; + $curIdEq = 'curid=' . $rc_cur_id; # If it's a new day, add the headline and flush the cache $date = $wgLang->date( $rc_timestamp, true); - $ret = "" ; + $ret = '' ; if ( $date != $this->lastdate ) { # Process current cache $ret = $this->recentChangesBlock () ; @@ -2312,12 +2403,16 @@ class Skin { } # Make article link - if ( $rc_type == RC_MOVE ) { - $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ); - $clink .= " " . wfMsg("movedto") . " "; - $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ); + if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + if ( $rc_type == RC_MOVE ) { + $msg = "1movedto2"; + } else { + $msg = "1movedto2_redir"; + } + $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), + $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); } else { - $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ; + $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ; } $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds ); @@ -2325,63 +2420,68 @@ class Skin { $rc->link = $clink ; $rc->timestamp = $time; - # Make "cur" link - if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) { - $curLink = wfMsg( "cur" ); - } else { - $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ), - "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' ); + # Make "cur" and "diff" links + if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + $curLink = wfMsg( 'cur' ); + $diffLink = wfMsg( 'diff' ); + } else { + $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid; + $aprops = ' tabindex="'.$baseRC->counter.'"'; + $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops ); + $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops ); } # Make "last" link $titleObj = $rc->getTitle(); - if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) { - $lastLink = wfMsg( "last" ); + if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + $lastLink = wfMsg( 'last' ); } else { - $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ), - "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ); + $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ), + $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid ); } # Make user link (or user contributions for unregistered users) if ( 0 == $rc_user ) { - $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ), - $rc_user_text, "target=" . $rc_user_text ); + $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ), + $rc_user_text, 'target=' . $rc_user_text ); } else { $userLink = $this->makeLink( $wgLang->getNsText( - Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text ); + Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text ); } $rc->userlink = $userLink ; $rc->lastlink = $lastLink ; $rc->curlink = $curLink ; + $rc->difflink = $diffLink; + # Make user talk link $utns=$wgLang->getNsText(NS_USER_TALK); $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name - $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname ); + $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname ); global $wgDisableAnonTalk; if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) { $blockLink = $this->makeKnownLink( $wgLang->specialPage( - "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" ); + 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text ); if( $wgDisableAnonTalk ) - $rc->usertalklink = " ({$blockLink})"; + $rc->usertalklink = ' ('.$blockLink.')'; else - $rc->usertalklink = " ({$userTalkLink} | {$blockLink})"; + $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')'; } else { if( $wgDisableAnonTalk && ($rc_user == 0) ) - $rc->usertalklink = ""; + $rc->usertalklink = ''; else - $rc->usertalklink = " ({$userTalkLink})"; + $rc->usertalklink = ' ('.$userTalkLink.')'; } # Put accumulated information into the cache, for later display # Page moves go on their own line $title = $rc->getTitle(); $secureName = $title->getPrefixedDBkey(); - if ( $rc_type == RC_MOVE ) { + if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { # Use an @ character to prevent collision with page names - $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc); + $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc); } else { if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ; array_push ( $this->rc_cache[$secureName] , $rc ) ; @@ -2410,33 +2510,34 @@ class Skin { # some nasty regex. # We look for all comments, match any text before and after the comment, # add a separator where needed and format the comment itself with CSS - while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) { + while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) { $pre=$match[1]; $auto=$match[2]; $post=$match[3]; - $sep="-"; - if($pre) { $auto="$sep ".$auto; } - if($post) { $auto.=" $sep"; } - $auto="<span class=\"autocomment\">".$auto."</span>"; + $sep='-'; + if($pre) { $auto = $sep.' '.$auto; } + if($post) { $auto .= ' '.$sep; } + $auto='<span class="autocomment">'.$auto.'</span>'; $comment=$pre.$auto.$post; } # format regular and media links - all other wiki formatting # is ignored - while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) { + while(preg_match('/\[\[(.*?)(\|(.*?))*\]\]/',$comment,$match)) { - $medians = $wgLang->getNsText(Namespace::getMedia()); - $func="makeLink"; - if(preg_match("/^".$medians."/i",$match[1])) { - $func="makeMediaLink"; + $medians = $wgLang->getNsText(Namespace::getMedia()).':'; + $func='makeLink'; + if(preg_match('/^'.$medians.'/i',$match[1])) { + $func='makeMediaLink'; } + # Handle link renaming [[foo|text]] will show link as "text" if(isset($match[3]) ) { $comment= - preg_replace("/\[\[(.*?)\]\]/", + preg_replace('/\[\[(.*?)\]\]/', $this->$func($match[1],$match[3]),$comment,1); } else { $comment= - preg_replace("/\[\[(.*?)\]\]/", + preg_replace('/\[\[(.*?)\]\]/', $this->$func($match[1],$match[1]),$comment,1); } } @@ -2450,18 +2551,18 @@ class Skin { global $wgUser, $wgLang, $wgTitle; $datetime = $wgLang->timeanddate( $timestamp, true ); - $del = wfMsg( "deleteimg" ); - $cur = wfMsg( "cur" ); + $del = wfMsg( 'deleteimg' ); + $cur = wfMsg( 'cur' ); if ( $iscur ) { $url = Image::wfImageUrl( $img ); $rlink = $cur; if ( $wgUser->isSysop() ) { - $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() . - "&action=delete" ); + $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() . + '&action=delete' ); $style = $this->getInternalLinkAttributes( $link, $del ); - $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>"; + $dlink = '<a href="'.$link.'"'.$style.'>'.$del.'</a>'; } else { $dlink = $del; } @@ -2469,15 +2570,15 @@ class Skin { $url = wfEscapeHTML( wfImageArchiveUrl( $img ) ); if( $wgUser->getID() != 0 ) { $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(), - wfMsg( "revertimg" ), "action=revert&oldimage=" . + wfMsg( 'revertimg' ), 'action=revert&oldimage=' . urlencode( $img ) ); $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(), - $del, "action=delete&oldimage=" . urlencode( $img ) ); + $del, 'action=delete&oldimage=' . urlencode( $img ) ); } else { # Having live active links for non-logged in users # means that bots and spiders crawling our site can # inadvertently change content. Baaaad idea. - $rlink = wfMsg( "revertimg" ); + $rlink = wfMsg( 'revertimg' ); $dlink = $del; } } @@ -2485,24 +2586,24 @@ class Skin { $userlink = $usertext; } else { $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) . - ":{$usertext}", $usertext ); + ':'.$usertext, $usertext ); } - $nbytes = wfMsg( "nbytes", $size ); + $nbytes = wfMsg( 'nbytes', $size ); $style = $this->getInternalLinkAttributes( $url, $datetime ); $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>" . " . . {$userlink} ({$nbytes})"; - if ( "" != $description && "*" != $description ) { + if ( '' != $description && '*' != $description ) { $sk=$wgUser->getSkin(); - $s .= $wgLang->emphasize(" (" . $sk->formatComment($description) . ")"); + $s .= $wgLang->emphasize(' (' . $sk->formatComment($description) . ')'); } $s .= "</li>\n"; return $s; } function tocIndent($level) { - return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 ); + return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 ); } function tocUnindent($level) { @@ -2511,11 +2612,11 @@ class Skin { # parameter level defines if we are on an indentation level function tocLine( $anchor, $tocline, $level ) { - $link = "<a href=\"#$anchor\">$tocline</a><br />"; + $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />'; if($level) { - return "$link\n"; + return $link."\n"; } else { - return "<div class='tocline'>$link</div>\n"; + return '<div class="tocline">'.$link."</div>\n"; } } @@ -2523,45 +2624,45 @@ class Skin { function tocTable($toc) { # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand # try min-width & co when somebody gets a chance - $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>"; + $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>'; return - "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n". - "<b>".wfMsg("toc")."</b>" . + '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n". + '<b>'.wfMsg('toc').'</b>' . $hideline . - "</td></tr><tr id='tocinside'><td>\n". + '</td></tr><tr id="tocinside"><td>'."\n". $toc."</td></tr></table>\n"; } # These two do not check for permissions: check $wgTitle->userCanEdit before calling them function editSectionScript( $section, $head ) { global $wgTitle, $wgRequest; - if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) { + if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) { return $head; } - $url = $wgTitle->escapeLocalURL( "action=edit§ion=$section" ); - return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>"; + $url = $wgTitle->escapeLocalURL( 'action=edit§ion='.$section ); + return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>'; } function editSectionLink( $section ) { global $wgRequest; global $wgTitle, $wgUser, $wgLang; - if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) { + if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) { # Section edit links would be out of sync on an old page. # But, if we're diffing to the current page, they'll be # correct. - return ""; + return ''; } - $editurl = "§ion={$section}"; - $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl); + $editurl = '§ion='.$section; + $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl); if( $wgLang->isRTL() ) { - $farside = "left"; - $nearside = "right"; + $farside = 'left'; + $nearside = 'right'; } else { - $farside = "right"; - $nearside = "left"; + $farside = 'right'; + $nearside = 'left'; } return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>"; @@ -2583,12 +2684,12 @@ class Skin { // can figure out a way to make them work in IE. However, we should make // sure these keys are not defined on the edit page. $toolarray=array( - array( "image"=>"button_bold.png", - "open"=>"\'\'\'", - "close"=>"\'\'\'", - "sample"=>wfMsg("bold_sample"), - "tip"=>wfMsg("bold_tip"), - "key"=>"B" + array( 'image'=>'button_bold.png', + 'open'=>"\'\'\'", + 'close'=>"\'\'\'", + 'sample'=>wfMsg('bold_sample'), + 'tip'=>wfMsg('bold_tip'), + 'key'=>'B' ), array( "image"=>"button_italic.png", "open"=>"\'\'", @@ -2666,16 +2767,16 @@ class Skin { $toolbar.="document.writeln(\"<div id='toolbar'>\");\n"; foreach($toolarray as $tool) { - $image=$wgStylePath."/images/".$tool["image"]; - $open=$tool["open"]; - $close=$tool["close"]; - $sample = addslashes( $tool["sample"] ); + $image=$wgStylePath.'/images/'.$tool['image']; + $open=$tool['open']; + $close=$tool['close']; + $sample = addslashes( $tool['sample'] ); // Note that we use the tip both for the ALT tag and the TITLE tag of the image. // Older browsers show a "speedtip" type message only for ALT. // Ideally these should be different, realistically they // probably don't need to be. - $tip = addslashes( $tool["tip"] ); + $tip = addslashes( $tool['tip'] ); #$key = $tool["key"]; @@ -2690,14 +2791,4 @@ class Skin { } } - -require_once( "SkinStandard.php" ); -require_once( "SkinNostalgia.php" ); -require_once( "SkinCologneBlue.php" ); - -if( $wgUsePHPTal ) { - require_once( "SkinPHPTal.php" ); -} - - ?> diff --git a/includes/SkinCologneBlue.php b/includes/SkinCologneBlue.php index 09336459db17..212e3939fddd 100644 --- a/includes/SkinCologneBlue.php +++ b/includes/SkinCologneBlue.php @@ -7,6 +7,9 @@ class SkinCologneBlue extends Skin { { return "cologneblue.css"; } + function getSkinName() { + return "cologneblue"; + } function doBeforeContent() { @@ -32,7 +35,9 @@ class SkinCologneBlue extends Skin { $s .= "</td><td align='right'>" ; $s .= "<font size='-1'><span id='langlinks'>" ; - $s .= str_replace ( "<br>" , "" , $this->otherLanguages() ) ; + $s .= str_replace ( "<br>" , "" , $this->otherLanguages() ); + $cat = $this->getCategoryLinks(); + if( $cat ) $s .= "<br />$cat\n"; $s .= "<br />" . $this->pageTitleLinks(); $s .= "</span></font>"; @@ -79,8 +84,7 @@ class SkinCologneBlue extends Skin { function doGetUserStyles() { global $wgUser, $wgOut, $wgStyleSheetPath; - - $s = parent::doGetUserStyles(); + $s = ''; $qb = $this->qbSetting(); if ( 2 == $qb ) { # Right @@ -95,6 +99,7 @@ class SkinCologneBlue extends Skin { "#article { margin-left:148px; margin-right: 4px; } \n" . "body>#quickbar { position:fixed; left:4px; top:4px; overflow:auto ;bottom:4px;} \n"; # Hides from IE } + $s .= parent::doGetUserStyles(); return $s; } function sysLinks() diff --git a/includes/SkinNostalgia.php b/includes/SkinNostalgia.php index 3d990ee6705e..c97c681ddd9b 100644 --- a/includes/SkinNostalgia.php +++ b/includes/SkinNostalgia.php @@ -12,6 +12,9 @@ class SkinNostalgia extends Skin { { return "nostalgia.css"; } + function getSkinName() { + return "nostalgia"; + } function doBeforeContent() { @@ -28,6 +31,9 @@ class SkinNostalgia extends Skin { $ol = $this->otherLanguages(); if($ol) $s .= "<br />" . $ol; + + $cat = $this->getCategoryLinks(); + if($cat) $s .= "<br />" . $cat; $s .= "<br clear='all' /><hr />\n</div>\n"; $s .= "\n<div id='article'>"; diff --git a/includes/SkinPHPTal.php b/includes/SkinPHPTal.php index bf39da259933..f56360f60f3a 100644 --- a/includes/SkinPHPTal.php +++ b/includes/SkinPHPTal.php @@ -27,6 +27,7 @@ # http://www.gnu.org/copyleft/gpl.html require_once "GlobalFunctions.php"; + global $IP; require_once $IP."/PHPTAL-NP-0.7.0/libs/PHPTAL.php"; class MediaWiki_I18N extends PHPTAL_I18N @@ -62,7 +63,7 @@ global $wgTitle, $wgArticle, $wgUser, $wgLang, $wgOut; global $wgScript, $wgStylePath, $wgLanguageCode, $wgUseNewInterlanguage; global $wgMimeType, $wgOutputEncoding, $wgUseDatabaseMessages, $wgRequest; - global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses; + global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses, $wgSiteNotice; extract( $wgRequest->getValues( 'oldid', 'diff' ) ); @@ -83,20 +84,27 @@ $this->userpageUrlDetails = $this->makeUrlDetails($this->userpage); $this->usercss = $this->userjs = $this->userjsprev = false; - if( $this->loggedin ) { $this->setupUserCssJs(); } + $this->setupUserCssJs(); $this->titletxt = $wgTitle->getPrefixedText(); $tpl->set( "title", $wgOut->getPageTitle() ); $tpl->set( "pagetitle", $wgOut->getHTMLTitle() ); - $tpl->setRef( "thispage", &$this->thispage ); + $tpl->setRef( "thispage", $this->thispage ); $subpagestr = $this->subPageSubtitle(); $tpl->set( "subtitle", !empty($subpagestr)? '<span class="subpages">'.$subpagestr.'</span>'.$out->getSubtitle(): $out->getSubtitle() ); + $undelete = $this->getUndeleteLink(); + $tpl->set( + "undelete", !empty($undelete)? + '<span class="subpages">'.$undelete.'</span>': + '' + ); + $tpl->set( 'catlinks', $this->getCategories()); if( $wgOut->isSyndicated() ) { $feeds = array(); @@ -107,13 +115,14 @@ 'ttip' => wfMsg('tooltip-'.$format) ); } - $tpl->setRef( 'feeds', &$feeds ); + $tpl->setRef( 'feeds', $feeds ); } - $tpl->setRef( 'mimetype', &$wgMimeType ); - $tpl->setRef( 'charset', &$wgOutputEncoding ); + $tpl->setRef( 'mimetype', $wgMimeType ); + $tpl->setRef( 'charset', $wgOutputEncoding ); $tpl->set( 'headlinks', $out->getHeadLinks() ); - $tpl->setRef( 'skinname', &$this->skinname ); - $tpl->setRef( "loggedin", &$this->loggedin ); + $tpl->setRef( 'skinname', $this->skinname ); + $tpl->setRef( "loggedin", $this->loggedin ); + $tpl->set('nsclass', 'ns-'.$wgTitle->getNamespace()); /* XXX currently unused, might get useful later $tpl->set( "editable", ($wgTitle->getNamespace() != NS_SPECIAL ) ); $tpl->set( "exists", $wgTitle->getArticleID() != 0 ); @@ -123,18 +132,23 @@ $tpl->set( "sysop", $wgUser->isSysop() ); */ $tpl->set( "searchaction", $this->escapeSearchLink() ); - $tpl->setRef( "stylepath", &$wgStylePath ); - $tpl->setRef( "logopath", &$wgLogo ); - $tpl->setRef( "lang", &$wgLanguageCode ); + $tpl->setRef( "stylepath", $wgStylePath ); + $tpl->setRef( "logopath", $wgLogo ); + $tpl->setRef( "lang", $wgLanguageCode ); $tpl->set( "dir", $wgLang->isRTL() ? "rtl" : "ltr" ); $tpl->set( "rtl", $wgLang->isRTL() ); $tpl->set( "langname", $wgLang->getLanguageName( $wgLanguageCode ) ); - $tpl->setRef( "username", &$this->username ); - $tpl->setRef( "userpage", &$this->userpage); - $tpl->setRef( "userpageurl", &$this->userpageUrlDetails['href']); - $tpl->setRef( "usercss", &$this->usercss); - $tpl->setRef( "userjs", &$this->userjs); - $tpl->setRef( "userjsprev", &$this->userjsprev); + $tpl->setRef( "username", $this->username ); + $tpl->setRef( "userpage", $this->userpage); + $tpl->setRef( "userpageurl", $this->userpageUrlDetails['href']); + $tpl->setRef( "usercss", $this->usercss); + $tpl->setRef( "userjs", $this->userjs); + $tpl->setRef( "userjsprev", $this->userjsprev); + if($this->loggedin) { + $tpl->set( "jsvarurl", $this->makeUrl('-','action=raw&gen=js&smaxage=0') ); + } else { + $tpl->set( "jsvarurl", $this->makeUrl('-','action=raw&gen=js') ); + } if( $wgUser->getNewtalk() ) { $usertitle = Title::newFromText( $this->userpage ); $usertalktitle = $usertitle->getTalkPage(); @@ -151,8 +165,8 @@ $ntl = ""; } - $tpl->setRef( "newtalk", &$ntl ); - $tpl->setRef( "skin", &$this); + $tpl->setRef( "newtalk", $ntl ); + $tpl->setRef( "skin", $this); $tpl->set( "logo", $this->logoText() ); if ( $wgOut->isArticle() and (!isset( $oldid ) or isset( $diff )) and 0 != $wgArticle->getID() ) { if ( !$wgDisableCounters ) { @@ -163,16 +177,20 @@ } $tpl->set('lastmod', $this->lastModified()); $tpl->set('copyright',$this->getCopyright()); + } elseif ( isset( $oldid ) && !isset( $diff ) ) { + $tpl->set('copyright', $this->getCopyright()); } + $tpl->set( "copyrightico", $this->getCopyrightIcon() ); $tpl->set( "poweredbyico", $this->getPoweredBy() ); $tpl->set( "disclaimer", $this->disclaimerLink() ); $tpl->set( "about", $this->aboutLink() ); - $tpl->setRef( "debug", &$out->mDebugtext ); + $tpl->setRef( "debug", $out->mDebugtext ); $tpl->set( "reporttime", $out->reportTime() ); - - $tpl->setRef( "bodytext", &$out->mBodytext ); + $tpl->set( "sitenotice", $wgSiteNotice ); + + $tpl->setRef( "bodytext", $out->mBodytext ); $language_urls = array(); foreach( $wgOut->getLanguageLinks() as $l ) { @@ -182,13 +200,13 @@ 'class' => $wgLang->isRTL() ? 'rtl' : 'ltr'); } if(count($language_urls)) { - $tpl->setRef( 'language_urls', &$language_urls); + $tpl->setRef( 'language_urls', $language_urls); } else { $tpl->set('language_urls', false); } $tpl->set('personal_urls', $this->buildPersonalUrls()); $content_actions = $this->buildContentActionUrls(); - $tpl->setRef('content_actions', &$content_actions); + $tpl->setRef('content_actions', $content_actions); // XXX: attach this from javascript, same with section editing if($this->iseditable && $wgUser->getOption("editondblclick") ) { @@ -218,72 +236,52 @@ $personal_urls['userpage'] = array( 'text' => $this->username, 'href' => &$this->userpageUrlDetails['href'], - 'class' => $this->userpageUrlDetails['exists']?false:'new', - 'ttip' => wfMsg('tooltip-userpage'), - 'akey' => wfMsg('accesskey-userpage') + 'class' => $this->userpageUrlDetails['exists']?false:'new' ); $usertalkUrlDetails = $this->makeTalkUrlDetails($this->userpage); $personal_urls['mytalk'] = array( 'text' => wfMsg('mytalk'), 'href' => &$usertalkUrlDetails['href'], - 'class' => $usertalkUrlDetails['exists']?false:'new', - 'ttip' => wfMsg('tooltip-mytalk'), - 'akey' => wfMsg('accesskey-mytalk') + 'class' => $usertalkUrlDetails['exists']?false:'new' ); $personal_urls['preferences'] = array( 'text' => wfMsg('preferences'), - 'href' => $this->makeSpecialUrl('Preferences'), - 'ttip' => wfMsg('tooltip-preferences'), - 'akey' => wfMsg('accesskey-preferences') + 'href' => $this->makeSpecialUrl('Preferences') ); $personal_urls['watchlist'] = array( 'text' => wfMsg('watchlist'), - 'href' => $this->makeSpecialUrl('Watchlist'), - 'ttip' => wfMsg('tooltip-watchlist'), - 'akey' => wfMsg('accesskey-watchlist') + 'href' => $this->makeSpecialUrl('Watchlist') ); $personal_urls['mycontris'] = array( 'text' => wfMsg('mycontris'), - 'href' => $this->makeSpecialUrl('Contributions','target=' . $this->username), - 'ttip' => wfMsg('tooltip-mycontris'), - 'akey' => wfMsg('accesskey-mycontris') + 'href' => $this->makeSpecialUrl('Contributions','target=' . urlencode( $this->username ) ) ); $personal_urls['logout'] = array( 'text' => wfMsg('userlogout'), - 'href' => $this->makeSpecialUrl('Userlogout','returnto=' . $this->thisurl), - 'ttip' => wfMsg('tooltip-logout'), - 'akey' => wfMsg('accesskey-logout') + 'href' => $this->makeSpecialUrl('Userlogout','returnto=' . $this->thisurl ) ); } else { if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) { $personal_urls['anonuserpage'] = array( 'text' => $this->username, 'href' => &$this->userpageUrlDetails['href'], - 'class' => $this->userpageUrlDetails['exists']?false:'new', - 'ttip' => wfMsg('tooltip-anonuserpage'), - 'akey' => wfMsg('accesskey-anonuserpage') + 'class' => $this->userpageUrlDetails['exists']?false:'new' ); $usertalkUrlDetails = $this->makeTalkUrlDetails($this->userpage); $personal_urls['anontalk'] = array( 'text' => wfMsg('anontalk'), 'href' => &$usertalkUrlDetails['href'], - 'class' => $usertalkUrlDetails['exists']?false:'new', - 'ttip' => wfMsg('tooltip-anontalk'), - 'akey' => wfMsg('accesskey-anontalk') + 'class' => $usertalkUrlDetails['exists']?false:'new' ); $personal_urls['anonlogin'] = array( 'text' => wfMsg('userlogin'), - 'href' => $this->makeSpecialUrl('Userlogin', 'returnto='.$this->thisurl), - 'ttip' => wfMsg('tooltip-login'), - 'akey' => wfMsg('accesskey-login') + 'href' => $this->makeSpecialUrl('Userlogin', 'returnto=' . $this->thisurl ) ); } else { $personal_urls['login'] = array( 'text' => wfMsg('userlogin'), - 'href' => $this->makeSpecialUrl('Userlogin', 'returnto='.$this->thisurl), - 'ttip' => wfMsg('tooltip-login'), - 'akey' => wfMsg('accesskey-login') + 'href' => $this->makeSpecialUrl('Userlogin', 'returnto=' . $this->thisurl ) ); } } @@ -302,32 +300,27 @@ if( $this->iscontent ) { - $content_actions['article'] = array('class' => (!Namespace::isTalk( $wgTitle->getNamespace())) ? 'selected' : false, - 'text' => $this->getNameSpaceWord(), - 'href' => $this->makeArticleUrl($this->thispage), - 'ttip' => wfMsg('tooltip-article'), - 'akey' => wfMsg('accesskey-article')); + $nskey = $this->getNameSpaceKey(); + $content_actions[$nskey] = array('class' => (!Namespace::isTalk( $wgTitle->getNamespace())) ? 'selected' : false, + 'text' => wfMsg($nskey), + 'href' => $this->makeArticleUrl($this->thispage)); /* set up the classes for the talk link */ $talk_class = (Namespace::isTalk( $wgTitle->getNamespace()) ? 'selected' : false); $talktitle = Title::newFromText( $this->titletxt ); $talktitle = $talktitle->getTalkPage(); - $this->checkTitle(&$talktitle, &$this->titletxt); + $this->checkTitle($talktitle, $this->titletxt); if($talktitle->getArticleId() != 0) { $content_actions['talk'] = array( 'class' => $talk_class, 'text' => wfMsg('talk'), - 'href' => $this->makeTalkUrl($this->titletxt), - 'ttip' => wfMsg('tooltip-talk'), - 'akey' => wfMsg('accesskey-talk') + 'href' => $this->makeTalkUrl($this->titletxt) ); } else { $content_actions['talk'] = array( 'class' => $talk_class?$talk_class.' new':'new', 'text' => wfMsg('talk'), - 'href' => $this->makeTalkUrl($this->titletxt,'action=edit'), - 'ttip' => wfMsg('tooltip-talk'), - 'akey' => wfMsg('accesskey-talk') + 'href' => $this->makeTalkUrl($this->titletxt,'action=edit') ); } @@ -338,35 +331,27 @@ $content_actions['edit'] = array( 'class' => ((($action == 'edit' or $action == 'submit') and $section != 'new') ? 'selected' : '').$istalkclass, 'text' => wfMsg('edit'), - 'href' => $this->makeUrl($this->thispage, 'action=edit'.$oid), - 'ttip' => wfMsg('tooltip-edit'), - 'akey' => wfMsg('accesskey-edit') + 'href' => $this->makeUrl($this->thispage, 'action=edit'.$oid) ); if ( $istalk ) { $content_actions['addsection'] = array( 'class' => $section == 'new'?'selected':false, 'text' => wfMsg('addsection'), - 'href' => $this->makeUrl($this->thispage, 'action=edit§ion=new'), - 'ttip' => wfMsg('tooltip-addsection'), - 'akey' => wfMsg('accesskey-addsection') + 'href' => $this->makeUrl($this->thispage, 'action=edit§ion=new') ); } } else { $oid = ( $oldid && ! isset( $diff ) ) ? "&oldid={$oldid}" : ''; - $content_actions['edit'] = array('class' => ($action == 'edit') ? 'selected' : false, + $content_actions['viewsource'] = array('class' => ($action == 'edit') ? 'selected' : false, 'text' => wfMsg('viewsource'), - 'href' => $this->makeUrl($this->thispage, 'action=edit'.$oid), - 'ttip' => wfMsg('tooltip-viewsource'), - 'akey' => wfMsg('accesskey-viewsource')); + 'href' => $this->makeUrl($this->thispage, 'action=edit'.$oid)); } if ( $wgTitle->getArticleId() ) { $content_actions['history'] = array('class' => ($action == 'history') ? 'selected' : false, 'text' => wfMsg('history_short'), - 'href' => $this->makeUrl($this->thispage, 'action=history'), - 'ttip' => wfMsg('tooltip-history'), - 'akey' => wfMsg('accesskey-history')); + 'href' => $this->makeUrl($this->thispage, 'action=history')); # XXX: is there a rollback action anywhere or is it planned? # Don't recall where i got this from... @@ -383,41 +368,32 @@ $content_actions['protect'] = array( 'class' => ($action == 'protect') ? 'selected' : false, 'text' => wfMsg('protect'), - 'href' => $this->makeUrl($this->thispage, 'action=protect'), - 'ttip' => wfMsg('tooltip-protect'), - 'akey' => wfMsg('accesskey-protect') + 'href' => $this->makeUrl($this->thispage, 'action=protect') ); } else { $content_actions['unprotect'] = array( 'class' => ($action == 'unprotect') ? 'selected' : false, 'text' => wfMsg('unprotect'), - 'href' => $this->makeUrl($this->thispage, 'action=unprotect'), - 'ttip' => wfMsg('tooltip-protect'), - 'akey' => wfMsg('accesskey-protect') + 'href' => $this->makeUrl($this->thispage, 'action=unprotect') ); } $content_actions['delete'] = array( 'class' => ($action == 'delete') ? 'selected' : false, 'text' => wfMsg('delete'), - 'href' => $this->makeUrl($this->thispage, 'action=delete'), - 'ttip' => wfMsg('tooltip-delete'), - 'akey' => wfMsg('accesskey-delete') + 'href' => $this->makeUrl($this->thispage, 'action=delete') ); } if ( $wgUser->getID() != 0 ) { if ( $wgTitle->userCanEdit()) { $content_actions['move'] = array('class' => ($wgTitle->getDbKey() == 'Movepage' and $wgTitle->getNamespace == Namespace::getSpecial()) ? 'selected' : false, 'text' => wfMsg('move'), - 'href' => $this->makeSpecialUrl('Movepage', 'target='.$this->thispage), - 'ttip' => wfMsg('tooltip-move'), - 'akey' => wfMsg('accesskey-move')); + 'href' => $this->makeSpecialUrl('Movepage', 'target='. urlencode( $this->thispage )) + ); } else { $content_actions['move'] = array('class' => 'inactive', 'text' => wfMsg('move'), - 'href' => false, - 'ttip' => wfMsg('tooltip-nomove'), - 'akey' => false); + 'href' => false); } } @@ -428,9 +404,7 @@ $content_actions['delete'] = array( 'class' => false, 'text' => wfMsg( "undelete_short", $n ), - 'href' => $this->makeSpecialUrl('Undelete/'.$this->thispage), - 'ttip' => wfMsg('tooltip-undelete', $n), - 'akey' => wfMsg('accesskey-undelete') + 'href' => $this->makeSpecialUrl('Undelete/'.$this->thispage) ); } } @@ -440,16 +414,11 @@ if( !$wgTitle->userIsWatching()) { $content_actions['watch'] = array('class' => ($action == 'watch' or $action == 'unwatch') ? 'selected' : false, 'text' => wfMsg('watch'), - 'href' => $this->makeUrl($this->thispage, 'action=watch'), - 'ttip' => wfMsg('tooltip-watch'), - 'akey' => wfMsg('accesskey-watch')); + 'href' => $this->makeUrl($this->thispage, 'action=watch')); } else { $content_actions['watch'] = array('class' => ($action == 'unwatch' or $action == 'watch') ? 'selected' : false, 'text' => wfMsg('unwatch'), - 'href' => $this->makeUrl($this->thispage, 'action=unwatch'), - 'ttip' => wfMsg('tooltip-unwatch'), - 'akey' => wfMsg('accesskey-unwatch')); - + 'href' => $this->makeUrl($this->thispage, 'action=unwatch')); } } } else { @@ -457,9 +426,7 @@ $content_actions['article'] = array('class' => 'selected', 'text' => wfMsg('specialpage'), - 'href' => false, - 'ttip' => wfMsg('tooltip-specialpage'), - 'akey' => false); + 'href' => false); } return $content_actions; @@ -478,10 +445,10 @@ $nav_urls['mainpage'] = array('href' => htmlspecialchars( $this->makeI18nUrl('mainpage'))); $nav_urls['randompage'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Randompage'))); $nav_urls['recentchanges'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Recentchanges'))); - $nav_urls['whatlinkshere'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Whatlinkshere', 'target='.$this->thispage))); + $nav_urls['whatlinkshere'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Whatlinkshere', 'target='.urlencode( $this->thispage )))); $nav_urls['currentevents'] = (wfMsg('currentevents') != '-') ? array('href' => htmlspecialchars( $this->makeI18nUrl('currentevents'))) : false; $nav_urls['portal'] = (wfMsg('portal') != '-') ? array('href' => htmlspecialchars( $this->makeI18nUrl('portal-url'))) : false; - $nav_urls['recentchangeslinked'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Recentchangeslinked', 'target='.$this->thispage))); + $nav_urls['recentchangeslinked'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Recentchangeslinked', 'target='.urlencode( $this->thispage )))); $nav_urls['bugreports'] = array('href' => htmlspecialchars( $this->makeI18nUrl('bugreportspage'))); // $nav_urls['sitesupport'] = array('href' => htmlspecialchars( $this->makeI18nUrl('sitesupportpage'))); $nav_urls['sitesupport'] = array('href' => htmlspecialchars( $wgSiteSupportPage)); @@ -489,9 +456,13 @@ $nav_urls['upload'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Upload'))); $nav_urls['specialpages'] = array('href' => htmlspecialchars( $this->makeSpecialUrl('Specialpages'))); - - $id=User::idFromName($wgTitle->getText()); - $ip=User::isIP($wgTitle->getText()); + if( $wgTitle->getNamespace() == NS_USER || $wgTitle->getNamespace() == NS_USER_TALK ) { + $id = User::idFromName($wgTitle->getText()); + $ip = User::isIP($wgTitle->getText()); + } else { + $id = 0; + $ip = false; + } if($id || $ip) { # both anons and non-anons have contri list $nav_urls['contributions'] = array( @@ -510,58 +481,101 @@ return $nav_urls; } - function getNameSpaceWord () { + function getNameSpaceKey () { global $wgTitle; switch ($wgTitle->getNamespace()) { case NS_MAIN: case NS_TALK: - return wfMsg('nstab-main'); + return 'nstab-main'; case NS_USER: case NS_USER_TALK: - return wfMsg('nstab-user'); + return 'nstab-user'; case NS_MEDIA: - return wfMsg('nstab-media'); + return 'nstab-media'; case NS_SPECIAL: - return wfMsg('nstab-special'); + return 'nstab-special'; case NS_WP: case NS_WP_TALK: - return wfMsg('nstab-wp'); + return 'nstab-wp'; case NS_IMAGE: case NS_IMAGE_TALK: - return wfMsg('nstab-image'); + return 'nstab-image'; case NS_MEDIAWIKI: case NS_MEDIAWIKI_TALK: - return wfMsg('nstab-mediawiki'); + return 'nstab-mediawiki'; case NS_TEMPLATE: case NS_TEMPLATE_TALK: - return wfMsg('nstab-template'); + return 'nstab-template'; case NS_HELP: case NS_HELP_TALK: - return wfMsg('nstab-help'); + return 'nstab-help'; case NS_CATEGORY: case NS_CATEGORY_TALK: - return wfMsg('nstab-category'); + return 'nstab-category'; default: - return wfMsg('nstab-main'); + return 'nstab-main'; } } /* private */ function setupUserCssJs () { global $wgRequest, $wgTitle; $action = $wgRequest->getText('action'); - if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) { - // css preview - $this->usercss = $wgRequest->getText('wpTextbox1'); - } else { - $this->usercss = '@import url('. - $this->makeUrl($this->userpage.'/'.$this->skinname.'.css', 'action=raw&ctype=text/css').');'; + # generated css + $this->usercss = '@import "'.$this->makeUrl('-','action=raw&gen=css').'";'."\n"; + + if( $this->loggedin ) { + if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) { + # generated css + $this->usercss = '@import "'.$this->makeUrl('-','action=raw&gen=css&smaxage=0&maxage=0').');'."\n"; + // css preview + $this->usercss .= $wgRequest->getText('wpTextbox1'); + } else { + # generated css + $this->usercss .= '@import "'.$this->makeUrl('-','action=raw&gen=css&smaxage=0').'";'."\n"; + # import user stylesheet + $this->usercss .= '@import "'. + $this->makeUrl($this->userpage.'/'.$this->skinname.'.css', 'action=raw&ctype=text/css').'";'."\n"; + } + if($wgTitle->isJsSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) { + # XXX: additional security check/prompt? + $this->userjsprev = $wgRequest->getText('wpTextbox1'); + } else { + $this->userjs = $this->makeUrl($this->userpage.'/'.$this->skinname.'.js', 'action=raw&ctype=text/javascript'); + } } - if($wgTitle->isJsSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) { - # XXX: additional security check/prompt? - $this->userjsprev = $wgRequest->getText('wpTextbox1'); - } else { - $this->userjs = $this->makeUrl($this->userpage.'/'.$this->skinname.'.js', 'action=raw&ctype=text/javascript'); + } + # returns css with user-specific options + function getUserStylesheet() { + global $wgUser, $wgRequest, $wgTitle, $wgLang, $wgSquidMaxage, $wgStylePath; + $action = $wgRequest->getText('action'); + $maxage = $wgRequest->getText('maxage'); + $s = "/* generated user stylesheet */\n"; + if($wgLang->isRTL()) $s .= '@import "'.$wgStylePath.'/'.$this->skinname.'/rtl.css";'."\n"; + $s .= '@import "'. + $this->makeNSUrl(ucfirst($this->skinname).'.css', 'action=raw&ctype=text/css&smaxage='.$wgSquidMaxage, NS_MEDIAWIKI)."\";\n"; + if($wgUser->getID() != 0) { + if ( 1 == $wgUser->getOption( "underline" ) ) { + $s .= "a { text-decoration: underline; }\n"; + } else { + $s .= "a { text-decoration: none; }\n"; + } + } + if ( 1 != $wgUser->getOption( "highlightbroken" ) ) { + $s .= "a.new, #quickbar a.new { color: #CC2200; }\n"; } + if ( 1 == $wgUser->getOption( "justify" ) ) { + $s .= "#bodyContent { text-align: justify; }\n"; + } + return $s; + } + function getUserJs() { + global $wgUser, $wgStylePath; + $s = "/* generated javascript */"; + $s .= "var skin = '{$this->skinname}';\nvar stylepath = '{$wgStylePath}';"; + $s .= '/* MediaWiki:'.ucfirst($this->skinname)." */\n"; + $s .= wfMsg(ucfirst($this->skinname).'.js'); + return $s; } + } class SkinDaVinci extends SkinPHPTal { @@ -584,5 +598,12 @@ $this->skinname = "monobook"; } } + + class SkinMySkin extends SkinPHPTal { + function initPage( &$out ) { + SkinPHPTal::initPage( $out ); + $this->skinname = "myskin"; + } + } ?> diff --git a/includes/SkinStandard.php b/includes/SkinStandard.php index 929fc3e91827..ba367a370d85 100644 --- a/includes/SkinStandard.php +++ b/includes/SkinStandard.php @@ -18,12 +18,12 @@ class SkinStandard extends Skin { function getUserStyles() { global $wgStylePath; - - $s = parent::getUserStyles(); + $s = ''; if ( 3 == $this->qbSetting() ) { # Floating left $s .= "<style type='text/css'>\n" . "@import '{$wgStylePath}/quickbar.css';\n</style>\n"; } + $s .= parent::getUserStyles(); return $s; } diff --git a/includes/SpecialAllpages.php b/includes/SpecialAllpages.php index 67246e447f01..ccac741ebd28 100644 --- a/includes/SpecialAllpages.php +++ b/includes/SpecialAllpages.php @@ -52,7 +52,7 @@ function indexShowToplevel() # There's got to be a cleaner way to do this! for( $i = 1; $i < $sections; $i++ ) { $from = $i * $indexMaxperpage; - $sql = "SELECT cur_title $fromwhere $order LIMIT $from,2"; + $sql = "SELECT cur_title $fromwhere $order ".wfLimitResult(2,$from); $res = wfQuery( $sql, DB_READ, $fname ); $s = wfFetchObject( $res ); @@ -66,7 +66,7 @@ function indexShowToplevel() } $from = $i * $indexMaxperpage; - $sql = "SELECT cur_title $fromwhere $order LIMIT " . ($count-1) . ",1"; + $sql = "SELECT cur_title $fromwhere $order ".wfLimitResult(1,$count-1); $res = wfQuery( $sql, DB_READ, $fname ); $s = wfFetchObject( $res ); $outpoint = $s->cur_title; diff --git a/includes/SpecialAncientpages.php b/includes/SpecialAncientpages.php index 52bc0058b3b2..3aa93a54a47d 100644 --- a/includes/SpecialAncientpages.php +++ b/includes/SpecialAncientpages.php @@ -13,12 +13,14 @@ class AncientPagesPage extends QueryPage { } function getSQL() { + global $wgIsMySQL; + $use_index=$wgIsMySQL?"USE INDEX (cur_timestamp)":""; return "SELECT 'Ancientpages' as type, cur_namespace as namespace, cur_title as title, UNIX_TIMESTAMP(cur_timestamp) as value - FROM cur USE INDEX (cur_timestamp) + FROM cur $use_index WHERE cur_namespace=0 AND cur_is_redirect=0"; } diff --git a/includes/SpecialAsksql.php b/includes/SpecialAsksql.php index 6c9c487e4faa..63fefb1a9672 100644 --- a/includes/SpecialAsksql.php +++ b/includes/SpecialAsksql.php @@ -1,4 +1,10 @@ <?php +# +# If enabled through $wgAllowSysopQueries = true, this class +# let users with sysop right the possibility to make sql queries +# against the cur table. +# Heavy queries could slow down the database specially for the +# biggest wikis. function wfSpecialAsksql() { diff --git a/includes/SpecialCategories.php b/includes/SpecialCategories.php index 1a3efca0ccee..6cc493e7ccdf 100644 --- a/includes/SpecialCategories.php +++ b/includes/SpecialCategories.php @@ -1,45 +1,44 @@ <?php +require_once("QueryPage.php"); + +class CategoriesPage extends QueryPage { + + function getName() { + return "Categories"; + } + + function isExpensive() { + return false; + } + + function getSQL() { + $NScat = NS_CATEGORY; + return "SELECT DISTINCT 'Categories' as type, + {$NScat} as namespace, + cl_to as title, + 1 as value + FROM categorylinks"; + } + + function sortDescending() { + return false; + } + + function formatResult( $skin, $result ) { + global $wgLang; + $title = Title::makeTitle( NS_CATEGORY, $result->title ); + return $skin->makeLinkObj( $title, $title->getText() ); + } +} + function wfSpecialCategories() { - global $wgUser, $wgOut , $wgLang; - - $sk = $wgUser->getSkin() ; - $sc = "Special:Categories" ; - - # List all existant categories. - # Note: this list could become *very large* - $r = "<ol>\n" ; - $sql = "SELECT cur_title FROM cur WHERE cur_namespace=".Namespace::getCategory() ; - $res = wfQuery ( $sql, DB_READ ) ; - while ( $x = wfFetchObject ( $res ) ) { - $title =& Title::makeTitle( NS_CATEGORY, $x->cur_title ); - $r .= "<li>" ; - $r .= $sk->makeKnownLinkObj ( $title, $title->getText() ) ; - $r .= "</li>\n" ; - } - wfFreeResult ( $res ) ; - $r .= "</ol>\n" ; - - $r .= "<hr />\n" ; - - # Links to category pages that haven't been created. - # FIXME: This could be slow if there are a lot, but the title index should - # make it reasonably snappy since we're using an index. - $cat = wfStrencode( $wgLang->getNsText( NS_CATEGORY ) ); - $sql = "SELECT DISTINCT bl_to FROM brokenlinks WHERE bl_to LIKE \"{$cat}:%\"" ; - $res = wfQuery ( $sql, DB_READ ) ; - $r .= "<ol>\n" ; - while ( $x = wfFetchObject ( $res ) ) { - $title = Title::newFromDBkey( $x->bl_to ); - $r .= "<li>" ; - $r .= $sk->makeBrokenLinkObj( $title, $title->getText() ) ; - $r .= "</li>\n" ; - } - wfFreeResult ( $res ) ; - $r .= "</ol>\n" ; - - $wgOut->addHTML ( $r ) ; + list( $limit, $offset ) = wfCheckLimits(); + + $cap = new CategoriesPage(); + + return $cap->doQuery( $offset, $limit ); } ?> diff --git a/includes/SpecialContributions.php b/includes/SpecialContributions.php index ad9b5acb5e06..0dcd5ebfc3ae 100644 --- a/includes/SpecialContributions.php +++ b/includes/SpecialContributions.php @@ -2,7 +2,7 @@ function wfSpecialContributions( $par = "" ) { - global $wgUser, $wgOut, $wgLang, $wgRequest; + global $wgUser, $wgOut, $wgLang, $wgRequest, $wgIsPg; $fname = "wfSpecialContributions"; $sysop = $wgUser->isSysop(); @@ -21,23 +21,35 @@ function wfSpecialContributions( $par = "" ) $offlimit = $limit + $offset; $querylimit = $offlimit + 1; $hideminor = ($wgRequest->getVal( 'hideminor' ) ? 1 : 0); + $sk = $wgUser->getSkin(); + + $userCond = ""; $nt = Title::newFromURL( $target ); $nt->setNamespace( Namespace::getUser() ); - $sk = $wgUser->getSkin(); $id = User::idFromName( $nt->getText() ); if ( 0 == $id ) { $ul = $nt->getText(); } else { - $ul = $sk->makeLinkObj( $nt, $nt->getText() ); + $ul = $sk->makeLinkObj( $nt, htmlspecialchars( $nt->getText() ) ); + $userCond = "=" . $id; } $talk = $nt->getTalkPage(); if( $talk ) $ul .= " (" . $sk->makeLinkObj( $talk, $wgLang->getNsText(Namespace::getTalk(0)) ) . ")"; else $ul .= "brrrp"; + + if ( $target == 'newbies' ) { + # View the contributions of all recently created accounts + $row = wfGetArray("user",array("max(user_id) as m"),false); + $userCond = ">" . ($row->m - $row->m / 100); + $ul = ""; + $id = 0; + } + $wgOut->setSubtitle( wfMsg( "contribsub", $ul ) ); if ( $hideminor ) { @@ -53,23 +65,24 @@ function wfSpecialContributions( $par = "" ) "&offset={$offset}&limit={$limit}&hideminor=1" ); } - if ( 0 == $id ) { - $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment,cur_minor_edit,cur_is_new FROM cur " . + $oldtable=$wgIsPg?'"old"':'old'; + if ( $userCond == "" ) { + $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment,cur_minor_edit,cur_is_new,cur_user_text FROM cur " . "WHERE cur_user_text='" . wfStrencode( $nt->getText() ) . "' {$cmq} " . "ORDER BY inverse_timestamp LIMIT {$querylimit}"; $res1 = wfQuery( $sql, DB_READ, $fname ); - $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment,old_minor_edit FROM old " . + $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment,old_minor_edit,old_user_text FROM $oldtable " . "WHERE old_user_text='" . wfStrencode( $nt->getText() ) . "' {$omq} " . "ORDER BY inverse_timestamp LIMIT {$querylimit}"; $res2 = wfQuery( $sql, DB_READ, $fname ); } else { - $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment,cur_minor_edit,cur_is_new FROM cur " . - "WHERE cur_user={$id} {$cmq} ORDER BY inverse_timestamp LIMIT {$querylimit}"; + $sql = "SELECT cur_namespace,cur_title,cur_timestamp,cur_comment,cur_minor_edit,cur_is_new,cur_user_text FROM cur " . + "WHERE cur_user {$userCond} {$cmq} ORDER BY inverse_timestamp LIMIT {$querylimit}"; $res1 = wfQuery( $sql, DB_READ, $fname ); - $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment,old_minor_edit FROM old " . - "WHERE old_user={$id} {$omq} ORDER BY inverse_timestamp LIMIT {$querylimit}"; + $sql = "SELECT old_namespace,old_title,old_timestamp,old_comment,old_minor_edit,old_user_text FROM $oldtable " . + "WHERE old_user {$userCond} {$omq} ORDER BY inverse_timestamp LIMIT {$querylimit}"; $res2 = wfQuery( $sql, DB_READ, $fname ); } $nCur = wfNumRows( $res1 ); @@ -107,6 +120,8 @@ function wfSpecialContributions( $par = "" ) $comment =$obj1->cur_comment; $me = $obj1->cur_minor_edit; $isnew = $obj1->cur_is_new; + $usertext = $obj1->cur_user_text; + $obj1 = wfFetchObject( $res1 ); $topmark = true; --$nCur; @@ -116,6 +131,7 @@ function wfSpecialContributions( $par = "" ) $ts = $obj2->old_timestamp; $comment =$obj2->old_comment; $me = $obj2->old_minor_edit; + $usertext = $obj2->old_user_text; $obj2 = wfFetchObject( $res2 ); $topmark = false; @@ -123,7 +139,7 @@ function wfSpecialContributions( $par = "" ) --$nOld; } if( $n >= $offset ) - ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment, ( $me > 0), $isnew ); + ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment, ( $me > 0), $isnew, $usertext ); } $wgOut->addHTML( "</ul>\n" ); } @@ -147,7 +163,7 @@ other users. TODO: This would probably look a lot nicer in a table. */ -function ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment, $isminor, $isnew ) +function ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment, $isminor, $isnew, $target ) { global $wgLang, $wgOut, $wgUser, $wgRequest; $page = Title::makeName( $ns, $t ); @@ -162,7 +178,7 @@ function ucListEdit( $sk, $ns, $t, $ts, $topmark, $comment, $isminor, $isnew ) $sysop = $wgUser->isSysop(); if($sysop ) { $extraRollback = $wgRequest->getBool( "bot" ) ? '&bot=1' : ''; - $target = $wgRequest->getText( 'target' ); + # $target = $wgRequest->getText( 'target' ); $topmarktext .= " [". $sk->makeKnownLink( $page, wfMsg( "rollbacklink" ), "action=rollback&from=" . urlencode( $target ) . $extraRollback ) ."]"; diff --git a/includes/SpecialDeadendpages.php b/includes/SpecialDeadendpages.php index 84641a5d51fd..a571d68388db 100644 --- a/includes/SpecialDeadendpages.php +++ b/includes/SpecialDeadendpages.php @@ -4,22 +4,26 @@ require_once( "QueryPage.php" ); class DeadendPagesPage extends PageQueryPage { - function getName( ) { - return "Deadendpages"; - } + function getName( ) { + return "Deadendpages"; + } - # LEFT JOIN is expensive + # LEFT JOIN is expensive - function isExpensive( ) { - return 1; - } + function isExpensive( ) { + return 1; + } + + function sortDescending() { + return false; + } - function getSQL( $offset, $limit ) { - return "SELECT cur_title as title, 0 as value " . - "FROM cur LEFT JOIN links ON cur_id = l_from " . - "WHERE l_from IS NULL " . - "AND cur_namespace = 0 " . - "AND cur_is_redirect = 0"; + function getSQL() { + return "SELECT 'Deadendpages' as type, cur_namespace AS namespace, cur_title as title, cur_title AS value " . + "FROM cur LEFT JOIN links ON cur_id = l_from " . + "WHERE l_from IS NULL " . + "AND cur_namespace = 0 " . + "AND cur_is_redirect = 0"; } } diff --git a/includes/SpecialListadmins.php b/includes/SpecialListadmins.php new file mode 100644 index 000000000000..8518c43eafb0 --- /dev/null +++ b/includes/SpecialListadmins.php @@ -0,0 +1,37 @@ +<?php +# +# This class is used to get a list of users flagged with "sysop" +# right. + +require_once("QueryPage.php"); + +class ListAdminsPage extends PageQueryPage { + + function getName() { + return 'Listadmins'; + } + + function sortDescending() { + return false; + } + + function getSQL() { + global $wgIsPg; + $usertable = $wgIsPg?'"user"':'user'; + $userspace = Namespace::getUser(); + return 'SELECT user_rights as type,'.$userspace.' as namespace,'. + 'user_name as title, user_name as value '. + "FROM $usertable ". + 'WHERE user_rights LIKE "%sysop%"'; + } +} + +function wfSpecialListadmins() { + list( $limit, $offset ) = wfCheckLimits(); + + $sla = new ListAdminsPage(); + + return $sla->doQuery( $offset, $limit ); +} + +?> diff --git a/includes/SpecialListusers.php b/includes/SpecialListusers.php index f87852f48297..e74f2a23a920 100644 --- a/includes/SpecialListusers.php +++ b/includes/SpecialListusers.php @@ -1,38 +1,48 @@ <?php +# +# This class is used to get a list of user. The ones with specials +# rights (sysop, bureaucrat, developer) will have them displayed +# next to their names. -function wfSpecialListusers() -{ - global $wgUser, $wgOut, $wgLang; +require_once("QueryPage.php"); - list( $limit, $offset ) = wfCheckLimits(); +class ListUsersPage extends QueryPage { - $top = wfShowingResults( $offset, $limit ); - $wgOut->addHTML( "<p>{$top}\n" ); + function getName() { + return "Listusers"; + } - $sl = wfViewPrevNext( $offset, $limit, - $wgLang->specialPage( "Listusers" ) ); - $wgOut->addHTML( "<br />{$sl}</p>\n<ol start='" . ( $offset + 1 ) . "'>" ); + function getSQL() { + global $wgIsPg; + $usertable = $wgIsPg?'"user"':'user'; + $userspace = Namespace::getUser(); + return "SELECT user_rights as type, $userspace as namespace, user_name as title, user_name as value FROM $usertable"; + } + + function sortDescending() { + return false; + } - $sql = "SELECT user_name,user_rights FROM user ORDER BY " . - "user_name LIMIT {$offset}, {$limit}"; - $res = wfQuery( $sql, DB_READ, "wfSpecialListusers" ); + function formatResult( $skin, $result ) { + global $wgLang; + $name = $skin->makeKnownLink( $wgLang->getNsText($result->namespace) . ':' . $result->title, $result->title ); + if( '' != $result->type ) { + $name .= ' (' . + $skin->makeKnownLink( wfMsg( "administrators" ), $result->type) . + ')'; + } + return $name; + } +} - $sk = $wgUser->getSkin(); - while ( $s = wfFetchObject( $res ) ) { - $n = $s->user_name; - $r = $s->user_rights; +function wfSpecialListusers() { + global $wgUser, $wgOut, $wgLang, $wgIsPg; - $l = $sk->makeLink( $wgLang->getNsText( - Namespace::getUser() ) . ":{$n}", $n ); + list( $limit, $offset ) = wfCheckLimits(); - if ( "" != $r ) { - $link = $sk->makeKnownLink( wfMsg( "administrators" ), $r ); - $l .= " ({$link})"; - } - $wgOut->addHTML( "<li>{$l}</li>\n" ); - } - wfFreeResult( $res ); - $wgOut->addHTML( "</ol>\n<p>{$sl}</p>\n" ); + $slu = new ListUsersPage(); + + return $slu->doQuery( $offset, $limit ); } ?> diff --git a/includes/SpecialLonelypages.php b/includes/SpecialLonelypages.php index bd5286414c6f..ebb4f0b034ac 100644 --- a/includes/SpecialLonelypages.php +++ b/includes/SpecialLonelypages.php @@ -3,30 +3,28 @@ require_once( "QueryPage.php" ); class LonelyPagesPage extends PageQueryPage { - - function getName() { - return "Lonelypages"; - } - - function isExpensive() { - return 1; - } - - function getSQL( $offset, $limit ) { - return "SELECT cur_title FROM cur LEFT JOIN links ON " . - "cur_id=l_to WHERE l_to IS NULL AND cur_namespace=0 AND " . - "cur_is_redirect=0 ORDER BY cur_title LIMIT {$offset}, {$limit}"; - } + function getName() { + return "Lonelypages"; + } + + function isExpensive() { + return true; + } + + function getSQL() { + return "SELECT 'Lonelypages' as type, cur_namespace AS namespace, cur_title AS title, cur_title AS value " . + "FROM cur LEFT JOIN links ON cur_id=l_to ". + "WHERE l_to IS NULL AND cur_namespace=0 AND cur_is_redirect=0"; + } } -function wfSpecialLonelypages() -{ - list( $limit, $offset ) = wfCheckLimits(); - - $lpp = new LonelyPagesPage(); - - return $lpp->doQuery( $offset, $limit ); +function wfSpecialLonelypages() { + list( $limit, $offset ) = wfCheckLimits(); + + $lpp = new LonelyPagesPage(); + + return $lpp->doQuery( $offset, $limit ); } ?> diff --git a/includes/SpecialMakesysop.php b/includes/SpecialMakesysop.php index 653f06256e60..a9564f167fb2 100644 --- a/includes/SpecialMakesysop.php +++ b/includes/SpecialMakesysop.php @@ -76,7 +76,7 @@ class MakesysopForm { </td> </tr>" ); - /* + $makeburo = wfMsg( "setbureaucratflag" ); $wgOut->addHTML( "<tr> @@ -84,7 +84,7 @@ class MakesysopForm { <input type=checkbox name=\"wpSetBureaucrat\" value=1>$makeburo </td> </tr>" - );*/ + ); if ( $wgUser->isDeveloper() ) { $rights = wfMsg( "rights" ); diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 5b013bffe1fc..c8e97f2311d8 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -1,5 +1,5 @@ <?php - +global $wgSpecialPages; $wgSpecialPages = array( "Userlogin" => new UnlistedSpecialPage( "Userlogin" ), "Userlogout" => new UnlistedSpecialPage( "Userlogout" ), @@ -9,11 +9,18 @@ $wgSpecialPages = array( "Upload" => new SpecialPage( "Upload" ), "Imagelist" => new SpecialPage( "Imagelist" ), "Listusers" => new SpecialPage( "Listusers" ), + "Listadmins" => new SpecialPage( "Listadmins" ), "Statistics" => new SpecialPage( "Statistics" ), "Randompage" => new SpecialPage( "Randompage" ), "Lonelypages" => new SpecialPage( "Lonelypages" ), - "Unusedimages" => new SpecialPage( "Unusedimages" ), - "Popularpages" => new SpecialPage( "Popularpages" ), + "Unusedimages" => new SpecialPage( "Unusedimages" ) +); +global $wgDisableCounters; +if( !$wgDisableCounters ) +{ + $wgSpecialPages["Popularpages"] = new SpecialPage( "Popularpages" ); +} +$wgSpecialPages = array_merge($wgSpecialPages, array ( "Wantedpages" => new SpecialPage( "Wantedpages" ), "Shortpages" => new SpecialPage( "Shortpages" ), "Longpages" => new SpecialPage( "Longpages" ), @@ -43,7 +50,7 @@ $wgSpecialPages = array( "Import" => new SpecialPage( "Import", "sysop" ), "Lockdb" => new SpecialPage( "Lockdb", "developer" ), "Unlockdb" => new SpecialPage( "Unlockdb", "developer" ) -); +)); class SpecialPage { diff --git a/includes/SpecialPreferences.php b/includes/SpecialPreferences.php index 11696a02efa7..e060dcb06b52 100644 --- a/includes/SpecialPreferences.php +++ b/includes/SpecialPreferences.php @@ -14,7 +14,7 @@ class PreferencesForm { var $mReset, $mPosted, $mToggles, $mSearchNs, $mRealName; function PreferencesForm( &$request ) { - global $wgLang; + global $wgLang, $wgAllowRealName; $this->mQuickbar = $request->getVal( 'wpQuickbar' ); $this->mOldpass = $request->getVal( 'wpOldpass' ); @@ -27,7 +27,7 @@ class PreferencesForm { $this->mMath = $request->getVal( 'wpMath' ); $this->mDate = $request->getVal( 'wpDate' ); $this->mUserEmail = $request->getVal( 'wpUserEmail' ); - $this->mRealName = $request->getVal( 'wpRealName' ); + $this->mRealName = ($wgAllowRealName) ? $request->getVal( 'wpRealName' ) : ''; $this->mEmailFlag = $request->getCheck( 'wpEmailFlag' ) ? 1 : 0; $this->mNick = $request->getVal( 'wpNick' ); $this->mSearch = $request->getVal( 'wpSearch' ); @@ -180,11 +180,11 @@ class PreferencesForm { /* private */ function resetPrefs() { - global $wgUser, $wgLang; + global $wgUser, $wgLang, $wgAllowRealName; $this->mOldpass = $this->mNewpass = $this->mRetypePass = ""; $this->mUserEmail = $wgUser->getEmail(); - $this->mRealName = $wgUser->getRealName(); + $this->mRealName = ($wgAllowRealName) ? $wgUser->getRealName() : ''; if ( 1 == $wgUser->getOption( "disablemail" ) ) { $this->mEmailFlag = 1; } else { $this->mEmailFlag = 0; } $this->mNick = $wgUser->getOption( "nickname" ); @@ -265,7 +265,8 @@ class PreferencesForm { /* private */ function mainPrefsForm( $err ) { global $wgUser, $wgOut, $wgLang, $wgUseDynamicDates, $wgValidSkinNames; - + global $wgAllowRealName; + $wgOut->setPageTitle( wfMsg( "preferences" ) ); $wgOut->setArticleRelated( false ); $wgOut->setRobotpolicy( "noindex,nofollow" ); @@ -277,6 +278,7 @@ class PreferencesForm { $uid = $wgUser->getID(); $wgOut->addWikiText( wfMsg( "prefslogintext", $uname, $uid ) ); + $wgOut->addWikiText( wfMsg('clearyourcache')); $qbs = $wgLang->getQuickbarSettings(); $skinNames = $wgLang->getSkinNames(); @@ -301,12 +303,13 @@ class PreferencesForm { $tbr = wfMsg( "rows" ); $tbc = wfMsg( "columns" ); $ltz = wfMsg( "localtime" ); + $timezone = wfMsg( "timezonelegend" ); $tzt = wfMsg( "timezonetext" ); $tzo = wfMsg( "timezoneoffset" ); $tzGuess = wfMsg( "guesstimezone" ); $tzServerTime = wfMsg( "servertime" ); $yem = wfMsg( "youremail" ); - $yrn = wfMsg( "yourrealname" ); + $yrn = ($wgAllowRealName) ? wfMsg( "yourrealname" ) : ''; $emf = wfMsg( "emailflag" ); $ynn = wfMsg( "yournick" ); $stt = wfMsg ( "stubthreshold" ) ; @@ -332,12 +335,15 @@ class PreferencesForm { $ps = $this->namespacesCheckboxes(); $wgOut->addHTML( "<fieldset> - <legend>".wfMsg('prefs-personal')."</legend> - <div><label>$yrn: <input type='text' name=\"wpRealName\" value=\"{$this->mRealName}\" size='20' /></label></div> + <legend>".wfMsg('prefs-personal')."</legend>"); + if ($wgAllowRealName) { + $wgOut->addHTML("<div><label>$yrn: <input type='text' name=\"wpRealName\" value=\"{$this->mRealName}\" size='20' /></label></div>"); + } + $wgOut->addHTML(" <div><label>$yem: <input type='text' name=\"wpUserEmail\" value=\"{$this->mUserEmail}\" size='20' /></label></div> <div><label><input type='checkbox' $emfc value=\"1\" name=\"wpEmailFlag\" /> $emf</label></div> <div><label>$ynn: <input type='text' name=\"wpNick\" value=\"{$this->mNick}\" size='12' /></label></div>\n" ); - + # Fields for changing password # $this->mOldpass = wfEscapeHTML( $this->mOldpass ); @@ -363,6 +369,7 @@ class PreferencesForm { $wgOut->addHTML( "<div><label><input type='radio' name=\"wpQuickbar\" value=\"$i\"$checked /> {$qbs[$i]}</label></div>\n" ); } + $wgOut->addHtml('<div class="prefsectiontip">'.wfMsg('qbsettingsnote').'</div>'); $wgOut->addHtml( "</fieldset>\n\n" ); # Skin setting @@ -426,7 +433,7 @@ class PreferencesForm { </fieldset> <fieldset> - <legend>$dateFormat</legend> + <legend>$timezone</legend> <div><b>$tzServerTime:</b> $nowserver</div> <div><b>$ltz:</b> $nowlocal</div> <div><label>$tzo*: <input type='text' name=\"wpHourDiff\" value=\"{$this->mHourDiff}\" size='6' /></label></div> diff --git a/includes/SpecialRandompage.php b/includes/SpecialRandompage.php index a442623f1b18..bf6a7fa9a03e 100644 --- a/includes/SpecialRandompage.php +++ b/includes/SpecialRandompage.php @@ -1,16 +1,18 @@ <?php +# $Id$ function wfSpecialRandompage() { - global $wgOut, $wgTitle, $wgArticle; + global $wgOut, $wgTitle, $wgArticle, $wgIsMySQL; $fname = "wfSpecialRandompage"; wfSeedRandom(); $rand = mt_rand() / mt_getrandmax(); # interpolation and sprintf() can muck up with locale-specific decimal separator $randstr = number_format( $rand, 12, ".", "" ); + $use_index=$wgIsMySQL?"USE INDEX (cur_random)":""; $sqlget = "SELECT cur_id,cur_title - FROM cur USE INDEX (cur_random) + FROM cur $use_index WHERE cur_namespace=0 AND cur_is_redirect=0 AND cur_random>$randstr ORDER BY cur_random diff --git a/includes/SpecialRecentchanges.php b/includes/SpecialRecentchanges.php index 127678528581..4470c7622c2b 100644 --- a/includes/SpecialRecentchanges.php +++ b/includes/SpecialRecentchanges.php @@ -111,11 +111,11 @@ function wfSpecialRecentchanges( $par ) } else { $note = wfMsg( "rcnote", $wgLang->formatNum( $limit ), $wgLang->formatNum( $days ) ); } - $wgOut->addHTML( "\n<hr/>\n{$note}\n<br/>" ); + $wgOut->addHTML( "\n<hr />\n{$note}\n<br />" ); $note = rcDayLimitLinks( $days, $limit, "Recentchanges", $hideparams, false, $minorLink, $botLink, $liuLink ); - $note .= "<br/>\n" . wfMsg( "rclistfrom", + $note .= "<br />\n" . wfMsg( "rclistfrom", $sk->makeKnownLink( $wgLang->specialPage( "Recentchanges" ), $wgLang->timeanddate( $now, true ), "{$hideparams}&from=$now" ) ); diff --git a/includes/SpecialShortpages.php b/includes/SpecialShortpages.php index 560b02b8c1af..c3eafc41187f 100644 --- a/includes/SpecialShortpages.php +++ b/includes/SpecialShortpages.php @@ -1,4 +1,8 @@ <?php +# +# SpecialShortpages extends QueryPage. It is used to return the shortest +# pages in the database. +# require_once("QueryPage.php"); @@ -34,8 +38,7 @@ class ShortPagesPage extends QueryPage { } } -function wfSpecialShortpages() -{ +function wfSpecialShortpages() { list( $limit, $offset ) = wfCheckLimits(); $spp = new ShortPagesPage(); diff --git a/includes/SpecialStatistics.php b/includes/SpecialStatistics.php index a6433aaeb6a9..b842e52525f6 100644 --- a/includes/SpecialStatistics.php +++ b/includes/SpecialStatistics.php @@ -2,7 +2,7 @@ function wfSpecialStatistics() { - global $wgUser, $wgOut, $wgLang; + global $wgUser, $wgOut, $wgLang, $wgIsPg; $fname = "wfSpecialStatistics"; $wgOut->addHTML( "<h2>" . wfMsg( "sitestats" ) . "</h2>\n" ); @@ -31,12 +31,13 @@ function wfSpecialStatistics() $wgOut->addWikiText( $text ); $wgOut->addHTML( "<h2>" . wfMsg( "userstats" ) . "</h2>\n" ); - $sql = "SELECT COUNT(user_id) AS total FROM user"; + $usertable=$wgIsPg?'"user"':'user'; + $sql = "SELECT COUNT(user_id) AS total FROM $usertable"; $res = wfQuery( $sql, DB_READ, $fname ); $row = wfFetchObject( $res ); $total = $row->total; - $sql = "SELECT COUNT(user_id) AS total FROM user " . + $sql = "SELECT COUNT(user_id) AS total FROM $usertable " . "WHERE user_rights LIKE '%sysop%'"; $res = wfQuery( $sql, DB_READ, $fname ); $row = wfFetchObject( $res ); diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php index 9f2f8e2963e6..e504b31a9edc 100644 --- a/includes/SpecialUndelete.php +++ b/includes/SpecialUndelete.php @@ -79,7 +79,8 @@ class UndeleteForm { if(!preg_match("/[0-9]{14}/",$timestamp)) return 0; $sql = "SELECT ar_text,ar_flags FROM archive ". - "WHERE ar_namespace={$namespace} AND ar_title=\"{$title}\" AND ar_timestamp={$timestamp}"; + "WHERE ar_namespace={$namespace} AND ar_title='" . + wfStrencode( $title ) . "' AND ar_timestamp='" . wfStrencode( $timestamp ) ."'"; $ret = wfQuery( $sql, DB_READ, $fname ); $row = wfFetchObject( $ret ); @@ -97,8 +98,8 @@ class UndeleteForm { $wgOut->setPagetitle( wfMsg( "undeletepage" ) ); # Get text of first revision - $sql = "SELECT ar_text FROM archive WHERE ar_namespace={$namespace} AND ar_title=\"{$title}\" - ORDER BY ar_timestamp DESC LIMIT 1"; + $sql = "SELECT ar_text FROM archive WHERE ar_namespace={$namespace} AND ar_title='" . + wfStrencode( $title ) . "' ORDER BY ar_timestamp DESC LIMIT 1"; $ret = wfQuery( $sql, DB_READ ); if( wfNumRows( $ret ) == 0 ) { @@ -110,8 +111,8 @@ class UndeleteForm { # Get remaining revisions $sql = "SELECT ar_minor_edit,ar_timestamp,ar_user,ar_user_text,ar_comment - FROM archive WHERE ar_namespace={$namespace} AND ar_title=\"{$title}\" - ORDER BY ar_timestamp DESC"; + FROM archive WHERE ar_namespace={$namespace} AND ar_title='" . wfStrencode( $title ) . + "' ORDER BY ar_timestamp DESC"; $ret = wfQuery( $sql, DB_READ ); # Ditch first row $row = wfFetchObject( $ret ); @@ -126,7 +127,8 @@ class UndeleteForm { <input type=submit name=\"restore\" value=\"".wfMsg("undeletebtn")."\"> </form>"); - $log = wfGetSQL("cur", "cur_text", "cur_namespace=4 AND cur_title=\"".wfMsg("dellogpage")."\"" ); + $log = wfGetSQL("cur", "cur_text", "cur_namespace=4 AND cur_title='". + wfStrencode( wfMsg("dellogpage") ) . "'" ); if(preg_match("/^(.*". preg_quote( ($namespace ? ($wgLang->getNsText($namespace) . ":") : "") . str_replace("_", " ", $title), "/" ).".*)$/m", $log, $m)) { @@ -140,7 +142,7 @@ class UndeleteForm { $sk->makeKnownLink( $wgLang->specialPage( "Undelete" ), $wgLang->timeanddate( $row->ar_timestamp, true ), "target=" . urlencode($this->mTarget) . "×tamp={$row->ar_timestamp}" ) . " " . - ". . {$row->ar_user_text}" . + ". . " . htmlspecialchars( $row->ar_user_text ) . " <i>(" . htmlspecialchars($row->ar_comment) . "</i>)\n"); } @@ -160,7 +162,7 @@ class UndeleteForm { $wgOut->fatalError( wfMsg( "cannotundelete" ) ); return; } - $t = addslashes($title); + $t = wfStrencode($title); # Move article and history from the "archive" table $sql = "SELECT COUNT(*) AS count FROM cur WHERE cur_namespace={$namespace} AND cur_title='{$t}'"; diff --git a/includes/SpecialUnusedimages.php b/includes/SpecialUnusedimages.php index 09075f5be1e2..4bc8d7bbf886 100644 --- a/includes/SpecialUnusedimages.php +++ b/includes/SpecialUnusedimages.php @@ -8,7 +8,7 @@ function wfSpecialUnusedimages() { $sql = "SELECT img_name,img_user,img_user_text,img_timestamp,img_description " . "FROM image LEFT JOIN imagelinks ON img_name=il_to WHERE il_to IS NULL " . - "ORDER BY img_timestamp LIMIT {$offset}, {$limit}"; + "ORDER BY img_timestamp ".wfLimitResult($limit,$offset); $res = wfQuery( $sql, DB_READ, $fname ); $sk = $wgUser->getSkin(); diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index eeff3989881d..f9dfebd824c9 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -73,13 +73,14 @@ class UploadForm { global $wgUser, $wgOut, $wgLang; global $wgUploadDirectory; global $wgSavedFile, $wgUploadOldVersion; - global $wgUseCopyrightUpload; + global $wgUseCopyrightUpload, $wgCheckCopyrightUpload; global $wgCheckFileExtensions, $wgStrictFileExtensions; - global $wgFileExtensions, $wgFileBlacklist; + global $wgFileExtensions, $wgFileBlacklist, $wgUploadSizeWarning; if ( $wgUseCopyrightUpload ) { $this->mUploadAffirm = 1; - if ( trim ( $this->mUploadCopyStatus ) == "" || trim ( $this->mUploadSource ) == "" ) { + if ($wgCheckCopyrightUpload && + (trim ( $this->mUploadCopyStatus ) == "" || trim ( $this->mUploadSource ) == "" )) { $this->mUploadAffirm = 0; } } @@ -106,6 +107,7 @@ class UploadForm { return; } $nt = Title::newFromText( $basename ); + $nt->setNamespace( Namespace::getImage() ); $this->mUploadSaveName = $nt->getDBkey(); /* Don't allow users to override the blacklist */ @@ -115,19 +117,31 @@ class UploadForm { } $this->saveUploadedFile( $this->mUploadSaveName, $this->mUploadTempName ); - if ( ( ! $this->mIgnoreWarning ) && - ( 0 != strcmp( ucfirst( $basename ), $this->mUploadSaveName ) ) ) { - return $this->uploadWarning( wfMsg( "badfilename", $this->mUploadSaveName ) ); - } + if ( !$nt->userCanEdit() ) { + return $this->uploadError( wfMsg( "protectedpage" ) ); + } - if ( $wgCheckFileExtensions ) { - if ( ( ! $this->mIgnoreWarning ) && - ( ! $this->checkFileExtension( $ext, $wgFileExtensions ) ) ) { - return $this->uploadWarning( wfMsg( "badfiletype", $ext ) ); + if ( ! $this->mIgnoreWarning ) { + $warning = ''; + if( 0 != strcmp( ucfirst( $basename ), $this->mUploadSaveName ) ) { + $warning .= '<li>'.wfMsg( "badfilename", $this->mUploadSaveName ).'</li>'; } - } - if ( ( ! $this->mIgnoreWarning ) && ( $this->mUploadSize > 150000 ) ) { - return $this->uploadWarning( wfMsg( "largefile" ) ); + + if ( $wgCheckFileExtensions ) { + if ( ! $this->checkFileExtension( $ext, $wgFileExtensions ) ) { + $warning .= '<li>'.wfMsg( "badfiletype", $ext ).'</li>'; + } + } + if ( $wgUploadSizeWarning && ( $this->mUploadSize > $wgUploadSizeWarning ) ) { + $warning .= '<li>'.wfMsg( "largefile" ).'</li>'; + } + if( $nt->getArticleID() ) { + $sk = $wgUser->getSkin(); + $dname = $wgLang->getNsText( Namespace::getImage() ) . ":{$this->mUploadSaveName}"; + $dlink = $sk->makeKnownLink( $dname, $dname ); + $warning .= '<li>'.wfMsg( "fileexists", $dlink ).'</li>'; + } + if($warning != '') return $this->uploadWarning($warning); } } if ( !is_null( $this->mUploadOldVersion ) ) { @@ -220,7 +234,7 @@ class UploadForm { $sub = wfMsg( "uploadwarning" ); $wgOut->addHTML( "<h2>{$sub}</h2>\n" ); - $wgOut->addHTML( "<h4><font color=red>{$warning}</font></h4>\n" ); + $wgOut->addHTML( "<ul class='warning'>{$warning}</ul><br/>\n" ); $save = wfMsg( "savefile" ); $reupload = wfMsg( "reupload" ); diff --git a/includes/SpecialUserlogin.php b/includes/SpecialUserlogin.php index c950ed5f150a..700cf6cf49e0 100644 --- a/includes/SpecialUserlogin.php +++ b/includes/SpecialUserlogin.php @@ -20,7 +20,7 @@ class LoginForm { var $mLoginattempt, $mRemember, $mEmail; function LoginForm( &$request ) { - global $wgLang; + global $wgLang, $wgAllowRealName; $this->mName = $request->getText( 'wpName' ); $this->mPassword = $request->getText( 'wpPassword' ); @@ -35,8 +35,12 @@ class LoginForm { $this->mAction = $request->getVal( 'action' ); $this->mRemember = $request->getCheck( 'wpRemember' ); $this->mEmail = $request->getText( 'wpEmail' ); - $this->mRealName = $request->getText( 'wpRealName' ); - + if ($wgAllowRealName) { + $this->mRealName = $request->getText( 'wpRealName' ); + } else { + $this->mRealName = ''; + } + # When switching accounts, it sucks to get automatically logged out if( $this->mReturnto == $wgLang->specialPage( "Userlogout" ) ) { $this->mReturnto = ""; @@ -122,6 +126,19 @@ class LoginForm { { global $wgUser, $wgOut; global $wgMaxNameChars; + global $wgMemc, $wgAccountCreationThrottle, $wgDBname, $wgIP; + + if ( $wgAccountCreationThrottle ) { + $key = "$wgDBname:acctcreate:ip:$wgIP"; + $value = $wgMemc->incr( $key ); + if ( !$value ) { + $wgMemc->set( $key, 1, 86400 ); + } + if ( $value > $wgAccountCreationThrottle ) { + $this->throttleHit( $wgAccountCreationThrottle ); + return; + } + } if (!$wgUser->isAllowedToCreateAccount()) { $this->userNotPrivilegedMessage(); @@ -301,7 +318,7 @@ class LoginForm { /* private */ function mainLoginForm( $err ) { global $wgUser, $wgOut, $wgLang; - global $wgDBname; + global $wgDBname, $wgAllowRealName; $le = wfMsg( "loginerror" ); $yn = wfMsg( "yourname" ); @@ -313,7 +330,11 @@ class LoginForm { $ca = wfMsg( "createaccount" ); $cam = wfMsg( "createaccountmail" ); $ye = wfMsg( "youremail" ); - $yrn = wfMsg( "yourrealname" ); + if ($wgAllowRealName) { + $yrn = wfMsg( "yourrealname" ); + } else { + $yrn = ''; + } $efl = wfMsg( "emailforlost" ); $mmp = wfMsg( "mailmypassword" ); $endText = wfMsg( "loginend" ); @@ -401,20 +422,23 @@ class LoginForm { <td align='right'>$ye:</td> <td align='left'> <input tabindex='6' type='text' name=\"wpEmail\" value=\"{$encEmail}\" size='20' /> - </td> - <td> </td> - </tr> - <tr> - <td align='right'>$yrn:</td> - <td align='left'> - <input tabindex='6' type='text' name=\"wpRealName\" value=\"{$encRealName}\" size='20' /> - </td> - <td align='left'> + </td>"); + + if ($wgAllowRealName) { + $wgOut->addHTML("<td> </td> + </tr><tr> + <td align='right'>$yrn:</td> + <td align='left'> + <input tabindex='6' type='text' name=\"wpRealName\" value=\"{$encRealName}\" size='20' /> + </td>"); + } + + $wgOut->addHTML("<td align='left'> <input tabindex='7' type='submit' name=\"wpCreateaccount\" value=\"{$ca}\" /> $cambutton </td></tr>"); } - + $wgOut->addHTML(" <tr><td colspan='3'> </td></tr><tr> <td colspan='3' align='left'> @@ -457,5 +481,11 @@ class LoginForm { return $this->successfulLogin( wfMsg( "loginsuccess", $wgUser->getName() ) ); } } + + /* private */ function throttleHit( $limit ) { + global $wgOut; + + $wgOut->addWikiText( wfMsg( 'acct_creation_throttle_hit', $limit ) ); + } } ?> diff --git a/includes/SpecialWatchlist.php b/includes/SpecialWatchlist.php index 619dc38445f9..806eff0e9673 100644 --- a/includes/SpecialWatchlist.php +++ b/includes/SpecialWatchlist.php @@ -5,7 +5,7 @@ require_once( "WatchedItem.php" ); function wfSpecialWatchlist() { global $wgUser, $wgOut, $wgLang, $wgTitle, $wgMemc; - global $wgUseWatchlistCache, $wgWLCacheTimeout, $wgDBname; + global $wgUseWatchlistCache, $wgWLCacheTimeout, $wgDBname, $wgIsMySQL; global $days, $limit, $target; # From query string $fname = "wfSpecialWatchlist"; @@ -102,10 +102,14 @@ function wfSpecialWatchlist() $sk = $wgUser->getSkin(); while( $s = wfFetchObject( $res ) ) { $t = Title::makeTitle( $s->wl_namespace, $s->wl_title ); - $t = $t->getPrefixedText(); - $wgOut->addHTML( "<li><input type='checkbox' name='id[]' value=\"" . htmlspecialchars($t) . "\" />" . - $sk->makeKnownLink( $t, $t ) . - "</li>\n" ); + if( is_null( $t ) ) { + $wgOut->addHTML( '<!-- bad title "' . htmlspecialchars( $s->wl_title ) . '" in namespace ' . IntVal( $s->wl_namespace ) . " -->\n" ); + } else { + $t = $t->getPrefixedText(); + $wgOut->addHTML( "<li><input type='checkbox' name='id[]' value=\"" . htmlspecialchars($t) . "\" />" . + $sk->makeKnownLink( $t, $t ) . + "</li>\n" ); + } } $wgOut->addHTML( "</ul>\n" . "<input type='submit' name='remove' value='" . @@ -137,11 +141,11 @@ function wfSpecialWatchlist() $wgLang->formatNum( $nitems ), $wgLang->formatNum( $npages ), $y, $specialTitle->escapeLocalUrl( "magic=yes" ) ) . "</i><br />\n" ); - + $use_index=$wgIsMySQL?"USE INDEX ($x)":""; $sql = "SELECT cur_namespace,cur_title,cur_comment, cur_id, cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new - FROM watchlist,cur USE INDEX ($x) + FROM watchlist,cur $use_index WHERE wl_user=$uid AND $z AND wl_title=cur_title diff --git a/includes/SpecialWhatlinkshere.php b/includes/SpecialWhatlinkshere.php index 900f9e7db294..d8770bb4383a 100644 --- a/includes/SpecialWhatlinkshere.php +++ b/includes/SpecialWhatlinkshere.php @@ -27,7 +27,7 @@ function wfSpecialWhatlinkshere($par = NULL) $sk = $wgUser->getSkin(); $isredir = " (" . wfMsg( "isredirect" ) . ")\n"; - $wgOut->addHTML("< ".$sk->makeKnownLinkObj($nt, "", "redirect=no" )."<br/>\n"); + $wgOut->addHTML("< ".$sk->makeKnownLinkObj($nt, "", "redirect=no" )."<br />\n"); if ( 0 == $id ) { $sql = "SELECT cur_id,cur_namespace,cur_title,cur_is_redirect FROM brokenlinks,cur WHERE bl_to='" . diff --git a/includes/Title.php b/includes/Title.php index 255cc157bc38..35ae3e839102 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -88,13 +88,13 @@ class Title { # From a URL-encoded title /* static */ function newFromURL( $url ) { - global $wgLang, $wgServer; + global $wgLang, $wgServer, $wgIsMySQL, $wgIsPg; $t = new Title(); - $s = urldecode( $url ); # This is technically wrong, as anything - # we've gotten is already decoded by PHP. - # Kept for backwards compatibility with - # buggy URLs we had for a while... - $s = $url; + + # For compatibility with old buggy URLs. "+" is not valid in titles, + # but some URLs used it as a space replacement and they still come + # from some external search tools. + $s = str_replace( "+", " ", $url ); # For links that came from outside, check for alternate/legacy # character encoding. @@ -109,14 +109,20 @@ class Title { $t->mDbkeyform = str_replace( " ", "_", $s ); if( $t->secureAndSplit() ) { - # check that lenght of title is < cur_title size - $sql = "SHOW COLUMNS FROM cur LIKE \"cur_title\";"; - $cur_title_object = wfFetchObject(wfQuery( $sql, DB_READ )); + if ($wgIsMySQL) { + $sql = "SHOW COLUMNS FROM cur LIKE \"cur_title\";"; + $cur_title_object = wfFetchObject(wfQuery( $sql, DB_READ )); - preg_match( "/\((.*)\)/", $cur_title_object->Type, $cur_title_size); + preg_match( "/\((.*)\)/", $cur_title_object->Type, $cur_title_type); + $cur_title_size=$cur_title_type[1]; + } else { + /* midom:FIXME pg_field_type does not return varchar length + assume 255 */ + $cur_title_size=255; + } - if (strlen($t->mDbkeyform) > $cur_title_size[1] ) { + if (strlen($t->mDbkeyform) > $cur_title_size ) { return NULL; } @@ -182,11 +188,12 @@ class Title { # Missing characters: # * []|# Needed for link syntax # * % and + are corrupted by Apache when they appear in the path + # * % seems to work though # # Theoretically 0x80-0x9F of ISO 8859-1 should be disallowed, but # this breaks interlanguage links - $set = " !\"$&'()*,\\-.\\/0-9:;<=>?@A-Z\\\\^_`a-z{}~\\x80-\\xFF"; + $set = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z{}~\\x80-\\xFF"; return $set; } @@ -228,8 +235,7 @@ class Title { # The URL contains $1, which is replaced by the title function getInterwikiLink( $key ) { - global $wgMemc, $wgDBname, $wgInterwikiExpiry; - static $wgTitleInterwikiCache = array(); + global $wgMemc, $wgDBname, $wgInterwikiExpiry, $wgTitleInterwikiCache; $k = "$wgDBname:interwiki:$key"; @@ -369,9 +375,6 @@ class Title { $n = $wgLang->getNsText( $this->mNamespace ); if ( "" != $n ) { $n .= ":"; } $u = str_replace( "$1", $n . $this->mUrlform, $p ); - if ( "" != $this->mFragment ) { - $u .= "#" . wfUrlencode( $this->mFragment ); - } return $u; } @@ -486,15 +489,20 @@ class Title { # Can $wgUser edit this page? function userCanEdit() { - + global $wgUser; if ( -1 == $this->mNamespace ) { return false; } + if ( NS_MEDIAWIKI == $this->mNamespace && !$wgUser->isSysop() ) { return false; } # if ( 0 == $this->getArticleID() ) { return false; } if ( $this->mDbkeyform == "_" ) { return false; } + # protect global styles and js + if ( NS_MEDIAWIKI == $this->mNamespace + && preg_match("/\\.(css|js)$/", $this->mTextform ) + && !$wgUser->isSysop() ) + { return false; } //if ( $this->isCssJsSubpage() and !$this->userCanEditCssJsSubpage() ) { return false; } # protect css/js subpages of user pages # XXX: this might be better using restrictions # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working - global $wgUser; if( Namespace::getUser() == $this->mNamespace and preg_match("/\\.(css|js)$/", $this->mTextform ) and !$wgUser->isSysop() @@ -520,7 +528,7 @@ class Title { if( in_array( $name, $wgWhitelistRead ) ) return true; # Compatibility with old settings - if( $this->getNamespace() == NS_ARTICLE ) { + if( $this->getNamespace() == NS_MAIN ) { if( in_array( ":" . $name, $wgWhitelistRead ) ) return true; } return false; @@ -638,6 +646,7 @@ class Title { # Initialisation if ( $imgpre === false ) { $imgpre = ":" . $wgLang->getNsText( Namespace::getImage() ) . ":"; + # % is needed as well $rxTc = "/[^" . Title::legalChars() . "]/"; } @@ -668,7 +677,7 @@ class Title { $this->mNamespace = NS_MAIN; } else { # Namespace or interwiki prefix - if ( preg_match( "/^((?:i|x|[a-z]{2,3})(?:-[a-z0-9]+)?|[A-Za-z0-9_\\x80-\\xff]+?)_*:_*(.*)$/", $t, $m ) ) { + if ( preg_match( "/^(.+?)_*:_*(.*)$/", $t, $m ) ) { #$p = strtolower( $m[1] ); $p = $m[1]; $lowerNs = strtolower( $p ); @@ -716,8 +725,13 @@ class Title { return false; } - # "." and ".." conflict with the directories of those names - if ( $r === "." || $r === ".." ) { + # "." and ".." conflict with the directories of those namesa + if ( strpos( $r, "." ) !== false && + ( $r === "." || $r === ".." || + strpos( $r, "./" ) === 0 || + strpos( $r, "/./" !== false ) || + strpos( $r, "/../" !== false ) ) ) + { return false; } @@ -756,9 +770,10 @@ class Title { $retVal = array(); if ( wfNumRows( $res ) ) { while ( $row = wfFetchObject( $res ) ) { - $titleObj = Title::makeTitle( $row->cur_namespace, $row->cur_title ); - $wgLinkCache->addGoodLink( $row->cur_id, $titleObj->getPrefixedDBkey() ); - $retVal[] = $titleObj; + if ( $titleObj = Title::makeTitle( $row->cur_namespace, $row->cur_title ) ) { + $wgLinkCache->addGoodLink( $row->cur_id, $titleObj->getPrefixedDBkey() ); + $retVal[] = $titleObj; + } } } wfFreeResult( $res ); @@ -777,7 +792,7 @@ class Title { if ( wfNumRows( $res ) ) { while ( $row = wfFetchObject( $res ) ) { $titleObj = Title::makeTitle( $row->cur_namespace, $row->cur_title ); - $wgLinkCache->addGoodLink( $titleObj->getPrefixedDBkey(), $row->cur_id ); + $wgLinkCache->addGoodLink( $row->cur_id, $titleObj->getPrefixedDBkey() ); $retVal[] = $titleObj; } } @@ -927,7 +942,7 @@ class Title { $fname ); - RecentChange::notifyMove( $now, $this, $nt, $wgUser, $comment ); + RecentChange::notifyMoveOverRedirect( $now, $this, $nt, $wgUser, $comment ); # Swap links @@ -935,34 +950,51 @@ class Title { $linksToOld = $this->getLinksTo(); $linksToNew = $nt->getLinksTo(); - # Make function to convert Titles to IDs - $titleToID = create_function('$t', 'return $t->getArticleID();'); - - # Reassign links to old title - if ( count( $linksToOld ) ) { - $sql = "UPDATE links SET l_to=$newid WHERE l_from IN ("; - $sql .= implode( ",", array_map( $titleToID, $linksToOld ) ); - $sql .= ")"; - wfQuery( $sql, DB_WRITE, $fname ); - } - - # Reassign links to new title - if ( count( $linksToNew ) ) { - $sql = "UPDATE links SET l_to=$oldid WHERE l_from IN ("; - $sql .= implode( ",", array_map( $titleToID, $linksToNew ) ); - $sql .= ")"; + # Delete them all + $sql = "DELETE FROM links WHERE l_to=$oldid OR l_to=$newid"; + wfQuery( $sql, DB_WRITE, $fname ); + + # Reinsert + if ( count( $linksToOld ) || count( $linksToNew )) { + $sql = "INSERT INTO links (l_from,l_to) VALUES "; + $first = true; + + # Insert links to old title + foreach ( $linksToOld as $linkTitle ) { + if ( $first ) { + $first = false; + } else { + $sql .= ","; + } + $id = $linkTitle->getArticleID(); + $sql .= "($id,$newid)"; + } + + # Insert links to new title + foreach ( $linksToNew as $linkTitle ) { + if ( $first ) { + $first = false; + } else { + $sql .= ","; + } + $id = $linkTitle->getArticleID(); + $sql .= "($id, $oldid)"; + } + wfQuery( $sql, DB_WRITE, $fname ); } - # Note: the insert below must be after the updates above! - # Now, we record the link from the redirect to the new title. # It should have no other outgoing links... $sql = "DELETE FROM links WHERE l_from={$newid}"; wfQuery( $sql, DB_WRITE, $fname ); $sql = "INSERT INTO links (l_from,l_to) VALUES ({$newid},{$oldid})"; wfQuery( $sql, DB_WRITE, $fname ); - + + # Clear linkscc + LinkCache::linksccClearLinksTo( $oldid ); + LinkCache::linksccClearLinksTo( $newid ); + # Purge squid if ( $wgUseSquid ) { $urls = array_merge( $nt->getSquidURLs(), $this->getSquidURLs() ); @@ -1029,14 +1061,16 @@ class Title { ), $fname ); - # Miscellaneous updates + # Record in RC + RecentChange::notifyMoveToNew( $now, $this, $nt, $wgUser, $comment ); - RecentChange::notifyMove( $now, $this, $nt, $wgUser, $comment ); + # Purge squid and linkscc as per article creation Article::onArticleCreate( $nt ); # Any text links to the old title must be reassigned to the redirect $sql = "UPDATE links SET l_to={$newid} WHERE l_to={$oldid}"; wfQuery( $sql, DB_WRITE, $fname ); + LinkCache::linksccClearLinksTo( $oldid ); # Record the just-created redirect's linking to the page $sql = "INSERT INTO links (l_from,l_to) VALUES ({$newid},{$oldid})"; @@ -1140,5 +1174,84 @@ class Title { return true; } + # Get categories to wich belong this title and return an array of + # categories names. + function getParentCategories( ) + { + global $wgLang,$wgUser; + + #$titlekey = wfStrencode( $this->getArticleID() ); + $titlekey = $this->getArticleId(); + $cns = Namespace::getCategory(); + $sk =& $wgUser->getSkin(); + $parents = array(); + + # get the parents categories of this title from the database + $sql = "SELECT DISTINCT cur_id FROM cur,categorylinks + WHERE cl_from='$titlekey' AND cl_to=cur_title AND cur_namespace='$cns' + ORDER BY cl_sortkey" ; + $res = wfQuery ( $sql, DB_READ ) ; + + if(wfNumRows($res) > 0) { + while ( $x = wfFetchObject ( $res ) ) $data[] = $x ; + wfFreeResult ( $res ) ; + } else { + $data = ''; + } + return $data; + } + + # will get the parents and grand-parents + # TODO : not sure what's happening when a loop happen like: + # Encyclopedia > Astronomy > Encyclopedia + function getAllParentCategories(&$stack) + { + global $wgUser,$wgLang; + $result = ''; + + # getting parents + $parents = $this->getParentCategories( ); + + if($parents == '') + { + # The current element has no more parent so we dump the stack + # and make a clean line of categories + $sk =& $wgUser->getSkin() ; + + foreach ( array_reverse($stack) as $child => $parent ) + { + # make a link of that parent + $result .= $sk->makeLink($wgLang->getNSText ( Namespace::getCategory() ).":".$parent,$parent); + $result .= ' > '; + $lastchild = $child; + } + # append the last child. + # TODO : We should have a last child unless there is an error in the + # "categorylinks" table. + if(isset($lastchild)) { $result .= $lastchild; } + + $result .= "<br/>\n"; + + # now we can empty the stack + $stack = array(); + + } else { + # look at parents of current category + foreach($parents as $parent) + { + # create a title object for the parent + $tpar = Title::newFromID($parent->cur_id); + # add it to the stack + $stack[$this->getText()] = $tpar->getText(); + # grab its parents + $result .= $tpar->getAllParentCategories($stack); + } + } + + if(isset($result)) { return $result; } + else { return ''; }; + } + + } ?> diff --git a/includes/Tokenizer.php b/includes/Tokenizer.php index ab18b106dbde..129d5e09313b 100644 --- a/includes/Tokenizer.php +++ b/includes/Tokenizer.php @@ -18,7 +18,7 @@ class Tokenizer { # factory function function newFromString( $s ) { - $fname = "Tokenizer::newFromString"; + $fname = 'Tokenizer::newFromString'; wfProfileIn( $fname ); $t = new Tokenizer(); @@ -37,7 +37,7 @@ class Tokenizer { // the stored token. function previewToken() { - $fname = "Tokenizer::previewToken"; + $fname = 'Tokenizer::previewToken'; wfProfileIn( $fname ); if ( count( $this->mQueuedToken ) != 0 ) { @@ -60,7 +60,7 @@ class Tokenizer { // TODO: handling of French blanks not yet implemented function nextToken() { - $fname = "Tokenizer::nextToken"; + $fname = 'Tokenizer::nextToken'; wfProfileIn( $fname ); if ( count( $this->mQueuedToken ) != 0 ) { @@ -71,48 +71,48 @@ class Tokenizer { $token = false; } else { - $token["text"]=""; - $token["type"]="text"; + $token['text']=''; + $token['type']='text'; while ( $this->mPos <= $this->mTextLength ) { switch ( @$ch = $this->mText[$this->mPos] ) { case 'R': // for "RFC " - if ( $this->continues("FC ") ) { - $queueToken["type"] = $queueToken["text"] = "RFC "; + if ( $this->continues('FC ') ) { + $queueToken['type'] = $queueToken['text'] = 'RFC '; $this->mQueuedToken[] = $queueToken; $this->mPos += 3; break 2; // switch + while } break; case 'I': // for "ISBN " - if ( $this->continues("SBN ") ) { - $queueToken["type"] = $queueToken["text"] = "ISBN "; + if ( $this->continues('SBN ') ) { + $queueToken['type'] = $queueToken['text'] = 'ISBN '; $this->mQueuedToken[] = $queueToken; $this->mPos += 4; break 2; // switch + while } break; - case "[": // for links "[[" - if ( $this->continues("[[") ) { - $queueToken["type"] = "[[["; - $queueToken["text"] = ""; + case '[': // for links "[[" + if ( $this->continues('[[') ) { + $queueToken['type'] = '[[['; + $queueToken['text'] = ''; $this->mQueuedToken[] = $queueToken; $this->mPos += 3; break 2; // switch + while - } else if ( $this->continues("[") ) { - $queueToken["type"] = "[["; - $queueToken["text"] = ""; + } else if ( $this->continues('[') ) { + $queueToken['type'] = '[['; + $queueToken['text'] = ''; // Check for a "prefixed link", e.g. Al[[Khazar]] // Mostly for arabic wikipedia if ( $this->linkPrefixExtension ) { while ( $this->linkPrefixExtension - && ($len = strlen( $token["text"] ) ) > 0 - && !ctype_space( $token["text"][$len-1] ) ) + && ($len = strlen( $token['text'] ) ) > 0 + && !ctype_space( $token['text'][$len-1] ) ) { //prepend the character to the link's open tag - $queueToken["text"] = $token["text"][$len-1] . $queueToken["text"]; + $queueToken['text'] = $token['text'][$len-1] . $queueToken['text']; //remove character from the end of the text token - $token["text"] = substr( $token["text"], 0, -1); + $token['text'] = substr( $token['text'], 0, -1); } } $this->mQueuedToken[] = $queueToken; @@ -120,10 +120,10 @@ class Tokenizer { break 2; // switch + while } break; - case "]": // for end of links "]]" - if ( $this->continues("]") ) { - $queueToken["type"] = "]]"; - $queueToken["text"] = ""; + case ']': // for end of links "]]" + if ( $this->continues(']') ) { + $queueToken['type'] = ']]'; + $queueToken['text'] = ''; $this->mQueuedToken[] = $queueToken; $this->mPos += 2; break 2; // switch + while @@ -131,13 +131,13 @@ class Tokenizer { break; case "'": // for all kind of em's and strong's if ( $this->continues("'") ) { - $queueToken["type"] = "'"; - $queueToken["text"] = ""; + $queueToken['type'] = "'"; + $queueToken['text'] = ''; while( ($this->mPos+1 < $this->mTextLength) && $this->mText[$this->mPos+1] == "'" ) { - $queueToken["type"] .= "'"; - $queueToken["pos"] = $this->mPos; + $queueToken['type'] .= "'"; + $queueToken['pos'] = $this->mPos; $this->mPos ++; } @@ -148,65 +148,65 @@ class Tokenizer { break; case "\n": // for block levels, actually, only "----" is handled. case "\r": // headings are detected to close any unbalanced em or strong tags in a section - if ( $this->continues( "----" ) ) + if ( $this->continues( '----' ) ) { - $queueToken["type"] = "----"; - $queueToken["text"] = ""; + $queueToken['type'] = '----'; + $queueToken['text'] = ''; $this->mQueuedToken[] = $queueToken; $this->mPos += 5; while ( $this->mPos<$this->mTextLength - and $this->mText[$this->mPos] == "-" ) + and $this->mText[$this->mPos] == '-' ) { $this->mPos ++; } break 2; } else if ( - $this->continues( "<h" ) and ( - $this->continues( "<h1" ) or - $this->continues( "<h2" ) or - $this->continues( "<h3" ) or - $this->continues( "<h4" ) or - $this->continues( "<h5" ) or - $this->continues( "<h6" ) + $this->continues( '<h' ) and ( + $this->continues( '<h1' ) or + $this->continues( '<h2' ) or + $this->continues( '<h3' ) or + $this->continues( '<h4' ) or + $this->continues( '<h5' ) or + $this->continues( '<h6' ) ) ) { // heading - $queueToken["type"] = "h"; - $queueToken["text"] = ""; + $queueToken['type'] = 'h'; + $queueToken['text'] = ''; $this->mQueuedToken[] = $queueToken; $this->mPos ++; break 2; // switch + while } break; - case "!": // French spacing rules have a space before exclamation - case "?": // and question marks. Those have to become - case ":": // And colons, Hashar says ... - if ( $this->preceeded( " " ) ) + case '!': // French spacing rules have a space before exclamation + case '?': // and question marks. Those have to become + case ':': // And colons, Hashar says ... + if ( $this->preceeded( ' ' ) ) { // strip blank from Token - $token["text"] = substr( $token["text"], 0, -1 ); - $queueToken["type"] = "blank"; - $queueToken["text"] = " {$ch}"; + $token['text'] = substr( $token['text'], 0, -1 ); + $queueToken['type'] = 'blank'; + $queueToken['text'] = " {$ch}"; $this->mQueuedToken[] = $queueToken; $this->mPos ++; break 2; // switch + while } break; - case "0": // A space between two numbers is used to ease reading - case "1": // of big numbers, e.g. 1 000 000. Those spaces need - case "2": // to be unbreakable - case "3": - case "4": - case "5": - case "6": - case "7": - case "8": - case "9": + case '0': // A space between two numbers is used to ease reading + case '1': // of big numbers, e.g. 1 000 000. Those spaces need + case '2': // to be unbreakable + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': if ( ($this->mTextLength >= $this->mPos +2) && ($this->mText[$this->mPos+1] == " ") && ctype_digit( $this->mText[$this->mPos+2] ) ) { - $queueToken["type"] = "blank"; - $queueToken["text"] = $ch . " "; + $queueToken['type'] = 'blank'; + $queueToken['text'] = $ch . ' '; $this->mQueuedToken[] = $queueToken; $this->mPos += 2; break 2; // switch + while @@ -215,8 +215,8 @@ class Tokenizer { case "\302": // first byte of UTF-8 Character Guillemet-left if ( $this->continues( "\253 ") ) // second byte and a blank { - $queueToken["type"] = "blank"; - $queueToken["text"] = "\302\253 "; + $queueToken['type'] = 'blank'; + $queueToken['text'] = "\302\253 "; $this->mQueuedToken[] = $queueToken; $this->mPos += 3; break 2; // switch + while @@ -225,20 +225,20 @@ class Tokenizer { case "\273": //last byte of UTF-8 Character Guillemet-right if ( $this->preceeded( " \302" ) ) { - $queueToken["type"] = "blank"; - $queueToken["text"] = " \302\273"; - $token["text"] = substr( $token["text"], 0, -2 ); + $queueToken['type'] = 'blank'; + $queueToken['text'] = " \302\273"; + $token['text'] = substr( $token['text'], 0, -2 ); $this->mQueuedToken[] = $queueToken; $this->mPos ++; break 2; // switch + while } break; - case "&": //extensions like <timeline>, since HTML stripping has already been done, + case '&': //extensions like <timeline>, since HTML stripping has already been done, //those look like <timeline> if ( $this->continues( "lt;timeline>" ) ) { - $queueToken["type"] = "<timeline>"; - $queueToken["text"] = "<timeline>"; + $queueToken['type'] = "<timeline>"; + $queueToken['text'] = "<timeline>"; $this->mQueuedToken[] = $queueToken; $this->mPos += 16; break 2; // switch + while @@ -246,7 +246,7 @@ class Tokenizer { break; } /* switch */ - $token["text"].=$ch; + $token['text'].=$ch; $this->mPos ++; // echo $this->mPos . "<br>\n"; } /* while */ @@ -286,11 +286,10 @@ class Tokenizer { { $n = strpos( $this->mText, $border, $this->mPos ); if ( $n === false ) - return ""; + return ''; $ret = substr( $this->mText, $this->mPos, $n - $this->mPos ); $this->mPos = $n + strlen( $border ) + 1; return $ret; } } - diff --git a/includes/User.php b/includes/User.php index 111bebff1a78..2a06936a04aa 100644 --- a/includes/User.php +++ b/includes/User.php @@ -1,7 +1,7 @@ <?php # See user.doc -require_once( "WatchedItem.php" ); +require_once( 'WatchedItem.php' ); class User { /* private */ var $mId, $mName, $mPassword, $mEmail, $mNewtalk; @@ -13,15 +13,13 @@ class User { /* private */ var $mCookiePassword; /* private */ var $mRealName; - function User() - { + function User() { $this->loadDefaults(); } # Static factory method # - function newFromName( $name ) - { + function newFromName( $name ) { $u = new User(); # Clean up name according to title rules @@ -31,18 +29,15 @@ class User { return $u; } - /* static */ function whoIs( $id ) - { - return wfGetSQL( "user", "user_name", "user_id=$id" ); + /* static */ function whoIs( $id ) { + return wfGetSQL( 'user', 'user_name', 'user_id='.$id ); } - /* static */ function whoIsReal( $id ) - { - return wfGetSQL( "user", "user_real_name", "user_id=$id" ); + /* static */ function whoIsReal( $id ) { + return wfGetSQL( 'user', 'user_real_name', 'user_id='.$id ); } - /* static */ function idFromName( $name ) - { + /* static */ function idFromName( $name ) { $nt = Title::newFromText( $name ); if( is_null( $nt ) ) { # Illegal name @@ -50,7 +45,7 @@ class User { } $sql = "SELECT user_id FROM user WHERE user_name='" . wfStrencode( $nt->getText() ) . "'"; - $res = wfQuery( $sql, DB_READ, "User::idFromName" ); + $res = wfQuery( $sql, DB_READ, 'User::idFromName' ); if ( 0 == wfNumRows( $res ) ) { return 0; @@ -67,9 +62,8 @@ class User { } - /* static */ function randomPassword() - { - $pwchars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"; + /* static */ function randomPassword() { + $pwchars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz'; $l = strlen( $pwchars ) - 1; wfSeedRandom(); @@ -80,33 +74,32 @@ class User { return $np; } - function loadDefaults() - { + function loadDefaults() { global $wgLang, $wgIP; global $wgNamespacesToBeSearchedDefault; $this->mId = $this->mNewtalk = 0; $this->mName = $wgIP; - $this->mEmail = ""; - $this->mPassword = $this->mNewpassword = ""; + $this->mEmail = ''; + $this->mPassword = $this->mNewpassword = ''; $this->mRights = array(); $defOpt = $wgLang->getDefaultUserOptions() ; foreach ( $defOpt as $oname => $val ) { $this->mOptions[$oname] = $val; } foreach ($wgNamespacesToBeSearchedDefault as $nsnum => $val) { - $this->mOptions["searchNs".$nsnum] = $val; + $this->mOptions['searchNs'.$nsnum] = $val; } unset( $this->mSkin ); $this->mDataLoaded = false; $this->mBlockedby = -1; # Unset $this->mTouched = '0'; # Allow any pages to be cached - $this->cookiePassword = ""; + $this->cookiePassword = ''; } /* private */ function getBlockedStatus() { - global $wgIP, $wgBlockCache; + global $wgIP, $wgBlockCache, $wgProxyList; if ( -1 != $this->mBlockedby ) { return; } @@ -129,12 +122,20 @@ class User { $this->mBlockreason = $block->mReason; } } + + # Proxy blocking + if ( !$this->mBlockedby ) { + if ( array_key_exists( $wgIP, $wgProxyList ) ) { + $this->mBlockreason = wfMsg( 'proxyblockreason' ); + $this->mBlockedby = "Proxy blocker"; + } + } } function isBlocked() { $this->getBlockedStatus(); - if ( 0 == $this->mBlockedby ) { return false; } + if ( 0 === $this->mBlockedby ) { return false; } return true; } @@ -151,10 +152,10 @@ class User { function SetupSession() { global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain; if( $wgSessionsInMemcached ) { - require_once( "MemcachedSessions.php" ); + require_once( 'MemcachedSessions.php' ); } session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain ); - session_cache_limiter( "private, must-revalidate" ); + session_cache_limiter( 'private, must-revalidate' ); @session_start(); } @@ -290,14 +291,12 @@ class User { return $this->mName; } - function setName( $str ) - { + function setName( $str ) { $this->loadFromDatabase(); $this->mName = $str; } - function getNewtalk() - { + function getNewtalk() { $this->loadFromDatabase(); return ( 0 != $this->mNewtalk ); } @@ -321,20 +320,17 @@ class User { return ($timestamp >= $this->mTouched); } - function getPassword() - { + function getPassword() { $this->loadFromDatabase(); return $this->mPassword; } - function getNewpassword() - { + function getNewpassword() { $this->loadFromDatabase(); return $this->mNewpassword; } - function addSalt( $p ) - { + function addSalt( $p ) { global $wgPasswordSalt; if($wgPasswordSalt) return md5( "{$this->mId}-{$p}" ); @@ -342,67 +338,57 @@ class User { return $p; } - function encryptPassword( $p ) - { + function encryptPassword( $p ) { return $this->addSalt( md5( $p ) ); } - function setPassword( $str ) - { + function setPassword( $str ) { $this->loadFromDatabase(); $this->setCookiePassword( $str ); $this->mPassword = $this->encryptPassword( $str ); - $this->mNewpassword = ""; + $this->mNewpassword = ''; } - function setCookiePassword( $str ) - { + function setCookiePassword( $str ) { $this->loadFromDatabase(); $this->mCookiePassword = md5( $str ); } - function setNewpassword( $str ) - { + function setNewpassword( $str ) { $this->loadFromDatabase(); $this->mNewpassword = $this->encryptPassword( $str ); } - function getEmail() - { + function getEmail() { $this->loadFromDatabase(); return $this->mEmail; } - function setEmail( $str ) - { + function setEmail( $str ) { $this->loadFromDatabase(); $this->mEmail = $str; } - function getRealName() - { + function getRealName() { $this->loadFromDatabase(); return $this->mRealName; } - function setRealName( $str ) - { + function setRealName( $str ) { $this->loadFromDatabase(); $this->mRealName = $str; } - function getOption( $oname ) - { + function getOption( $oname ) { $this->loadFromDatabase(); if ( array_key_exists( $oname, $this->mOptions ) ) { return $this->mOptions[$oname]; } else { - return ""; + return ''; } } - function setOption( $oname, $val ) - { + function setOption( $oname, $val ) { $this->loadFromDatabase(); if ( $oname == 'skin' ) { # Clear cached skin, so the new one displays immediately in Special:Preferences @@ -412,73 +398,93 @@ class User { $this->invalidateCache(); } - function getRights() - { + function getRights() { $this->loadFromDatabase(); return $this->mRights; } - function addRight( $rname ) - { + function addRight( $rname ) { $this->loadFromDatabase(); array_push( $this->mRights, $rname ); $this->invalidateCache(); } - function isSysop() - { + function isSysop() { $this->loadFromDatabase(); if ( 0 == $this->mId ) { return false; } - return in_array( "sysop", $this->mRights ); + return in_array( 'sysop', $this->mRights ); } - function isDeveloper() - { + function isDeveloper() { $this->loadFromDatabase(); if ( 0 == $this->mId ) { return false; } - return in_array( "developer", $this->mRights ); + return in_array( 'developer', $this->mRights ); } - function isBureaucrat() - { + function isBureaucrat() { $this->loadFromDatabase(); if ( 0 == $this->mId ) { return false; } - return in_array( "bureaucrat", $this->mRights ); + return in_array( 'bureaucrat', $this->mRights ); } - function isBot() - { + function isBot() { $this->loadFromDatabase(); # Why was this here? I need a UID=0 conversion script [TS] # if ( 0 == $this->mId ) { return false; } - return in_array( "bot", $this->mRights ); + return in_array( 'bot', $this->mRights ); } - function &getSkin() - { + function &getSkin() { if ( ! isset( $this->mSkin ) ) { + # get all skin names available from SkinNames.php $skinNames = Skin::getSkinNames(); - $s = $this->getOption( "skin" ); - if ( "" == $s ) { $s = 'standard'; } - - if ( !isset( $skinNames[$s] ) ) { + # get the user skin + $userSkin = $this->getOption( 'skin' ); + if ( $userSkin == '' ) { $userSkin = 'standard'; } + + if ( !isset( $skinNames[$userSkin] ) ) { + # in case the user skin could not be found find a replacement $fallback = array( - 'standard' => "Standard", - 'nostalgia' => "Nostalgia", - 'cologneblue' => "Cologne Blue"); - if(is_int($s) && isset( $fallback[$s]) ){ - $sn = $fallback[$s]; + 0 => 'SkinStandard', + 1 => 'SkinNostalgia', + 2 => 'SkinCologneBlue'); + # if phptal is enabled we should have monobook skin that superseed + # the good old SkinStandard. + if ( isset( $skinNames['monobook'] ) ) { + $fallback[0] = 'SkinMonoBook'; + } + + if(is_numeric($userSkin) && isset( $fallback[$userSkin]) ){ + $sn = $fallback[$userSkin]; } else { - $sn = "SkinStandard"; + $sn = 'SkinStandard'; } } else { - $sn = "Skin" . $skinNames[$s]; + # The user skin is available + $sn = 'Skin' . $skinNames[$userSkin]; + } + + # only require the needed stuff + switch($sn) { + case 'SkinMonoBook': + require_once( 'SkinPHPTal.php' ); + break; + case 'SkinStandard': + require_once( 'SkinStandard.php' ); + break; + case 'SkinNostalgia': + require_once( 'SkinNostalgia.php' ); + break; + case 'SkinCologneBlue': + require_once( 'SkinCologneBlue.php' ); + break; } + # now we can create the skin object $this->mSkin = new $sn; } return $this->mSkin; @@ -502,18 +508,16 @@ class User { } - /* private */ function encodeOptions() - { + /* private */ function encodeOptions() { $a = array(); foreach ( $this->mOptions as $oname => $oval ) { - array_push( $a, "{$oname}={$oval}" ); + array_push( $a, $oname.'='.$oval ); } $s = implode( "\n", $a ); return wfStrencode( $s ); } - /* private */ function decodeOptions( $str ) - { + /* private */ function decodeOptions( $str ) { $a = explode( "\n", $str ); foreach ( $a as $s ) { if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) { @@ -522,40 +526,37 @@ class User { } } - function setCookies() - { + function setCookies() { global $wgCookieExpiration, $wgCookiePath, $wgCookieDomain, $wgDBname; if ( 0 == $this->mId ) return; $this->loadFromDatabase(); $exp = time() + $wgCookieExpiration; $_SESSION['wsUserID'] = $this->mId; - setcookie( "{$wgDBname}UserID", $this->mId, $exp, $wgCookiePath, $wgCookieDomain ); + setcookie( $wgDBname.'UserID', $this->mId, $exp, $wgCookiePath, $wgCookieDomain ); $_SESSION['wsUserName'] = $this->mName; - setcookie( "{$wgDBname}UserName", $this->mName, $exp, $wgCookiePath, $wgCookieDomain ); + setcookie( $wgDBname.'UserName', $this->mName, $exp, $wgCookiePath, $wgCookieDomain ); $_SESSION['wsUserPassword'] = $this->mPassword; - if ( 1 == $this->getOption( "rememberpassword" ) ) { - setcookie( "{$wgDBname}Password", $this->mCookiePassword, $exp, $wgCookiePath, $wgCookieDomain ); + if ( 1 == $this->getOption( 'rememberpassword' ) ) { + setcookie( $wgDBname.'Password', $this->mCookiePassword, $exp, $wgCookiePath, $wgCookieDomain ); } else { - setcookie( "{$wgDBname}Password", "", time() - 3600 ); + setcookie( $wgDBname.'Password', '', time() - 3600 ); } } - function logout() - { + function logout() { global $wgCookiePath, $wgCookieDomain, $wgDBname; $this->mId = 0; $_SESSION['wsUserID'] = 0; - setcookie( "{$wgDBname}UserID", "", time() - 3600, $wgCookiePath, $wgCookieDomain ); - setcookie( "{$wgDBname}Password", "", time() - 3600, $wgCookiePath, $wgCookieDomain ); + setcookie( $wgDBname.'UserID', '', time() - 3600, $wgCookiePath, $wgCookieDomain ); + setcookie( $wgDBname.'Password', '', time() - 3600, $wgCookiePath, $wgCookieDomain ); } - function saveSettings() - { + function saveSettings() { global $wgMemc, $wgDBname; if ( ! $this->mNewtalk ) { @@ -586,11 +587,10 @@ class User { # Checks if a user with the given name exists # - function idForName() - { + function idForName() { $gotid = 0; $s = trim( $this->mName ); - if ( 0 == strcmp( "", $s ) ) return 0; + if ( 0 == strcmp( '', $s ) ) return 0; $sql = "SELECT user_id FROM user WHERE user_name='" . wfStrencode( $s ) . "'"; @@ -598,15 +598,14 @@ class User { if ( 0 == wfNumRows( $res ) ) { return 0; } $s = wfFetchObject( $res ); - if ( "" == $s ) return 0; + if ( '' == $s ) return 0; $gotid = $s->user_id; wfFreeResult( $res ); return $gotid; } - function addToDatabase() - { + function addToDatabase() { $sql = "INSERT INTO user (user_name,user_password,user_newpassword," . "user_email, user_real_name, user_rights, user_options) " . " VALUES ('" . wfStrencode( $this->mName ) . "', '" . @@ -614,7 +613,7 @@ class User { wfStrencode( $this->mNewpassword ) . "', '" . wfStrencode( $this->mEmail ) . "', '" . wfStrencode( $this->mRealName ) . "', '" . - wfStrencode( implode( ",", $this->mRights ) ) . "', '" . + wfStrencode( implode( ',', $this->mRights ) ) . "', '" . $this->encodeOptions() . "')"; wfQuery( $sql, DB_WRITE, "User::addToDatabase" ); $this->mId = $this->idForName(); @@ -625,14 +624,14 @@ class User { global $wgIP; # If the (non-anonymous) user is blocked, this function will block any IP address # that they successfully log on from. - $fname = "User::spreadBlock"; + $fname = 'User::spreadBlock'; wfDebug( "User:spreadBlock()\n" ); if ( $this->mId == 0 ) { return; } - $userblock = Block::newFromDB( "", $this->mId ); + $userblock = Block::newFromDB( '', $this->mId ); if ( !$userblock->isValid() ) { return; } @@ -646,11 +645,11 @@ class User { } # Make a new block object with the desired properties - wfDebug( "Autoblocking {$this->mUserName}@{$wgIP}\n" ); + wfDebug( "Autoblocking {$this->mName}@{$wgIP}\n" ); $ipblock->mAddress = $wgIP; $ipblock->mUser = 0; $ipblock->mBy = $userblock->mBy; - $ipblock->mReason = wfMsg( "autoblocker", $this->getName(), $userblock->mReason ); + $ipblock->mReason = wfMsg( 'autoblocker', $this->getName(), $userblock->mReason ); $ipblock->mTimestamp = wfTimestampNow(); $ipblock->mAuto = 1; # If the user is already blocked with an expiry date, we don't @@ -675,17 +674,17 @@ class User { // stubthreshold is only included below for completeness, // it will always be 0 when this function is called by parsercache. - $confstr = $this->getOption( "quickbar" ); - $confstr .= "!" . $this->getOption( "underline" ); - $confstr .= "!" . $this->getOption( "hover" ); - $confstr .= "!" . $this->getOption( "skin" ); - $confstr .= "!" . $this->getOption( "math" ); - $confstr .= "!" . $this->getOption( "highlightbroken" ); - $confstr .= "!" . $this->getOption( "stubthreshold" ); - $confstr .= "!" . $this->getOption( "editsection" ); - $confstr .= "!" . $this->getOption( "editsectiononrightclick" ); - $confstr .= "!" . $this->getOption( "showtoc" ); - $confstr .= "!" . $this->getOption( "date" ); + $confstr = $this->getOption( 'quickbar' ); + $confstr .= '!' . $this->getOption( 'underline' ); + $confstr .= '!' . $this->getOption( 'hover' ); + $confstr .= '!' . $this->getOption( 'skin' ); + $confstr .= '!' . $this->getOption( 'math' ); + $confstr .= '!' . $this->getOption( 'highlightbroken' ); + $confstr .= '!' . $this->getOption( 'stubthreshold' ); + $confstr .= '!' . $this->getOption( 'editsection' ); + $confstr .= '!' . $this->getOption( 'editsectiononrightclick' ); + $confstr .= '!' . $this->getOption( 'showtoc' ); + $confstr .= '!' . $this->getOption( 'date' ); if(strlen($confstr) > 32) $hash = md5($confstr); @@ -694,14 +693,13 @@ class User { return $hash; } - function isAllowedToCreateAccount() - { + function isAllowedToCreateAccount() { global $wgWhitelistAccount; $allowed = false; if (!$wgWhitelistAccount) { return 1; }; // default behaviour foreach ($wgWhitelistAccount as $right => $ok) { - $userHasRight = (!strcmp($right, "user") || in_array($right, $this->getRights())); + $userHasRight = (!strcmp($right, 'user') || in_array($right, $this->getRights())); $allowed |= ($ok && $userHasRight); } return $allowed; @@ -717,6 +715,15 @@ class User { function getUserPage() { return Title::makeTitle( NS_USER, $this->mName ); } + + /* static */ function getMaxID() { + $row = wfGetArray( 'user', array('max(user_id) as m'), false ); + return $row->m; + } + + function isNewbie() { + return $this->mId > User::getMaxID() * 0.99 && !$this->isSysop() || $this->getID() == 0; + } } ?> diff --git a/includes/UserTalkUpdate.php b/includes/UserTalkUpdate.php index 306cd3c80d81..66ea7a9aee25 100644 --- a/includes/UserTalkUpdate.php +++ b/includes/UserTalkUpdate.php @@ -33,6 +33,7 @@ class UserTalkUpdate { } else { # Not ours. If writing, mark it as modified. + $sql = false; if ( 1 == $this->mAction ) { $user = new User(); $user->setID(User::idFromName($this->mTitle)); diff --git a/includes/ViewCountUpdate.php b/includes/ViewCountUpdate.php index 84a03991f8ce..16976f11b0f2 100644 --- a/includes/ViewCountUpdate.php +++ b/includes/ViewCountUpdate.php @@ -1,6 +1,6 @@ <?php +# $Id$ # See deferred.doc - class ViewCountUpdate { var $mPageID; @@ -12,13 +12,12 @@ class ViewCountUpdate { function doUpdate() { - global $wgDisableCounters; + global $wgDisableCounters, $wgIsMySQL; if ( $wgDisableCounters ) { return; } - - $sql = "UPDATE LOW_PRIORITY cur SET cur_counter=(1+cur_counter)," . + $lowpri=$wgIsMySQL?"LOW_PRIORITY":""; + $sql = "UPDATE $lowpri cur SET cur_counter=(1+cur_counter)," . "cur_timestamp=cur_timestamp WHERE cur_id={$this->mPageID}"; $res = wfQuery( $sql, DB_WRITE, "ViewCountUpdate::doUpdate" ); } } - ?> diff --git a/includes/WatchedItem.php b/includes/WatchedItem.php index 74371be4bf25..23ad2804e1de 100644 --- a/includes/WatchedItem.php +++ b/includes/WatchedItem.php @@ -36,10 +36,22 @@ class WatchedItem { function addWatch() { + global $wgIsMySQL; # REPLACE instead of INSERT because occasionally someone # accidentally reloads a watch-add operation. - $sql = "REPLACE INTO watchlist (wl_user, wl_namespace,wl_title) VALUES ($this->id,$this->ns,'$this->eti')"; - $res = wfQuery( $sql, DB_WRITE ); + if ($wgIsMySQL) { + $sql = "REPLACE INTO watchlist (wl_user, wl_namespace,wl_title) ". + "VALUES ($this->id,$this->ns,'$this->eti')"; + $res = wfQuery( $sql, DB_WRITE ); + } else { + $sql = "DELETE FROM watchlist WHERE wl_user=$this->id AND + wl_namespace=$this->ns AND wl_title='$this->eti'"; + wfQuery( $sql, DB_WRITE); + $sql = "INSERT INTO watchlist (wl_user, wl_namespace,wl_title) ". + "VALUES ($this->id,$this->ns,'$this->eti')"; + $res = wfQuery( $sql, DB_WRITE ); + } + if( $res === false ) return false; global $wgMemc; @@ -49,7 +61,7 @@ class WatchedItem { function removeWatch() { - $sql = "DELETE FROM watchlist WHERE wl_user=$this->id AND wl_namespace=$this->ns AND wl_title='$this->eti' LIMIT 1"; + $sql = "DELETE FROM watchlist WHERE wl_user=$this->id AND wl_namespace=$this->ns AND wl_title='$this->eti'"; $res = wfQuery( $sql, DB_WRITE ); if( $res === false ) return false; diff --git a/includes/memcached-client.php b/includes/memcached-client.php index 3f0eb44f9e0f..17d9ecbecd3d 100644 --- a/includes/memcached-client.php +++ b/includes/memcached-client.php @@ -667,7 +667,7 @@ class memcached function _dead_sock ($sock) { $host = array_search($sock, $this->_cache_sock); - list ($ip, $port) = explode(":", $host); + @list ($ip, $port) = explode(":", $host); $this->_host_dead[$ip] = time() + 30 + intval(rand(0, 10)); $this->_host_dead[$host] = $this->_host_dead[$ip]; unset($this->_cache_sock[$host]); @@ -737,13 +737,7 @@ class memcached */ function _hashfunc ($key) { - $hash = 0; - for ($i=0; $i<strlen($key); $i++) - { - $hash = $hash*33 + ord($key[$i]); - } - - return $hash; + return crc32($key); } // }}} |