Index: branches/stable/phase3/includes/User.php |
— | — | @@ -282,7 +282,11 @@ |
283 | 283 | |
284 | 284 | function addSalt( $p ) |
285 | 285 | { |
286 | | - return md5( "{$this->mId}-{$p}" ); |
| 286 | + global $wgPasswordSalt; |
| 287 | + if($wgPasswordSalt) |
| 288 | + return md5( "{$this->mId}-{$p}" ); |
| 289 | + else |
| 290 | + return $p; |
287 | 291 | } |
288 | 292 | |
289 | 293 | function encryptPassword( $p ) |
Index: branches/stable/phase3/includes/Article.php |
— | — | @@ -2,6 +2,8 @@ |
3 | 3 | # Class representing a Wikipedia article and history. |
4 | 4 | # See design.doc for an overview. |
5 | 5 | |
| 6 | +include_once( "CacheManager.php" ); |
| 7 | + |
6 | 8 | class Article { |
7 | 9 | /* private */ var $mContent, $mContentLoaded; |
8 | 10 | /* private */ var $mUser, $mTimestamp, $mUserText; |
— | — | @@ -1623,15 +1625,25 @@ |
1624 | 1626 | |
1625 | 1627 | /* Caching functions */ |
1626 | 1628 | |
1627 | | - function tryFileCache() { |
| 1629 | + function tryFileCache() { |
| 1630 | + global $wgTitle; |
| 1631 | + |
1628 | 1632 | if($this->isFileCacheable()) { |
1629 | | - if($this->isFileCacheGood()) { |
1630 | | - wfDebug( " tryFileCache() - about to load\n" ); |
1631 | | - $this->loadFromFileCache(); |
| 1633 | + $cache = new CacheManager( $wgTitle ); |
| 1634 | + if($cache->isFileCacheGood( $this->mTouched )) { |
| 1635 | + wfDebug( " tryFileCache() - about to load\n" ); |
| 1636 | + $cache->loadFromFileCache(); |
1632 | 1637 | exit; |
1633 | 1638 | } else { |
1634 | | - wfDebug( " tryFileCache() - starting buffer\n" ); |
1635 | | - ob_start( array(&$this, 'saveToFileCache' ) ); |
| 1639 | + wfDebug( " tryFileCache() - starting buffer\n" ); |
| 1640 | + if($cache->useGzip() && wfClientAcceptsGzip()) { |
| 1641 | + /* For some reason, adding this header line over in |
| 1642 | + CacheManager::saveToFileCache() fails on my test |
| 1643 | + setup at home, though it works on the live install. |
| 1644 | + Make double-sure... --brion */ |
| 1645 | + header( "Content-Encoding: gzip" ); |
| 1646 | + } |
| 1647 | + ob_start( array(&$cache, 'saveToFileCache' ) ); |
1636 | 1648 | } |
1637 | 1649 | } else { |
1638 | 1650 | wfDebug( " tryFileCache() - not cacheable\n" ); |
— | — | @@ -1652,104 +1664,8 @@ |
1653 | 1665 | and (!isset($redirect)) |
1654 | 1666 | and (!isset($printable)) |
1655 | 1667 | and (!$this->mRedirectedFrom); |
1656 | | - |
1657 | 1668 | } |
1658 | | - |
1659 | | - function fileCacheName() { |
1660 | | - global $wgTitle, $wgFileCacheDirectory, $wgLang; |
1661 | | - if( !$this->mFileCache ) { |
1662 | | - $hash = md5( $key = $wgTitle->getDbkey() ); |
1663 | | - if( $wgTitle->getNamespace() ) |
1664 | | - $key = $wgLang->getNsText( $wgTitle->getNamespace() ) . ":" . $key; |
1665 | | - $key = str_replace( ".", "%2E", urlencode( $key ) ); |
1666 | | - $hash1 = substr( $hash, 0, 1 ); |
1667 | | - $hash2 = substr( $hash, 0, 2 ); |
1668 | | - $this->mFileCache = "{$wgFileCacheDirectory}/{$hash1}/{$hash2}/{$key}.html"; |
1669 | | - wfDebug( " fileCacheName() - {$this->mFileCache}\n" ); |
1670 | | - } |
1671 | | - return $this->mFileCache; |
1672 | | - } |
1673 | 1669 | |
1674 | | - function isFileCacheGood() { |
1675 | | - global $wgUser, $wgCacheEpoch; |
1676 | | - if(!file_exists( $fn = $this->fileCacheName() ) ) return false; |
1677 | | - $cachetime = wfUnix2Timestamp( filemtime( $fn ) ); |
1678 | | - $good = (( $this->mTouched <= $cachetime ) && |
1679 | | - ($wgCacheEpoch <= $cachetime )); |
1680 | | - wfDebug(" isFileCacheGood() - cachetime $cachetime, touched {$this->mTouched} epoch {$wgCacheEpoch}, good $good\n"); |
1681 | | - return $good; |
1682 | | - } |
1683 | | - |
1684 | | - function loadFromFileCache() { |
1685 | | - global $wgUseGzip, $wgOut; |
1686 | | - wfDebug(" loadFromFileCache()\n"); |
1687 | | - $filename=$this->fileCacheName(); |
1688 | | - $filenamegz = "{$filename}.gz"; |
1689 | | - $wgOut->sendCacheControl(); |
1690 | | - if( $wgUseGzip |
1691 | | - && wfClientAcceptsGzip() |
1692 | | - && file_exists( $filenamegz) |
1693 | | - && ( filemtime( $filenamegz ) >= filemtime( $filename ) ) ) { |
1694 | | - wfDebug(" sending gzip\n"); |
1695 | | - header( "Content-Encoding: gzip" ); |
1696 | | - header( "Vary: Accept-Encoding" ); |
1697 | | - $filename = $filenamegz; |
1698 | | - } |
1699 | | - readfile( $filename ); |
1700 | | - } |
1701 | | - |
1702 | | - function saveToFileCache( $text ) { |
1703 | | - global $wgUseGzip, $wgCompressByDefault; |
1704 | | - if(strcmp($text,"") == 0) return ""; |
1705 | | - |
1706 | | - wfDebug(" saveToFileCache()\n", false); |
1707 | | - $filename=$this->fileCacheName(); |
1708 | | - $mydir2=substr($filename,0,strrpos($filename,"/")); # subdirectory level 2 |
1709 | | - $mydir1=substr($mydir2,0,strrpos($mydir2,"/")); # subdirectory level 1 |
1710 | | - if(!file_exists($mydir1)) { mkdir($mydir1,0775); } # create if necessary |
1711 | | - if(!file_exists($mydir2)) { mkdir($mydir2,0775); } |
1712 | | - |
1713 | | - $f = fopen( $filename, "w" ); |
1714 | | - if($f) { |
1715 | | - $now = wfTimestampNow(); |
1716 | | - fwrite( $f, str_replace( "</html>", |
1717 | | - "<!-- Cached $now -->\n</html>", |
1718 | | - $text ) ); |
1719 | | - fclose( $f ); |
1720 | | - if( $wgUseGzip and $wgCompressByDefault ) { |
1721 | | - $start = microtime(); |
1722 | | - wfDebug(" saving gzip\n"); |
1723 | | - $gzout = gzencode( str_replace( "</html>", |
1724 | | - "<!-- Cached/compressed $now -->\n</html>", |
1725 | | - $text ) ); |
1726 | | - if( $gzout === false ) { |
1727 | | - wfDebug(" failed to gzip compress, sending plaintext\n"); |
1728 | | - return $text; |
1729 | | - } |
1730 | | - if( $f = fopen( "{$filename}.gz", "w" ) ) { |
1731 | | - fwrite( $f, $gzout ); |
1732 | | - fclose( $f ); |
1733 | | - $end = microtime(); |
1734 | | - |
1735 | | - list($usec1, $sec1) = explode(" ",$start); |
1736 | | - list($usec2, $sec2) = explode(" ",$end); |
1737 | | - $interval = ((float)$usec2 + (float)$sec2) - |
1738 | | - ((float)$usec1 + (float)$sec1); |
1739 | | - wfDebug(" saved gzip in $interval\n"); |
1740 | | - } else { |
1741 | | - wfDebug(" failed to write gzip, still sending\n" ); |
1742 | | - } |
1743 | | - if(wfClientAcceptsGzip()) { |
1744 | | - header( "Content-Encoding: gzip" ); |
1745 | | - header( "Vary: Accept-Encoding" ); |
1746 | | - wfDebug(" sending NEW gzip now...\n" ); |
1747 | | - return $gzout; |
1748 | | - } |
1749 | | - } |
1750 | | - } |
1751 | | - return $text; |
1752 | | - } |
1753 | | - |
1754 | 1670 | } |
1755 | 1671 | |
1756 | 1672 | ?> |
Index: branches/stable/phase3/includes/SpecialPreferences.php |
— | — | @@ -181,7 +181,7 @@ |
182 | 182 | $checked = " checked"; |
183 | 183 | } |
184 | 184 | $name = str_replace( "_", " ", $ns[$i] ); |
185 | | - if ( "" == $name ) { $name = "(Main)"; } |
| 185 | + if ( "" == $name ) { $name = wfMsg( "blanknamespace" ); } |
186 | 186 | |
187 | 187 | if ( 0 != $i ) { $r1 .= " "; } |
188 | 188 | $r1 .= "<label><input type=checkbox value=\"1\" name=\"" . |
Index: branches/stable/phase3/includes/DefaultSettings.php |
— | — | @@ -86,8 +86,14 @@ |
87 | 87 | # but this will increase CPU usage. |
88 | 88 | # Requires zlib support enabled in PHP. |
89 | 89 | $wgUseGzip = false; |
90 | | -$wgCompressByDefault = true; |
91 | 90 | |
| 91 | +# For security, the user password hashes include "salt" to |
| 92 | +# make it more difficult for someone who somehow gets ahold |
| 93 | +# of the hashes to crack them all at once. |
| 94 | +# |
| 95 | +# For compatibility with old installations, set to false. |
| 96 | +$wgPasswordSalt = true; |
| 97 | + |
92 | 98 | # Which namespaces should support subpages? |
93 | 99 | # See Language.php for a list of namespaces. |
94 | 100 | # |
Index: branches/stable/phase3/includes/Skin.php |
— | — | @@ -1713,8 +1713,10 @@ |
1714 | 1714 | |
1715 | 1715 | function editSectionLink($section) { |
1716 | 1716 | |
| 1717 | + global $printable; |
1717 | 1718 | global $wgTitle,$wgUser,$oldid; |
1718 | 1719 | if($oldid) return ""; |
| 1720 | + if ($printable) return ""; |
1719 | 1721 | $editurl="§ion={$section}"; |
1720 | 1722 | $url=$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl); |
1721 | 1723 | return "<div style=\"float:right;margin-left:5px;\"><small>[".$url."]</small></div>"; |
Index: branches/stable/phase3/includes/DatabaseFunctions.php |
— | — | @@ -1,10 +1,11 @@ |
2 | 2 | <? |
3 | 3 | global $IP; |
4 | 4 | include_once( "$IP/FulltextStoplist.php" ); |
| 5 | +include_once( "$IP/CacheManager.php" ); |
5 | 6 | |
6 | 7 | $wgLastDatabaseQuery = ""; |
7 | 8 | |
8 | | -function wfGetDB( $altuser = "", $altpassword = "" ) |
| 9 | +function wfGetDB( $altuser = "", $altpassword = "", $altserver = "", $altdb = "" ) |
9 | 10 | { |
10 | 11 | global $wgDBserver, $wgDBuser, $wgDBpassword; |
11 | 12 | global $wgDBname, $wgDBconnection, $wgEmergencyContact; |
— | — | @@ -17,30 +18,73 @@ |
18 | 19 | $wgEmergencyContact . "\">Wikipedia developers</a>.</p>"; |
19 | 20 | |
20 | 21 | if ( $altuser != "" ) { |
21 | | - $wgDBconnection = mysql_connect( $wgDBserver, $altuser, $altpassword ) |
| 22 | + $serve = ($altserver ? $altserver : $wgDBserver ); |
| 23 | + $db = ($altdb ? $altdb : $wgDBname ); |
| 24 | + $wgDBconnection = mysql_connect( $serve, $altuser, $altpassword ) |
22 | 25 | or die( "bad sql user" ); |
23 | 26 | mysql_select_db( $wgDBname, $wgDBconnection ) or die( |
24 | 27 | htmlspecialchars(mysql_error()) ); |
25 | 28 | } |
26 | 29 | |
27 | 30 | if ( ! $wgDBconnection ) { |
28 | | - $wgDBconnection = mysql_pconnect( $wgDBserver, $wgDBuser, |
29 | | - $wgDBpassword ) or die( $noconn . |
30 | | - "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b></p>\n" . $helpme ); |
| 31 | + @$wgDBconnection = mysql_pconnect( $wgDBserver, $wgDBuser, $wgDBpassword ) |
| 32 | + or wfEmergencyAbort(); |
| 33 | + |
31 | 34 | if( !mysql_select_db( $wgDBname, $wgDBconnection ) ) { |
| 35 | + /* Persistent connections may become stuck in an unusable state */ |
32 | 36 | wfDebug( "Persistent connection is broken?\n", true ); |
33 | 37 | |
34 | | - $wgDBconnection = mysql_connect( $wgDBserver, $wgDBuser, |
35 | | - $wgDBpassword ) or die( $noconn . |
36 | | - "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b> (tried non-p connect)</p>\n" . $helpme ); |
37 | | - mysql_select_db( $wgDBname, $wgDBconnection ) or die( $nodb . |
38 | | - "\n<p><b>" . htmlspecialchars(mysql_error()) . "</b> (tried non-p connect)</p>\n" . $helpme ); |
39 | | - } |
| 38 | + @$wgDBconnection = mysql_connect( $wgDBserver, $wgDBuser, $wgDBpassword ) |
| 39 | + or wfEmergencyAbort(); |
| 40 | + |
| 41 | + @mysql_select_db( $db, $wgDBconnection ) |
| 42 | + or wfEmergencyAbort(); |
| 43 | + } |
40 | 44 | } |
41 | 45 | # mysql_ping( $wgDBconnection ); |
42 | 46 | return $wgDBconnection; |
43 | 47 | } |
44 | 48 | |
| 49 | +/* Call this function if we couldn't contact the database... |
| 50 | + We'll try to use the cache to display something in the meantime */ |
| 51 | +function wfEmergencyAbort( $msg = "" ) { |
| 52 | + global $wgTitle, $wgUseFileCache, $title, $wgOutputEncoding; |
| 53 | + |
| 54 | + header( "Content-type: text/html; charset=$wgOutputEncoding" ); |
| 55 | + if($msg == "") $msg = wfMsg( "noconnect" ); |
| 56 | + $text = $msg; |
| 57 | + |
| 58 | + if($wgUseFileCache) { |
| 59 | + if($wgTitle) { |
| 60 | + $t =& $wgTitle; |
| 61 | + } else { |
| 62 | + if($title) { |
| 63 | + $t = Title::newFromURL( $title ); |
| 64 | + } else { |
| 65 | + $t = Title::newFromText( wfMsg("mainpage") ); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + $cache = new CacheManager( $t ); |
| 70 | + if( $cache->isFileCached() ) { |
| 71 | + $msg = "<p style='color: red'><b>$msg<br>\n" . |
| 72 | + wfMsg( "cachederror" ) . "</b></p>\n"; |
| 73 | + |
| 74 | + $tag = "<div id='article'>"; |
| 75 | + $text = str_replace( |
| 76 | + $tag, |
| 77 | + $tag . $msg, |
| 78 | + $cache->fetchPageText() ); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + /* Don't cache error pages! They cause no end of trouble... */ |
| 83 | + header( "Cache-control: none" ); |
| 84 | + header( "Pragma: nocache" ); |
| 85 | + echo $text; |
| 86 | + exit; |
| 87 | +} |
| 88 | + |
45 | 89 | function wfQuery( $sql, $fname = "" ) |
46 | 90 | { |
47 | 91 | global $wgLastDatabaseQuery, $wgOut; |
Index: branches/stable/phase3/includes/OutputPage.php |
— | — | @@ -302,11 +302,13 @@ |
303 | 303 | if( $this->mLastModified != "" ) { |
304 | 304 | wfDebug( "** private caching; {$this->mLastModified} **\n", false ); |
305 | 305 | header( "Cache-Control: private, must-revalidate, max-age=0" ); |
| 306 | + header( "Vary: Accept-Encoding" ); |
306 | 307 | header( "Last-modified: {$this->mLastModified}" ); |
307 | 308 | } else { |
308 | 309 | wfDebug( "** no caching **\n", false ); |
309 | 310 | header( "Cache-Control: no-cache" ); # Experimental - see below |
310 | 311 | header( "Pragma: no-cache" ); |
| 312 | + header( "Vary: Accept-Encoding" ); |
311 | 313 | header( "Last-modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" ); |
312 | 314 | } |
313 | 315 | header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page! |
Index: branches/stable/phase3/includes/SpecialWatchlist.php |
— | — | @@ -11,52 +11,148 @@ |
12 | 12 | $wgOut->setPagetitle( wfMsg( "watchlist" ) ); |
13 | 13 | $sub = str_replace( "$1", $wgUser->getName(), wfMsg( "watchlistsub" ) ); |
14 | 14 | $wgOut->setSubtitle( $sub ); |
15 | | - $wgOut->setRobotpolicy( "index,follow" ); |
| 15 | + $wgOut->setRobotpolicy( "noindex,nofollow" ); |
16 | 16 | |
| 17 | + $uid = $wgUser->getID(); |
| 18 | + if( $uid == 0 ) { |
| 19 | + $wgOut->addHTML( wfMsg( "nowatchlist" ) ); |
| 20 | + return; |
| 21 | + } |
| 22 | + |
| 23 | + global $action,$remove,$id; |
| 24 | + if(($action == "submit") && isset($remove) && is_array($id)) { |
| 25 | + $wgOut->addHTML( wfMsg( "removingchecked" ) ); |
| 26 | + foreach($id as $one) { |
| 27 | + $t = Title::newFromURL( $one ); |
| 28 | + if($t->getDBkey() != "") { |
| 29 | + $sql = "DELETE FROM watchlist WHERE wl_user=$uid AND " . |
| 30 | + "wl_namespace=" . $t->getNamespace() . " AND " . |
| 31 | + "wl_title='" . wfStrencode( $t->getDBkey() ) . "'"; |
| 32 | + $res = wfQuery( $sql ); |
| 33 | + if($res === FALSE) { |
| 34 | + $wgOut->addHTML( "<br />\n" . wfMsg( "couldntremove", htmlspecialchars($one) ) ); |
| 35 | + } else { |
| 36 | + $wgOut->addHTML( " (" . htmlspecialchars($one) . ")" ); |
| 37 | + } |
| 38 | + } else { |
| 39 | + $wgOut->addHTML( "<br />\n" . wfMsg( "iteminvalidname", htmlspecialchars($one) ) ); |
| 40 | + } |
| 41 | + } |
| 42 | + $wgOut->addHTML( "done.\n<p>" ); |
| 43 | + } |
| 44 | + |
| 45 | + $sql = "SELECT COUNT(*) AS n FROM watchlist WHERE wl_user=$uid"; |
| 46 | + $res = wfQuery( $sql ); |
| 47 | + $s = wfFetchObject( $res ); |
| 48 | + $nitems = $s->n; |
| 49 | + |
| 50 | + if($nitems == 0) { |
| 51 | + $wgOut->addHTML( wfMsg( "nowatchlist" ) ); |
| 52 | + return; |
| 53 | + } |
| 54 | + |
17 | 55 | if ( ! isset( $days ) ) { |
18 | | - $days = $wgUser->getOption( "rcdays" ); |
19 | | - if ( ! $days ) { $days = 3; } |
| 56 | + $big = 250; |
| 57 | + if($nitems > $big) { |
| 58 | + # Set default cutoff shorter |
| 59 | + $days = (1.0 / 24.0); # 1 hour... |
| 60 | + } else { |
| 61 | + $days = 0; # no time cutoff for shortlisters |
| 62 | + } |
| 63 | + } else { |
| 64 | + $days = floatval($days); |
20 | 65 | } |
21 | | - $days = (int)$days; |
22 | | - list( $limit, $offset ) = wfCheckLimits( 100, "rclimit" ); |
23 | 66 | |
24 | 67 | if ( $days <= 0 ) { |
25 | 68 | $docutoff = ''; |
| 69 | + $cutoff = false; |
| 70 | + $npages = wfMsg( "all" ); |
26 | 71 | } else { |
27 | | - $docutoff = "cur_timestamp > '" . |
28 | | - wfUnix2Timestamp( time() - ( $days * 86400 ) ) |
29 | | - . "' AND"; |
| 72 | + $docutoff = "AND cur_timestamp > '" . |
| 73 | + ( $cutoff = wfUnix2Timestamp( time() - intval( $days * 86400 ) ) ) |
| 74 | + . "'"; |
| 75 | + $sql = "SELECT COUNT(*) AS n FROM cur WHERE cur_timestamp>'$cutoff'"; |
| 76 | + $res = wfQuery( $sql ); |
| 77 | + $s = wfFetchObject( $res ); |
| 78 | + $npages = $s->n; |
30 | 79 | } |
31 | | - if ( $limit == 0 ) { |
32 | | - $dolimit = ""; |
33 | | - } else { |
34 | | - $dolimit = "LIMIT $limit"; |
35 | | - } |
36 | 80 | |
37 | | - $uid = $wgUser->getID(); |
38 | | - if( $uid == 0 ) { |
39 | | - $wgOut->addHTML( wfMsg( "nowatchlist" ) ); |
| 81 | + if(isset($_REQUEST['magic'])) { |
| 82 | + $wgOut->addHTML( wfMsg( "watchlistcontains", $nitems ) . |
| 83 | + "<p>" . wfMsg( "watcheditlist" ) . "</p>\n" ); |
| 84 | + |
| 85 | + $wgOut->addHTML( "<form action='" . |
| 86 | + wfLocalUrl( $wgLang->specialPage( "Watchlist" ), "action=submit" ) . |
| 87 | + "' method='post'>\n" . |
| 88 | + "<ul>\n" ); |
| 89 | + $sql = "SELECT wl_namespace,wl_title FROM watchlist WHERE wl_user=$uid"; |
| 90 | + $res = wfQuery( $sql ); |
| 91 | + global $wgUser, $wgLang; |
| 92 | + $sk = $wgUser->getSkin(); |
| 93 | + while( $s = wfFetchObject( $res ) ) { |
| 94 | + $t = Title::makeTitle( $s->wl_namespace, $s->wl_title ); |
| 95 | + $t = $t->getPrefixedText(); |
| 96 | + $wgOut->addHTML( "<li><input type='checkbox' name='id[]' value=\"" . htmlspecialchars($t) . "\">" . |
| 97 | + $sk->makeKnownLink( $t, $t ) . |
| 98 | + "</li>\n" ); |
| 99 | + } |
| 100 | + $wgOut->addHTML( "</ul>\n" . |
| 101 | + "<input type='submit' name='remove' value='" . |
| 102 | + wfMsg( "removechecked" ) . "'>\n" . |
| 103 | + "</form>\n" ); |
| 104 | + |
40 | 105 | return; |
41 | 106 | } |
| 107 | + |
| 108 | + # If the watchlist is relatively short, it's simplest to zip |
| 109 | + # down its entirety and then sort the results. |
| 110 | + |
| 111 | + # If it's relatively long, it may be worth our while to zip |
| 112 | + # through the time-sorted page list checking for watched items. |
| 113 | + |
| 114 | + # Up estimate of watched items by 15% to compensate for talk pages... |
| 115 | + if( $cutoff && ( $nitems*1.15 > $npages ) ) { |
| 116 | + $x = "cur_timestamp"; |
| 117 | + $y = wfMsg( "watchmethod-recent" ); |
| 118 | + $z = "wl_namespace=cur_namespace&65534"; |
| 119 | + } else { |
| 120 | + $x = "name_title_timestamp"; |
| 121 | + $y = wfMsg( "watchmethod-list" ); |
| 122 | + $z = "(wl_namespace=cur_namespace OR wl_namespace+1=cur_namespace)"; |
| 123 | + } |
42 | 124 | |
43 | | - $sql = "SELECT DISTINCT |
44 | | - cur_id,cur_namespace,cur_title,cur_comment, |
| 125 | + $wgOut->addHTML( "<i>" . wfMsg( "watchdetails", $nitems, $npages, $y, |
| 126 | + wfLocalUrl( $wgLang->specialPage("Watchlist"),"magic=yes" ) ) . "</i><br>\n" ); |
| 127 | + |
| 128 | + |
| 129 | + $sql = "SELECT |
| 130 | + cur_namespace,cur_title,cur_comment, |
45 | 131 | cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new |
46 | | - FROM cur,watchlist |
47 | | - WHERE wl_user={$uid} AND wl_title=cur_title |
48 | | - AND (cur_namespace=wl_namespace OR cur_namespace=wl_namespace+1) |
49 | | - ORDER BY inverse_timestamp {$dolimit}"; |
| 132 | + FROM watchlist,cur USE INDEX ($x) |
| 133 | + WHERE wl_user=$uid |
| 134 | + AND $z |
| 135 | + AND wl_title=cur_title |
| 136 | + $docutoff |
| 137 | + ORDER BY cur_timestamp DESC"; |
| 138 | + |
| 139 | + |
50 | 140 | $res = wfQuery( $sql, $fname ); |
| 141 | + |
| 142 | + if($days >= 1) |
| 143 | + $note = wfMsg( "rcnote", $limit, $days ); |
| 144 | + elseif($days > 0) |
| 145 | + $note = wfMsg( "wlnote", $limit, round($days*24) ); |
| 146 | + else |
| 147 | + $note = ""; |
| 148 | + $wgOut->addHTML( "\n<hr>\n{$note}\n<br>" ); |
| 149 | + $note = wlCutoffLinks( $days, $limit ); |
| 150 | + $wgOut->addHTML( "{$note}\n" ); |
| 151 | + |
51 | 152 | if ( wfNumRows( $res ) == 0 ) { |
52 | | - $wgOut->addHTML( wfMsg( "nowatchlist" ) ); |
| 153 | + $wgOut->addHTML( "<p><i>" . wfMsg( "watchnochange" ) . "</i></p>" ); |
53 | 154 | return; |
54 | 155 | } |
55 | 156 | |
56 | | - $note = wfMsg( "rcnote", $limit, $days ); |
57 | | - $wgOut->addHTML( "\n<hr>\n{$note}\n<br>" ); |
58 | | - $note = rcDayLimitlinks( $days, $limit, "Watchlist", "", true ); |
59 | | - $wgOut->addHTML( "{$note}\n" ); |
60 | | - |
61 | 157 | $sk = $wgUser->getSkin(); |
62 | 158 | $s = $sk->beginRecentChangesList(); |
63 | 159 | |
— | — | @@ -79,4 +175,45 @@ |
80 | 176 | $wgOut->addHTML( $s ); |
81 | 177 | } |
82 | 178 | |
| 179 | + |
| 180 | +function wlHoursLink( $h, $page ) { |
| 181 | + global $wgUser, $wgLang; |
| 182 | + $sk = $wgUser->getSkin(); |
| 183 | + $s = $sk->makeKnownLink( |
| 184 | + $wgLang->specialPage( $page ), |
| 185 | + $h, "days=" . ($h / 24.0) ); |
| 186 | + return $s; |
| 187 | +} |
| 188 | + |
| 189 | + |
| 190 | +function wlDaysLink( $d, $page ) { |
| 191 | + global $wgUser, $wgLang; |
| 192 | + $sk = $wgUser->getSkin(); |
| 193 | + $s = $sk->makeKnownLink( |
| 194 | + $wgLang->specialPage( $page ), |
| 195 | + ($d ? $d : wfMsg( "all" ) ), "days=$d" ); |
| 196 | + return $s; |
| 197 | +} |
| 198 | + |
| 199 | +function wlCutoffLinks( $days, $limit, $page = "Watchlist" ) |
| 200 | +{ |
| 201 | + $hours = array( 1, 2, 6, 12 ); |
| 202 | + $days = array( 1, 3, 7 ); |
| 203 | + $cl = ""; |
| 204 | + $i = 0; |
| 205 | + foreach( $hours as $h ) { |
| 206 | + $hours[$i++] = wlHoursLink( $h, $page ); |
| 207 | + } |
| 208 | + $i = 0; |
| 209 | + foreach( $days as $d ) { |
| 210 | + $days[$i++] = wlDaysLink( $d, $page ); |
| 211 | + } |
| 212 | + return |
| 213 | + "Show last " . |
| 214 | + implode(" | ", $hours) . " hours " . |
| 215 | + implode(" | ", $days) . " days " . |
| 216 | + wlDaysLink( 0, $page ); |
| 217 | +# $note = wfMsg( "rclinks", $cl, $dl, $mlink ); |
| 218 | +} |
| 219 | + |
83 | 220 | ?> |
Index: branches/stable/phase3/languages/Language.php |
— | — | @@ -394,8 +394,9 @@ |
395 | 395 | \"$1\" |
396 | 396 | from within function \"$2\". |
397 | 397 | MySQL returned error \"$3: $4\".\n", |
398 | | -"noconnect" => "Could not connect to DB on $1", |
| 398 | +"noconnect" => "Sorry! The wiki is experiencing some technical difficulties, and cannot contact the database server.", |
399 | 399 | "nodb" => "Could not select database $1", |
| 400 | +"cachederror" => "The following is a cached copy of the requested page, and may not be up to date.", |
400 | 401 | "readonly" => "Database locked", |
401 | 402 | "enterlockreason" => "Enter a reason for the lock, including an estimate |
402 | 403 | of when the lock will be released", |
— | — | @@ -908,7 +909,25 @@ |
909 | 910 | "watchthispage" => "Watch this page", |
910 | 911 | "unwatchthispage" => "Stop watching", |
911 | 912 | "notanarticle" => "Not an article", |
| 913 | +"watchnochange" => "None of your watched items were edited in the time period displayed.", |
| 914 | +"watchdetails" => "($1 pages watched not counting talk pages; |
| 915 | +$2 total pages edited since cutoff; |
| 916 | +$3... |
| 917 | +<a href='$4'>show and edit complete list</a>.)", |
| 918 | +"watchmethod-recent" => "checking recent edits for watched pages", |
| 919 | +"watchmethod-list" => "checking watched pages for recent edits", |
| 920 | +"removechecked" => "Remove checked items from watchlist", |
| 921 | +"watchlistcontains" => "Your watchlist contains $1 pages.", |
| 922 | +"watcheditlist" => "Here's an alphabetical list of your |
| 923 | +watched pages. Check the boxes of pages you want to remove |
| 924 | +from your watchlist and click the 'remove checked' button |
| 925 | +at the bottom of the screen.", |
| 926 | +"removingchecked" => "Removing requested items from watchlist...", |
| 927 | +"couldntremove" => "Couldn't remove item '$1'...", |
| 928 | +"iteminvalidname" => "Problem with item '$1', invalid name...", |
| 929 | +"wlnote" => "Below are the last $1 changes in the last <b>$2</b> hours.", |
912 | 930 | |
| 931 | + |
913 | 932 | # Delete/protect/revert |
914 | 933 | # |
915 | 934 | "deletepage" => "Delete page", |