Index: branches/filerepo-work/phase3/includes/GlobalFunctions.php |
— | — | @@ -2276,11 +2276,14 @@ |
2277 | 2277 | /** |
2278 | 2278 | * Find a file. |
2279 | 2279 | * Shortcut for RepoGroup::singleton()->findFile() |
2280 | | - * @param mixed $title Title object or string. May be interwiki. |
| 2280 | + * @param mixed $title Title object or string. May be interwiki. |
| 2281 | + * @param mixed $time Requested time for an archived image, or false for the |
| 2282 | + * current version. An image object will be returned which |
| 2283 | + * existed at or before the specified time. |
2281 | 2284 | * @return File, or false if the file does not exist |
2282 | 2285 | */ |
2283 | | -function wfFindFile( $title ) { |
2284 | | - return RepoGroup::singleton()->findFile( $title ); |
| 2286 | +function wfFindFile( $title, $time = false ) { |
| 2287 | + return RepoGroup::singleton()->findFile( $title, $time ); |
2285 | 2288 | } |
2286 | 2289 | |
2287 | 2290 | /** |
Index: branches/filerepo-work/phase3/includes/filerepo/OldLocalFile.php |
— | — | @@ -0,0 +1,145 @@ |
| 2 | +<?php
|
| 3 | +
|
| 4 | +/**
|
| 5 | + * Class to represent a file in the oldimage table
|
| 6 | + *
|
| 7 | + * @addtogroup FileRepo
|
| 8 | + */
|
| 9 | +class OldLocalFile extends LocalFile {
|
| 10 | + var $requestedTime, $archive_name;
|
| 11 | +
|
| 12 | + const CACHE_VERSION = 1;
|
| 13 | + const MAX_CACHE_ROWS = 20;
|
| 14 | +
|
| 15 | + function newFromTitle( $title, $repo, $time ) {
|
| 16 | + return new OldLocalFile( $title, $repo, $time );
|
| 17 | + }
|
| 18 | +
|
| 19 | + function __construct( $title, $repo, $time ) {
|
| 20 | + parent::__construct( $title, $repo );
|
| 21 | + $this->requestedTime = $time;
|
| 22 | + }
|
| 23 | +
|
| 24 | + function getCacheKey() {
|
| 25 | + $hashedName = md5($this->getName());
|
| 26 | + return wfMemcKey( 'oldfile', $hashedName );
|
| 27 | + }
|
| 28 | +
|
| 29 | + /**
|
| 30 | + * Try to load file metadata from memcached. Returns true on success.
|
| 31 | + */
|
| 32 | + function loadFromCache() {
|
| 33 | + global $wgMemc;
|
| 34 | + wfProfileIn( __METHOD__ );
|
| 35 | + $this->dataLoaded = false;
|
| 36 | + $key = $this->getCacheKey();
|
| 37 | + if ( !$key ) {
|
| 38 | + return false;
|
| 39 | + }
|
| 40 | + $oldImages = $wgMemc->get( $key );
|
| 41 | +
|
| 42 | + if ( isset( $oldImages['version'] ) && $oldImages['version'] == MW_OLDFILE_VERSION ) {
|
| 43 | + unset( $oldImages['version'];
|
| 44 | + $more = isset( $oldImages['more'] );
|
| 45 | + unset( $oldImages['more'] );
|
| 46 | + krsort( $oldImages );
|
| 47 | + $found = false;
|
| 48 | + foreach ( $oldImages as $timestamp => $info ) {
|
| 49 | + if ( $timestamp <= $this->desiredTimestamp ) {
|
| 50 | + $found = true;
|
| 51 | + break;
|
| 52 | + }
|
| 53 | + }
|
| 54 | + if ( $found ) {
|
| 55 | + wfDebug( "Pulling file metadata from cache key {$key}[{$timestamp}]\n" );
|
| 56 | + $this->loadFromRow( (object)$cachedValues ) );
|
| 57 | + $this->fileExists = true;
|
| 58 | + $this->dataLoaded = true;
|
| 59 | + } elseif ( $more ) {
|
| 60 | + wfDebug( "Cache key was truncated, oldimage row might be found in the database\n" );
|
| 61 | + } else {
|
| 62 | + wfDebug( "Image did not exist at the specified time.\n" );
|
| 63 | + $this->fileExists = false;
|
| 64 | + $this->dataLoaded = true;
|
| 65 | + }
|
| 66 | + }
|
| 67 | +
|
| 68 | + if ( $this->dataLoaded ) {
|
| 69 | + wfIncrStats( 'image_cache_hit' );
|
| 70 | + } else {
|
| 71 | + wfIncrStats( 'image_cache_miss' );
|
| 72 | + }
|
| 73 | +
|
| 74 | + wfProfileOut( __METHOD__ );
|
| 75 | + return $this->dataLoaded;
|
| 76 | + }
|
| 77 | +
|
| 78 | + function saveToCache() {
|
| 79 | + // Cache the entire history of the image (up to MAX_CACHE_ROWS).
|
| 80 | + // This is expensive, so we only do it if $wgMemc is real
|
| 81 | + global $wgMemc;
|
| 82 | + if ( $wgMemc instanceof FakeMemcachedClient ) {
|
| 83 | + return;
|
| 84 | + }
|
| 85 | + $key = $this->getCacheKey();
|
| 86 | + if ( !$key ) {
|
| 87 | + return;
|
| 88 | + }
|
| 89 | + wfProfileIn( __METHOD__ );
|
| 90 | +
|
| 91 | + $dbr = $this->repo->getSlaveDB();
|
| 92 | + $res = $dbr->select( 'oldimage', $this->getCacheFields(),
|
| 93 | + array( 'oi_name' => $this->getName() ), __METHOD__,
|
| 94 | + array(
|
| 95 | + 'LIMIT' => self::MAX_CACHE_ROWS + 1,
|
| 96 | + 'ORDER BY' => 'oi_timestamp DESC',
|
| 97 | + ));
|
| 98 | + $cache = array( 'version' => self::CACHE_VERSION );
|
| 99 | + $numRows = $dbr->numRows( $res );
|
| 100 | + if ( $numRows > self::MAX_CACHE_ROWS ) {
|
| 101 | + $cache['more'] = true;
|
| 102 | + $numRows--;
|
| 103 | + }
|
| 104 | + for ( $i = 0; $i < $numRows; $i++ ) {
|
| 105 | + $row = $dbr->fetchObject( $res );
|
| 106 | + $this->decodeRow( $row, 'oi_' );
|
| 107 | + $cache[$row->oi_timestamp] = $row;
|
| 108 | + }
|
| 109 | + $dbr->freeResult( $res );
|
| 110 | + $wgMemc->set( $key, $cache, 7*86400 /* 1 week */ );
|
| 111 | + wfProfileOut( __METHOD__ );
|
| 112 | + }
|
| 113 | +
|
| 114 | + function loadFromDB() {
|
| 115 | + wfProfileIn( __METHOD__ );
|
| 116 | + $dbr = $this->repo->getSlaveDB();
|
| 117 | + $row = $dbr->selectRow( 'oldimage', $this->getCacheFields( 'oi_' ),
|
| 118 | + array(
|
| 119 | + 'oi_name' => $this->getName(),
|
| 120 | + 'oi_timestamp <= ' . $this->requestedTimestamp
|
| 121 | + ), __METHOD__, array( 'ORDER BY' => 'oi_timestamp DESC' ) );
|
| 122 | + if ( $row ) {
|
| 123 | + $this->decodeRow( $row, 'oi_' );
|
| 124 | + $this->loadFromRow( $row, 'oi_' );
|
| 125 | + } else {
|
| 126 | + $this->fileExists = false;
|
| 127 | + }
|
| 128 | + $this->dataLoaded = true;
|
| 129 | + }
|
| 130 | +
|
| 131 | + function getCacheFields( $prefix = 'img_' ) {
|
| 132 | + $fields = parent::getCacheFields( $prefix );
|
| 133 | + $fields[] = $prefix . 'archive_name';
|
| 134 | + }
|
| 135 | +
|
| 136 | + function getRel() {
|
| 137 | + return 'archive/' . $this->getHashPath() . '/' . $this->archive_name;
|
| 138 | + }
|
| 139 | +
|
| 140 | + function getUrlRel() {
|
| 141 | + return 'archive/' . $this->getHashPath() . '/' . urlencode( $this->archive_name );
|
| 142 | + }
|
| 143 | +}
|
| 144 | +
|
| 145 | +
|
| 146 | +?>
|
Index: branches/filerepo-work/phase3/includes/filerepo/LocalFile.php |
— | — | @@ -5,7 +5,7 @@ |
6 | 6 | /** |
7 | 7 | * Bump this number when serialized cache records may be incompatible. |
8 | 8 | */ |
9 | | -define( 'MW_FILE_VERSION', 3 ); |
| 9 | +define( 'MW_FILE_VERSION', 4 ); |
10 | 10 | |
11 | 11 | /** |
12 | 12 | * Class to represent a local file in the wiki's own database |
— | — | @@ -27,10 +27,13 @@ |
28 | 28 | $height, # | |
29 | 29 | $bits, # --- returned by getimagesize (loadFromXxx) |
30 | 30 | $attr, # / |
31 | | - $type, # MEDIATYPE_xxx (bitmap, drawing, audio...) |
| 31 | + $media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...) |
32 | 32 | $mime, # MIME type, determined by MimeMagic::guessMimeType |
| 33 | + $major_mime, # Major mime type |
| 34 | + $minor_mine, # Minor mime type |
33 | 35 | $size, # Size in bytes (loadFromXxx) |
34 | 36 | $metadata, # Metadata |
| 37 | + $timestamp, # Upload timestamp |
35 | 38 | $dataLoaded; # Whether or not all this has been loaded from the database (loadFromXxx) |
36 | 39 | |
37 | 40 | /**#@-*/ |
— | — | @@ -71,20 +74,9 @@ |
72 | 75 | $cachedValues = $wgMemc->get( $key ); |
73 | 76 | |
74 | 77 | // Check if the key existed and belongs to this version of MediaWiki |
75 | | - if (!empty($cachedValues) && is_array($cachedValues) |
76 | | - && isset($cachedValues['version']) && ( $cachedValues['version'] == MW_FILE_VERSION ) |
77 | | - && isset( $cachedValues['mime'] ) && isset( $cachedValues['metadata'] ) ) |
78 | | - { |
| 78 | + if ( isset($cachedValues['version']) && ( $cachedValues['version'] == MW_FILE_VERSION ) ) { |
79 | 79 | wfDebug( "Pulling file metadata from cache key $key\n" ); |
80 | | - $this->fileExists = $cachedValues['fileExists']; |
81 | | - $this->width = $cachedValues['width']; |
82 | | - $this->height = $cachedValues['height']; |
83 | | - $this->bits = $cachedValues['bits']; |
84 | | - $this->type = $cachedValues['type']; |
85 | | - $this->mime = $cachedValues['mime']; |
86 | | - $this->metadata = $cachedValues['metadata']; |
87 | | - $this->size = $cachedValues['size']; |
88 | | - $this->dataLoaded = true; |
| 80 | + $this->loadFromRow( $cachedValues, '' ); |
89 | 81 | } |
90 | 82 | if ( $this->dataLoaded ) { |
91 | 83 | wfIncrStats( 'image_cache_hit' ); |
— | — | @@ -106,25 +98,19 @@ |
107 | 99 | if ( !$key ) { |
108 | 100 | return; |
109 | 101 | } |
110 | | - $cachedValues = array( |
111 | | - 'version' => MW_FILE_VERSION, |
112 | | - 'fileExists' => $this->fileExists, |
113 | | - 'width' => $this->width, |
114 | | - 'height' => $this->height, |
115 | | - 'bits' => $this->bits, |
116 | | - 'type' => $this->type, |
117 | | - 'mime' => $this->mime, |
118 | | - 'metadata' => $this->metadata, |
119 | | - 'size' => $this->size ); |
| 102 | + $fields = $this->getCacheFields( '' ); |
| 103 | + $cache = array( 'version' => MW_FILE_VERSION ); |
| 104 | + foreach ( $fields as $field ) { |
| 105 | + $cache[$field] = $this->$field; |
| 106 | + } |
120 | 107 | |
121 | | - $wgMemc->set( $key, $cachedValues, 60 * 60 * 24 * 7 ); // A week |
| 108 | + $wgMemc->set( $key, $cache, 60 * 60 * 24 * 7 ); // A week |
122 | 109 | } |
123 | 110 | |
124 | 111 | /** |
125 | 112 | * Load metadata from the file itself |
126 | 113 | */ |
127 | 114 | function loadFromFile() { |
128 | | - global $wgContLang; |
129 | 115 | wfProfileIn( __METHOD__ ); |
130 | 116 | $path = $this->getPath(); |
131 | 117 | $this->fileExists = file_exists( $path ); |
— | — | @@ -134,7 +120,7 @@ |
135 | 121 | $magic=& MimeMagic::singleton(); |
136 | 122 | |
137 | 123 | $this->mime = $magic->guessMimeType($path,true); |
138 | | - $this->type = $magic->getMediaType($path,$this->mime); |
| 124 | + $this->media_type = $magic->getMediaType($path,$this->mime); |
139 | 125 | $handler = MediaHandler::getHandler( $this->mime ); |
140 | 126 | |
141 | 127 | # Get size in bytes |
— | — | @@ -152,7 +138,7 @@ |
153 | 139 | wfDebug(__METHOD__.": $path loaded, {$this->size} bytes, {$this->mime}.\n"); |
154 | 140 | } else { |
155 | 141 | $this->mime = NULL; |
156 | | - $this->type = MEDIATYPE_UNKNOWN; |
| 142 | + $this->media_type = MEDIATYPE_UNKNOWN; |
157 | 143 | $this->metadata = ''; |
158 | 144 | wfDebug(__METHOD__.": $path NOT FOUND!\n"); |
159 | 145 | } |
— | — | @@ -178,33 +164,40 @@ |
179 | 165 | wfProfileOut( __METHOD__ ); |
180 | 166 | } |
181 | 167 | |
| 168 | + function getCacheFields( $prefix = 'img_' ) { |
| 169 | + static $fields = array( 'size', 'width', 'height', 'bits', 'media_type', |
| 170 | + 'major_mime', 'minor_mime', 'metadata', 'timestamp' ); |
| 171 | + static $results = array(); |
| 172 | + if ( $prefix = '' ) { |
| 173 | + return $fields; |
| 174 | + } |
| 175 | + if ( !isset( $results[$prefix] ) ) { |
| 176 | + $prefixedFields = array(); |
| 177 | + foreach ( $fields as $field ) { |
| 178 | + $prefixedFields[] = $prefix . $field; |
| 179 | + } |
| 180 | + $fields[$prefix] = $prefixedFields; |
| 181 | + } |
| 182 | + return $fields[$prefix]; |
| 183 | + } |
| 184 | + |
182 | 185 | /** |
183 | 186 | * Load file metadata from the DB |
184 | 187 | */ |
185 | 188 | function loadFromDB() { |
186 | | - global $wgContLang; |
187 | 189 | wfProfileIn( __METHOD__ ); |
188 | 190 | |
189 | 191 | $dbr = $this->repo->getSlaveDB(); |
190 | 192 | |
191 | | - $row = $dbr->selectRow( 'image', |
192 | | - array( 'img_size', 'img_width', 'img_height', 'img_bits', |
193 | | - 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), |
| 193 | + $row = $dbr->selectRow( 'image', $this->getCacheFields( 'img_' ), |
194 | 194 | array( 'img_name' => $this->getName() ), __METHOD__ ); |
195 | 195 | if ( $row ) { |
196 | | - $this->fileExists = true; |
| 196 | + $this->decodeRow( $row ); |
197 | 197 | $this->loadFromRow( $row ); |
198 | 198 | // Check for rows from a previous schema, quietly upgrade them |
199 | 199 | $this->maybeUpgradeRow(); |
200 | 200 | } else { |
201 | | - $this->size = 0; |
202 | | - $this->width = 0; |
203 | | - $this->height = 0; |
204 | | - $this->bits = 0; |
205 | | - $this->type = 0; |
206 | 201 | $this->fileExists = false; |
207 | | - $this->metadata = ''; |
208 | | - $this->mime = false; |
209 | 202 | } |
210 | 203 | |
211 | 204 | # Unconditionally set loaded=true, we don't want the accessors constantly rechecking |
— | — | @@ -212,26 +205,39 @@ |
213 | 206 | wfProfileOut( __METHOD__ ); |
214 | 207 | } |
215 | 208 | |
| 209 | + function decodeRow( &$row, $prefix = 'img_' ) { |
| 210 | + $tsName = $prefix . 'timestamp'; |
| 211 | + $row->$tsName = wfTimestamp( $row->$tsName ); |
| 212 | + } |
| 213 | + |
| 214 | + function encodeRow( &$row, $db, $prefix = 'img_' ) { |
| 215 | + $tsName = $prefix . 'timestamp'; |
| 216 | + $row->$tsName = $db->timestamp( $row->$tsName ); |
| 217 | + } |
| 218 | + |
216 | 219 | /* |
217 | 220 | * Load file metadata from a DB result row |
218 | 221 | */ |
219 | | - function loadFromRow( &$row ) { |
220 | | - $this->size = $row->img_size; |
221 | | - $this->width = $row->img_width; |
222 | | - $this->height = $row->img_height; |
223 | | - $this->bits = $row->img_bits; |
224 | | - $this->type = $row->img_media_type; |
225 | | - |
226 | | - $major= $row->img_major_mime; |
227 | | - $minor= $row->img_minor_mime; |
228 | | - |
229 | | - if (!$major) $this->mime = "unknown/unknown"; |
230 | | - else { |
231 | | - if (!$minor) $minor= "unknown"; |
232 | | - $this->mime = $major.'/'.$minor; |
| 222 | + function loadFromRow( $row, $prefix = 'img_' ) { |
| 223 | + $array = (array)$row; |
| 224 | + $prefixLength = strlen( $prefix ); |
| 225 | + // Sanity check prefix once |
| 226 | + if ( substr( key( $array ), 0, $prefixLength ) !== $prefix ) { |
| 227 | + throw new MWException( __METHOD__. ': incorrect $prefix parameter' ); |
| 228 | + } |
| 229 | + foreach ( $array as $name => $value ) { |
| 230 | + $deprefixedName = substr( $name, $prefixLength ); |
| 231 | + $this->$deprefixedName = $value; |
233 | 232 | } |
234 | | - $this->metadata = $row->img_metadata; |
235 | | - |
| 233 | + if ( !$this->major_mime ) { |
| 234 | + $this->mime = "unknown/unknown"; |
| 235 | + } else { |
| 236 | + if (!$this->minor_mime) { |
| 237 | + $this->minor_mime = "unknown"; |
| 238 | + } |
| 239 | + $this->mime = $this->major_mime.'/'.$this->minor_mime; |
| 240 | + } |
| 241 | + $this->fileExists = true; |
236 | 242 | $this->dataLoaded = true; |
237 | 243 | } |
238 | 244 | |
— | — | @@ -242,12 +248,7 @@ |
243 | 249 | if ( !$this->dataLoaded ) { |
244 | 250 | if ( !$this->loadFromCache() ) { |
245 | 251 | $this->loadFromDB(); |
246 | | - if ( $this->fileExists ) { |
247 | | - // FIXME: We can do negative caching for local files, because the cache |
248 | | - // will be purged on upload. But we can't do it when shared files |
249 | | - // are enabled, since updates to that won't purge foreign caches. |
250 | | - $this->saveToCache(); |
251 | | - } |
| 252 | + $this->saveToCache(); |
252 | 253 | } |
253 | 254 | $this->dataLoaded = true; |
254 | 255 | } |
— | — | @@ -257,7 +258,7 @@ |
258 | 259 | * Upgrade a row if it needs it |
259 | 260 | */ |
260 | 261 | function maybeUpgradeRow() { |
261 | | - if ( is_null($this->type) || $this->mime == 'image/svg' ) { |
| 262 | + if ( is_null($this->media_type) || $this->mime == 'image/svg' ) { |
262 | 263 | $this->upgradeRow(); |
263 | 264 | } else { |
264 | 265 | $handler = $this->getHandler(); |
— | — | @@ -285,7 +286,7 @@ |
286 | 287 | 'img_width' => $this->width, |
287 | 288 | 'img_height' => $this->height, |
288 | 289 | 'img_bits' => $this->bits, |
289 | | - 'img_media_type' => $this->type, |
| 290 | + 'img_media_type' => $this->media_type, |
290 | 291 | 'img_major_mime' => $major, |
291 | 292 | 'img_minor_mime' => $minor, |
292 | 293 | 'img_metadata' => $this->metadata, |
— | — | @@ -372,7 +373,7 @@ |
373 | 374 | */ |
374 | 375 | function getMediaType() { |
375 | 376 | $this->load(); |
376 | | - return $this->type; |
| 377 | + return $this->media_type; |
377 | 378 | } |
378 | 379 | |
379 | 380 | /** canRender inherited */ |
— | — | @@ -632,7 +633,7 @@ |
633 | 634 | 'img_width' => intval( $this->width ), |
634 | 635 | 'img_height' => intval( $this->height ), |
635 | 636 | 'img_bits' => $this->bits, |
636 | | - 'img_media_type' => $this->type, |
| 637 | + 'img_media_type' => $this->media_type, |
637 | 638 | 'img_major_mime' => $major, |
638 | 639 | 'img_minor_mime' => $minor, |
639 | 640 | 'img_timestamp' => $now, |
— | — | @@ -670,7 +671,7 @@ |
671 | 672 | 'img_width' => intval( $this->width ), |
672 | 673 | 'img_height' => intval( $this->height ), |
673 | 674 | 'img_bits' => $this->bits, |
674 | | - 'img_media_type' => $this->type, |
| 675 | + 'img_media_type' => $this->media_type, |
675 | 676 | 'img_major_mime' => $major, |
676 | 677 | 'img_minor_mime' => $minor, |
677 | 678 | 'img_timestamp' => $now, |
— | — | @@ -1254,14 +1255,18 @@ |
1255 | 1256 | return $html; |
1256 | 1257 | } |
1257 | 1258 | |
1258 | | -} //class |
| 1259 | + function getTimestamp() { |
| 1260 | + $this->load(); |
| 1261 | + return $this->timestamp; |
| 1262 | + } |
| 1263 | +} // LocalFile class |
1259 | 1264 | |
1260 | 1265 | /** |
1261 | 1266 | * Backwards compatibility class |
1262 | 1267 | */ |
1263 | 1268 | class Image extends LocalFile { |
1264 | 1269 | function __construct( $title ) { |
1265 | | - $repo = FileRepoGroup::singleton()->getRepo( 0 ); |
| 1270 | + $repo = FileRepoGroup::singleton()->getLocalRepo(); |
1266 | 1271 | parent::__construct( $title, $repo ); |
1267 | 1272 | } |
1268 | 1273 | } |
Index: branches/filerepo-work/phase3/includes/filerepo/FSRepo.php |
— | — | @@ -33,21 +33,44 @@ |
34 | 34 | /** |
35 | 35 | * Create a new File object from the local repository |
36 | 36 | * @param mixed $title Title object or string |
| 37 | + * @param mixed $time Time at which the image is supposed to have existed. |
| 38 | + * If this is specified, the returned object will be an |
| 39 | + * instance of the repository's old file class instead of |
| 40 | + * a current file. Repositories not supporting version |
| 41 | + * control should return false if this parameter is set. |
37 | 42 | */ |
38 | | - |
39 | | - function newFile( $title ) { |
40 | | - if ( $title instanceof Title ) { |
41 | | - return call_user_func( $this->fileFactory, $title, $this ); |
42 | | - } else { |
| 43 | + function newFile( $title, $time = false ) { |
| 44 | + if ( !($title instanceof Title) ) { |
43 | 45 | $title = Title::makeTitleSafe( NS_IMAGE, $title ); |
44 | | - if ( is_object( $title ) ) { |
45 | | - return call_user_func( $this->fileFactory, $title, $this ); |
46 | | - } else { |
47 | | - return NULL; |
| 46 | + if ( !is_object( $title ) ) { |
| 47 | + return null; |
48 | 48 | } |
49 | 49 | } |
| 50 | + if ( $time ) { |
| 51 | + return call_user_func( $this->oldFileFactor, $title, $this, $time ); |
| 52 | + } else { |
| 53 | + return call_user_func( $this->fileFactory, $title, $this ); |
| 54 | + } |
50 | 55 | } |
51 | 56 | |
| 57 | + /** |
| 58 | + * Find an instance of the named file that existed at the specified time |
| 59 | + * Returns false if the file did not exist. Repositories not supporting |
| 60 | + * version control should return false if the time is specified. |
| 61 | + * |
| 62 | + * @param mixed $time 14-character timestamp, or false for the current version |
| 63 | + */ |
| 64 | + function findFile( $title, $time = false ) { |
| 65 | + $img = $this->newFile( $title ); |
| 66 | + if ( $img->exists() && $img->getTimestamp() <= $time ) { |
| 67 | + return $img; |
| 68 | + } |
| 69 | + $img = $this->newFile( $title, $time ); |
| 70 | + if ( $img->exists() ) { |
| 71 | + return $img; |
| 72 | + } |
| 73 | + } |
| 74 | + |
52 | 75 | function getRootDirectory() { |
53 | 76 | return $this->directory; |
54 | 77 | } |
Index: branches/filerepo-work/phase3/includes/filerepo/File.php |
— | — | @@ -90,6 +90,7 @@ |
91 | 91 | /** |
92 | 92 | * Upgrade the database row if there is one |
93 | 93 | * Called by ImagePage |
| 94 | + * STUB |
94 | 95 | */ |
95 | 96 | function upgradeRow() {} |
96 | 97 | |
— | — | @@ -941,6 +942,17 @@ |
942 | 943 | return false; |
943 | 944 | } |
944 | 945 | } |
| 946 | + |
| 947 | + /** |
| 948 | + * Get the 14-character timestamp of the file upload, or false if |
| 949 | + */ |
| 950 | + function getTimestmap() { |
| 951 | + $path = $this->getPath(); |
| 952 | + if ( !file_exists( $path ) ) { |
| 953 | + return false; |
| 954 | + } |
| 955 | + return wfTimestamp( filemtime( $path ) ); |
| 956 | + } |
945 | 957 | } |
946 | 958 | |
947 | 959 | ?> |
Index: branches/filerepo-work/phase3/includes/filerepo/RepoGroup.php |
— | — | @@ -31,20 +31,22 @@ |
32 | 32 | * Search repositories for an image. |
33 | 33 | * You can also use wfGetFile() to do this. |
34 | 34 | * @param mixed $title Title object or string |
| 35 | + * @param mixed $time The 14-char timestamp before which the file should |
| 36 | + * have been uploaded, or false for the current version |
35 | 37 | * @return File object or false if it is not found |
36 | 38 | */ |
37 | | - function findFile( $title ) { |
| 39 | + function findFile( $title, $time = false ) { |
38 | 40 | if ( !$this->reposInitialised ) { |
39 | 41 | $this->initialiseRepos(); |
40 | 42 | } |
41 | 43 | |
42 | | - $image = $this->localRepo->newFile( $title ); |
43 | | - if ( $image->exists() ) { |
| 44 | + $image = $this->localRepo->findFile( $title, $time ); |
| 45 | + if ( $image ) { |
44 | 46 | return $image; |
45 | 47 | } |
46 | 48 | foreach ( $this->foreignRepos as $repo ) { |
47 | | - $image = $repo->newFile( $title ); |
48 | | - if ( $image->exists() ) { |
| 49 | + $image = $repo->findFile( $image, $time ); |
| 50 | + if ( $image ) { |
49 | 51 | return $image; |
50 | 52 | } |
51 | 53 | } |