bugfixes to deletion code
[lhc/web/wiklou.git] / includes / Article.php
index b438099..bc7847e 100644 (file)
@@ -7,7 +7,7 @@ class Article {
        /* private */ var $mUser, $mTimestamp, $mUserText;
        /* private */ var $mCounter, $mComment, $mCountAdjustment;
        /* private */ var $mMinorEdit, $mRedirectedFrom;
-       /* private */ var $mTouched;
+       /* private */ var $mTouched, $mFileCache;
 
        function Article() { $this->clear(); }
 
@@ -16,7 +16,7 @@ class Article {
                $this->mContentLoaded = false;
                $this->mUser = $this->mCounter = -1; # Not loaded
                $this->mRedirectedFrom = $this->mUserText =
-               $this->mTimestamp = $this->mComment = "";
+               $this->mTimestamp = $this->mComment = $this->mFileCache = "";
                $this->mCountAdjustment = 0;
                $this->mTouched = "19700101000000";
        }
@@ -433,7 +433,7 @@ class Article {
 
                if ( "initial" == $formtype ) {
                        $wpEdittime = $this->getTimestamp();
-                       $wpTextbox1 = $this->getContent();
+                       $wpTextbox1 = $this->getContent(true);
                        $wpSummary = "";
                }
                $wgOut->setRobotpolicy( "noindex,nofollow" );
@@ -446,7 +446,7 @@ class Article {
                        $wgOut->addHTML( wfMsg( "explainconflict" ) );
 
                        $wpTextbox2 = $wpTextbox1;
-                       $wpTextbox1 = $this->getContent();
+                       $wpTextbox1 = $this->getContent(true);
                        $wpEdittime = $this->getTimestamp();
                } else {
                        $s = str_replace( "$1", $wgTitle->getPrefixedText(),
@@ -538,7 +538,7 @@ class Article {
                        }
                }
                $wgOut->addHTML( "
-<form id=\"editform\" method=\"post\" action=\"$action\"
+<form id=\"editform\" name=\"editform\" method=\"post\" action=\"$action\"
 enctype=\"application/x-www-form-urlencoded\">
 <textarea tabindex=1 name=\"wpTextbox1\" rows={$rows}
 cols={$cols}{$ew} wrap=\"virtual\">" .
@@ -591,6 +591,8 @@ name=\"wpSummary\" maxlength=200 size=60><br>
 
                $now = wfTimestampNow();
                $won = wfInvertTimestamp( $now );
+               wfSeedRandom();
+               $rand = mt_rand() / mt_getrandmax();
                $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," .
@@ -599,7 +601,7 @@ name=\"wpSummary\" maxlength=200 size=60><br>
                  wfStrencode( $summary ) . "', '" .
                  $wgUser->getID() . "', '{$now}', " .
                  ( $isminor ? 1 : 0 ) . ", 0, '', '" .
-                 wfStrencode( $wgUser->getName() ) . "', $redir, 1, RAND(), '{$now}', '{$won}')";
+                 wfStrencode( $wgUser->getName() ) . "', $redir, 1, $rand, '{$now}', '{$won}')";
                $res = wfQuery( $sql, $fname );
 
                $newid = wfInsertId();
@@ -1002,15 +1004,72 @@ name=\"wpSummary\" maxlength=200 size=60><br>
                                $wgOut->fatalError( wfMsg( "cannotdelete" ) );
                                return;
                        }
-                       $sub = str_replace( "$1", $image, wfMsg( "deletesub" ) );
+                       $sub = str_replace( "$1", $image, wfMsg( "deletesub" ) );                       
                } else {
+
                        if ( ( "" == trim( $wgTitle->getText() ) )
                          or ( $wgTitle->getArticleId() == 0 ) ) {
                                $wgOut->fatalError( wfMsg( "cannotdelete" ) );
                                return;
                        }
                        $sub = str_replace( "$1", $wgTitle->getPrefixedText(),
-                         wfMsg( "deletesub" ) );
+                         wfMsg( "deletesub" ) );                       
+
+                       # determine whether this page has earlier revisions
+                       # and insert a warning if it does
+                       # we select the text because it might be useful below
+                       $sql="SELECT old_text FROM old WHERE old_namespace=0 and old_title='" . wfStrencode($wgTitle->getPrefixedDBkey())."' ORDER BY inverse_timestamp LIMIT 1";
+                       $res=wfQuery($sql,$fname);
+                       if( ($old=wfFetchObject($res)) && !$wpConfirm ) {
+                               $skin=$wgUser->getSkin();
+                               $wgOut->addHTML("<B>".wfMsg("historywarning"));
+                               $wgOut->addHTML( $skin->historyLink() ."</B><P>");
+                       }
+
+                       $sql="SELECT cur_text FROM cur WHERE cur_namespace=0 and cur_title='" . wfStrencode($wgTitle->getPrefixedDBkey())."'";
+                       $res=wfQuery($sql,$fname);
+                       if( ($s=wfFetchObject($res))) {
+
+                               # if this is a mini-text, we can paste part of it into the deletion reason
+
+                               #if this is empty, an earlier revision may contain "useful" text
+                               if($s->cur_text!="") {
+                                       $text=$s->cur_text;
+                               } else {
+                                       if($old) {
+                                               $text=$old->old_text;
+                                               $blanked=1;
+                                       }
+                                       
+                               }
+                               
+                               $length=strlen($text);                          
+                               
+                               # this should not happen, since it is not possible to store an empty, new
+                               # page. Let's insert a standard text in case it does, though
+                               if($length==0 && !$wpReason) { $wpReason=wfmsg("exblank");}
+                               
+                               
+                               if($length < 500 && !$wpReason) {
+                                                                               
+                                       # 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("/\</","&lt;",$text);
+                                       $text=preg_replace("/\>/","&gt;",$text);
+                                       $text=preg_replace("/[\n\r]/","",$text);
+                                       if(!$blanked) {
+                                               $wpReason=wfMsg("excontent"). " '".$text;
+                                       } else {
+                                               $wpReason=wfMsg("exbeforeblank") . " '".$text;
+                                       }
+                                       if($length>150) { $wpReason .= "..."; } # we've only pasted part of the text
+                                       $wpReason.="'"; 
+                               }
+                       }
+
                }
 
                # Likewise, deleting old images doesn't require confirmation
@@ -1042,7 +1101,7 @@ name=\"wpSummary\" maxlength=200 size=60><br>
 <form id=\"deleteconfirm\" method=\"post\" action=\"{$formaction}\">
 <table border=0><tr><td align=right>
 {$delcom}:</td><td align=left>
-<input type=text size=20 name=\"wpReason\" value=\"{$wpReason}\">
+<input type=text size=60 name=\"wpReason\" value=\"{$wpReason}\">
 </td></tr><tr><td>&nbsp;</td></tr>
 <tr><td align=right>
 <input type=checkbox name=\"wpConfirm\" value='1'>
@@ -1267,19 +1326,19 @@ name=\"wpSummary\" maxlength=200 size=60><br>
 
        function rollback()
        {
-               global $wgUser, $wgTitle, $wgLang, $wgOut;
+               global $wgUser, $wgTitle, $wgLang, $wgOut, $from;
 
                if ( ! $wgUser->isSysop() ) {
                        $wgOut->sysopRequired();
                        return;
                }
-               
+
                # Replace all this user's current edits with the next one down
                $tt = wfStrencode( $wgTitle->getDBKey() );
                $n = $wgTitle->getNamespace();
                
                # Get the last editor
-               $sql = "SELECT cur_id,cur_user,cur_user_text 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 );
                if( ($x = wfNumRows( $res )) != 1 ) {
                        # Something wrong
@@ -1291,6 +1350,21 @@ name=\"wpSummary\" maxlength=200 size=60><br>
                $uid = $s->cur_user;
                $pid = $s->cur_id;
                
+               $from = str_replace( '_', ' ', wfCleanQueryVar( $from ) );
+               if( $from != $s->cur_user_text ) {
+                       $wgOut->setPageTitle(wfmsg("rollbackfailed"));
+                       $wgOut->addWikiText( wfMsg( "alreadyrolled",
+                               htmlspecialchars( $wgTitle->getPrefixedText()),
+                               htmlspecialchars( $from ),
+                               htmlspecialchars( $s->cur_user_text ) ) );
+                       if($s->cur_comment != "") {
+                               $wgOut->addHTML(
+                                       wfMsg("editcomment",
+                                       htmlspecialchars( $s->cur_comment ) ) );
+                               }
+                       return;
+               }
+               
                # Get the last edit not by this guy
                $sql = "SELECT old_text,old_user,old_user_text
                FROM old USE INDEX (name_title_timestamp)
@@ -1300,6 +1374,7 @@ name=\"wpSummary\" maxlength=200 size=60><br>
                $res = wfQuery( $sql );
                if( wfNumRows( $res ) != 1 ) {
                        # Something wrong
+                       $wgOut->setPageTitle(wfMsg("rollbackfailed"));
                        $wgOut->addHTML( wfMsg( "cantrollback" ) );
                        return;
                }
@@ -1485,7 +1560,7 @@ name=\"wpSummary\" maxlength=200 size=60><br>
                                $this->loadFromFileCache();
                                exit;
                        } else {
-                   wfDebug( " tryFileCache() - starting buffer\n" );
+                   wfDebug( " tryFileCache() - starting buffer\n" );                   
                        ob_start( array(&$this, 'saveToFileCache' ) );
                        }
                } else {
@@ -1512,42 +1587,89 @@ name=\"wpSummary\" maxlength=200 size=60><br>
        
        function fileCacheName() {
                global $wgTitle, $wgFileCacheDirectory, $wgLang;
-               $hash = md5( $key = $wgTitle->getDbkey() );
-               if( $wgTitle->getNamespace() )
-                       $key = $wgLang->getNsText( $wgTitle->getNamespace() ) . ":" . $key;
-               $key = urlencode( $key );
-               $hash1 = substr( $hash, 0, 1 );
-               $hash2 = substr( $hash, 0, 2 );
-               $fn = "{$wgFileCacheDirectory}/{$hash1}/{$hash2}/{$key}.html";
-               wfDebug( " fileCacheName() - $fn\n" );
-               return $fn;
+               if( !$this->mFileCache ) {
+                       $hash = md5( $key = $wgTitle->getDbkey() );
+                       if( $wgTitle->getNamespace() )
+                               $key = $wgLang->getNsText( $wgTitle->getNamespace() ) . ":" . $key;
+                       $key = str_replace( ".", "%2E", urlencode( $key ) );
+                       $hash1 = substr( $hash, 0, 1 );
+                       $hash2 = substr( $hash, 0, 2 );
+                       $this->mFileCache = "{$wgFileCacheDirectory}/{$hash1}/{$hash2}/{$key}.html";
+                       wfDebug( " fileCacheName() - {$this->mFileCache}\n" );
+               }
+               return $this->mFileCache;
        }
 
        function isFileCacheGood() {
                global $wgUser, $wgCacheEpoch;
                if(!file_exists( $fn = $this->fileCacheName() ) ) return false;
                $cachetime = wfUnix2Timestamp( filemtime( $fn ) );
-               $good = ( $this->mTouched <= $cachetime ) and
-                       $wgUser->validateCache( $cachetime ) and
+               $good = ( $this->mTouched <= $cachetime ) &&
                        ($wgCacheEpoch <= $cachetime );
-        wfDebug(" isFileCacheGood() - cachetime $cachetime, good $good\n");
+        wfDebug(" isFileCacheGood() - cachetime $cachetime, touched {$this->mTouched} epoch {$wgCacheEpoch}, good $good\n");
                return $good;
        }
 
        function loadFromFileCache() {
+               global $wgUseGzip;
                wfDebug(" loadFromFileCache()\n");
-               readfile($this->fileCacheName());
+               $filename=$this->fileCacheName();
+               $filenamegz = "{$filename}.gz";
+               if( $wgUseGzip
+                       && wfClientAcceptsGzip()
+                       && file_exists( $filenamegz)
+                       && ( filemtime( $filenamegz ) >= filemtime( $filename ) ) ) {
+                       wfDebug("  sending gzip\n");
+                       header( "Content-Encoding: gzip" );
+                       header( "Vary: Accept-Encoding" );
+                       $filename = $filenamegz;
+               }
+               readfile( $filename );
        }
        
        function saveToFileCache( $text ) {
-               # FIXME: assumes directories are already laid out
+               global $wgUseGzip, $wgCompressByDefault;
+               
         wfDebug(" saveToFileCache()\n");
-               $f = fopen( $this->fileCacheName(), "w" );
+               $filename=$this->fileCacheName();
+                $mydir2=substr($filename,0,strrpos($filename,"/")); # subdirectory level 2
+               $mydir1=substr($mydir2,0,strrpos($mydir2,"/")); # subdirectory level 1
+               if(!file_exists($mydir1)) { mkdir($mydir1,0777); } # create if necessary
+               if(!file_exists($mydir2)) { mkdir($mydir2,0777); }                      
+               $f = fopen( $filename, "w" );
                if($f) {
+                       $now = wfTimestampNow();
                        fwrite( $f, str_replace( "</html>",
-                               "<!-- Cached " . wfTimestampNow() . " -->\n</html>",
+                               "<!-- Cached $now -->\n</html>",
                                $text ) );
                        fclose( $f );
+                       if( $wgUseGzip and $wgCompressByDefault ) {
+                               $start = microtime();
+                               wfDebug("  saving gzip\n");
+                               $gzout = gzencode( str_replace( "</html>",
+                                               "<!-- Cached/compressed $now -->\n</html>",
+                                               $text ) );
+                               if( $gzout === false ) {
+                                       wfDebug("  failed to gzip compress, sending plaintext\n");
+                                       return $text;
+                               }
+                               if( $f = fopen( "{$filename}.gz", "w" ) ) {
+                                       fwrite( $f, $gzout );
+                                       fclose( $f );
+                                       $end = microtime();
+                                       
+                                       list($usec1, $sec1) = explode(" ",$start);
+                                       list($usec2, $sec2) = explode(" ",$end);
+                                       $interval = ((float)$usec2 + (float)$sec2) -
+                                                               ((float)$usec1 + (float)$sec1);
+                                       wfDebug("  saved gzip in $interval\n");
+                               } else {
+                                       wfDebug("  failed to write gzip, still sending\n" );
+                               }
+                               header( "Content-Encoding: gzip" );
+                               header( "Vary: Accept-Encoding" );
+                               return $gzout;
+                       }
                }
                return $text;
        }