Index: trunk/phase3/includes/Article.php |
— | — | @@ -32,19 +32,35 @@ |
33 | 33 | $this->mTouched = '19700101000000'; |
34 | 34 | } |
35 | 35 | |
| 36 | + # Get revision text associated with an old or archive row |
| 37 | + # $row is usually an object from wfFetchRow(), both the flags and the text field must be included |
36 | 38 | /* static */ function getRevisionText( $row, $prefix = 'old_' ) { |
37 | | - # Deal with optional compression of archived pages. |
38 | | - # This can be done periodically via maintenance/compressOld.php, and |
39 | | - # as pages are saved if $wgCompressRevisions is set. |
40 | | - $text = $prefix . 'text'; |
41 | | - $flags = $prefix . 'flags'; |
42 | | - if( isset( $row->$flags ) && (false !== strpos( $row->$flags, 'gzip' ) ) ) { |
43 | | - return gzinflate( $row->$text ); |
| 39 | + # Get data |
| 40 | + $textField = $prefix . 'text'; |
| 41 | + $flagsField = $prefix . 'flags'; |
| 42 | + |
| 43 | + if ( isset( $row->$flagsField ) ) { |
| 44 | + $flags = explode( ",", $row->$flagsField ); |
| 45 | + } else { |
| 46 | + $flags = array(); |
44 | 47 | } |
45 | | - if( isset( $row->$text ) ) { |
46 | | - return $row->$text; |
| 48 | + |
| 49 | + if ( isset( $row->$textField ) ) { |
| 50 | + $text = $row->$textField; |
| 51 | + } else { |
| 52 | + return false; |
47 | 53 | } |
48 | | - return false; |
| 54 | + |
| 55 | + if ( in_array( 'link', $flags ) ) { |
| 56 | + # Handle link type |
| 57 | + $text = Article::followLink( $text ); |
| 58 | + } elseif ( in_array( 'gzip', $flags ) ) { |
| 59 | + # Deal with optional compression of archived pages. |
| 60 | + # This can be done periodically via maintenance/compressOld.php, and |
| 61 | + # as pages are saved if $wgCompressRevisions is set. |
| 62 | + return gzinflate( $text ); |
| 63 | + } |
| 64 | + return $text; |
49 | 65 | } |
50 | 66 | |
51 | 67 | /* static */ function compressRevisionText( &$text ) { |
— | — | @@ -60,6 +76,120 @@ |
61 | 77 | return 'gzip'; |
62 | 78 | } |
63 | 79 | |
| 80 | + # Returns the text associated with a "link" type old table row |
| 81 | + /* static */ function followLink( $link ) { |
| 82 | + # Split the link into fields and values |
| 83 | + $lines = explode( '\n', $link ); |
| 84 | + $hash = ''; |
| 85 | + $locations = array(); |
| 86 | + foreach ( $lines as $line ) { |
| 87 | + # Comments |
| 88 | + if ( $line{0} == '#' ) { |
| 89 | + continue; |
| 90 | + } |
| 91 | + # Field/value pairs |
| 92 | + if ( preg_match( '/^(.*?)\s*:\s*(.*)$/', $line, $matches ) ) { |
| 93 | + $field = strtolower($matches[1]); |
| 94 | + $value = $matches[2]; |
| 95 | + if ( $field == 'hash' ) { |
| 96 | + $hash = $value; |
| 97 | + } elseif ( $field == 'location' ) { |
| 98 | + $locations[] = $value; |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + if ( $hash === '' ) { |
| 104 | + return false; |
| 105 | + } |
| 106 | + |
| 107 | + # Look in each specified location for the text |
| 108 | + $text = false; |
| 109 | + foreach ( $locations as $location ) { |
| 110 | + $text = Article::fetchFromLocation( $location, $hash ); |
| 111 | + if ( $text !== false ) { |
| 112 | + break; |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + return $text; |
| 117 | + } |
| 118 | + |
| 119 | + /* static */ function fetchFromLocation( $location, $hash ) { |
| 120 | + global $wgDatabase, $wgKnownDBServers; |
| 121 | + $fname = 'fetchFromLocation'; |
| 122 | + wfProfileIn( $fname ); |
| 123 | + |
| 124 | + $p = strpos( $location, ':' ); |
| 125 | + if ( $p === false ) { |
| 126 | + wfProfileOut( $fname ); |
| 127 | + return false; |
| 128 | + } |
| 129 | + |
| 130 | + $type = substr( $location, 0, $p ); |
| 131 | + $text = false; |
| 132 | + switch ( $type ) { |
| 133 | + case 'mysql': |
| 134 | + # MySQL locations are specified by mysql://<machineID>/<dbname>/<tblname>/<index> |
| 135 | + # Machine ID 0 is the current connection |
| 136 | + if ( preg_match( '/^mysql:\/\/(\d+)\/([A-Za-z_]+)\/([A-Za-z_]+)\/([A-Za-z_]+)$/', |
| 137 | + $location, $matches ) ) { |
| 138 | + $machineID = $matches[1]; |
| 139 | + $dbName = $matches[2]; |
| 140 | + $tblName = $matches[3]; |
| 141 | + $index = $matches[4]; |
| 142 | + if ( $machineID == 0 ) { |
| 143 | + # Current connection |
| 144 | + $db =& wfGetDB(); |
| 145 | + } else { |
| 146 | + # Alternate connection |
| 147 | + $db =& $wgLoadBalancer->getConnection( $machineID ); |
| 148 | + |
| 149 | + if ( array_key_exists( $machineId, $wgKnownMysqlServers ) ) { |
| 150 | + # Try to open, return false on failure |
| 151 | + $params = $wgKnownDBServers[$machineId]; |
| 152 | + $db = Database::newFromParams( $params['server'], $params['user'], $params['password'], |
| 153 | + $dbName, 1, false, true, true ); |
| 154 | + } |
| 155 | + } |
| 156 | + if ( $db->isOpen() ) { |
| 157 | + $index = wfStrencode( $index ); |
| 158 | + $res = $db->query( "SELECT blob_data FROM $dbName.$tblName WHERE blob_index='$index'", $fname ); |
| 159 | + $row = $db->fetchObject( $res ); |
| 160 | + $text = $row->text_data; |
| 161 | + } |
| 162 | + } |
| 163 | + break; |
| 164 | + case 'file': |
| 165 | + # File locations are of the form file://<filename>, relative to the current directory |
| 166 | + if ( preg_match( '/^file:\/\/(.*)$', $location, $matches ) ) |
| 167 | + $filename = strstr( $location, 'file://' ); |
| 168 | + $text = @file_get_contents( $matches[1] ); |
| 169 | + } |
| 170 | + if ( $text !== false ) { |
| 171 | + # Got text, now we need to interpret it |
| 172 | + # The first line contains information about how to do this |
| 173 | + $p = strpos( $text, '\n' ); |
| 174 | + $type = substr( $text, 0, $p ); |
| 175 | + $text = substr( $text, $p + 1 ); |
| 176 | + switch ( $type ) { |
| 177 | + case 'plain': |
| 178 | + break; |
| 179 | + case 'gzip': |
| 180 | + $text = gzinflate( $text ); |
| 181 | + break; |
| 182 | + case 'object': |
| 183 | + $object = unserialize( $text ); |
| 184 | + $text = $object->getItem( $hash ); |
| 185 | + break; |
| 186 | + default: |
| 187 | + $text = false; |
| 188 | + } |
| 189 | + } |
| 190 | + wfProfileOut( $fname ); |
| 191 | + return $text; |
| 192 | + } |
| 193 | + |
64 | 194 | # Note that getContent/loadContent may follow redirects if |
65 | 195 | # not told otherwise, and so may cause a change to mTitle. |
66 | 196 | |
Index: trunk/phase3/includes/HistoryBlob.php |
— | — | @@ -0,0 +1,64 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +# Pure virtual parent |
| 5 | +class HistoryBlob |
| 6 | +{ |
| 7 | + function setMeta() {} |
| 8 | + function getMeta() {} |
| 9 | + function addItem() {} |
| 10 | + function getItem() {} |
| 11 | +} |
| 12 | + |
| 13 | +# The real object |
| 14 | +class ConcatenatedGzipHistoryBlob |
| 15 | +{ |
| 16 | + /* private */ var $mVersion = 0, $mCompressed = false, $mItems = array(); |
| 17 | + |
| 18 | + function HistoryBlob() { |
| 19 | + if ( !function_exists( 'gzdeflate' ) ) { |
| 20 | + die( "Need zlib support to read or write this kind of history object (ConcatenatedGzipHistoryBlob)\n" ); |
| 21 | + } |
| 22 | + } |
| 23 | + |
| 24 | + function setMeta( $metaData ) { |
| 25 | + $this->uncompress(); |
| 26 | + $this->mItems['meta'] = $metaData; |
| 27 | + } |
| 28 | + |
| 29 | + function getMeta() { |
| 30 | + $this->uncompress(); |
| 31 | + return $this->mItems['meta']; |
| 32 | + } |
| 33 | + |
| 34 | + function addItem( $text ) { |
| 35 | + $this->uncompress(); |
| 36 | + $this->mItems[md5($text)] = $text; |
| 37 | + } |
| 38 | + |
| 39 | + function getItem( $hash ) { |
| 40 | + $this->compress(); |
| 41 | + return $this->mItems[$hash]; |
| 42 | + } |
| 43 | + |
| 44 | + function compress() { |
| 45 | + if ( !$this->mCompressed ) { |
| 46 | + $this->mItems = gzdeflate( serialize( $this->mItems ) ); |
| 47 | + $this->mCompressed = true; |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + function uncompress() { |
| 52 | + if ( $this->mCompressed ) { |
| 53 | + $this->mItems = unserialize( gzinflate( $this->mItems ) ); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + function __sleep() { |
| 58 | + compress(); |
| 59 | + } |
| 60 | + |
| 61 | + function __wakeup() { |
| 62 | + uncompress(); |
| 63 | + } |
| 64 | +} |
| 65 | +?> |
Property changes on: trunk/phase3/includes/HistoryBlob.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 66 | + native |
Added: svn:keywords |
2 | 67 | + Author Date Id Revision |