Experimental support for the "link" type old entries. Before this is useful, a comman...
authorTim Starling <tstarling@users.mediawiki.org>
Tue, 15 Jun 2004 15:05:56 +0000 (15:05 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Tue, 15 Jun 2004 15:05:56 +0000 (15:05 +0000)
includes/Article.php
includes/HistoryBlob.php [new file with mode: 0644]

index 6a0e4a5..b1c1cd1 100644 (file)
@@ -32,19 +32,35 @@ class Article {
                $this->mTouched = '19700101000000';
        }
 
+       # 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_' ) {
-               # 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 );
-               }
-               if( isset( $row->$text ) ) {
-                       return $row->$text;
-               }
-               return false;
+               # 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 ( 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 $text;
        }
        
        /* static */ function compressRevisionText( &$text ) {
@@ -60,6 +76,120 @@ class Article {
                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 $wgDatabase, $wgKnownDBServers;
+               $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.
 
diff --git a/includes/HistoryBlob.php b/includes/HistoryBlob.php
new file mode 100644 (file)
index 0000000..cf170b7
--- /dev/null
@@ -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();
+       }
+}
+?>