r22590 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r22589‎ | r22590 | r22591 >
Date:04:44, 31 May 2007
Author:aaron
Status:old
Tags:
Comment:
*Update branch
Modified paths:
  • /branches/phase3_rev_deleted/includes/Article.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/AutoLoader.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/CategoryPage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ChangesList.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/DatabasePostgres.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/DefaultSettings.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Defines.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ExternalEdit.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/GlobalFunctions.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Image.php (deleted) (history)
  • /branches/phase3_rev_deleted/includes/ImageFunctions.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ImageGallery.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ImagePage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ImageQueryPage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Linker.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/MediaTransformOutput.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/OutputPage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Parser.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/ParserOutput.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/QueryPage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Revision.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SearchEngine.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Setup.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Skin.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialBlockip.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialImagelist.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialImport.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialLog.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialMIMEsearch.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialNewimages.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialPage.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialRevisiondelete.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialUndelete.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialUpload.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/SpecialWhatlinkshere.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/StreamFile.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/Title.php (modified) (history)
  • /branches/phase3_rev_deleted/includes/memcached-client.php (modified) (history)
  • /branches/phase3_rev_deleted/languages/messages/MessagesEn.php (modified) (history)

Diff [purge]

Index: branches/phase3_rev_deleted/includes/Image.php
@@ -1,2351 +0,0 @@
2 -<?php
3 -/**
4 - */
5 -
6 -/**
7 - * NOTE FOR WINDOWS USERS:
8 - * To enable EXIF functions, add the folloing lines to the
9 - * "Windows extensions" section of php.ini:
10 - *
11 - * extension=extensions/php_mbstring.dll
12 - * extension=extensions/php_exif.dll
13 - */
14 -
15 -/**
16 - * Bump this number when serialized cache records may be incompatible.
17 - */
18 -define( 'MW_IMAGE_VERSION', 2 );
19 -
20 -/**
21 - * Class to represent an image
22 - *
23 - * Provides methods to retrieve paths (physical, logical, URL),
24 - * to generate thumbnails or for uploading.
25 - *
26 - * @addtogroup Media
27 - */
28 -class Image
29 -{
30 - const DELETED_FILE = 1;
31 - const DELETED_COMMENT = 2;
32 - const DELETED_USER = 4;
33 - const DELETED_RESTRICTED = 8;
34 - const RENDER_NOW = 1;
35 -
36 - /**#@+
37 - * @private
38 - */
39 - var $name, # name of the image (constructor)
40 - $imagePath, # Path of the image (loadFromXxx)
41 - $url, # Image URL (accessor)
42 - $title, # Title object for this image (constructor)
43 - $fileExists, # does the image file exist on disk? (loadFromXxx)
44 - $fromSharedDirectory, # load this image from $wgSharedUploadDirectory (loadFromXxx)
45 - $historyLine, # Number of line to return by nextHistoryLine() (constructor)
46 - $historyRes, # result of the query for the image's history (nextHistoryLine)
47 - $width, # \
48 - $height, # |
49 - $bits, # --- returned by getimagesize (loadFromXxx)
50 - $attr, # /
51 - $type, # MEDIATYPE_xxx (bitmap, drawing, audio...)
52 - $mime, # MIME type, determined by MimeMagic::guessMimeType
53 - $extension, # The file extension (constructor)
54 - $size, # Size in bytes (loadFromXxx)
55 - $metadata, # Metadata
56 - $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx)
57 - $page, # Page to render when creating thumbnails
58 - $lastError, # Error string associated with a thumbnail display error
59 - $timeframe, # Loads the image as it was at this time (if public)
60 - $oldimage; # Is this an old version?
61 -
62 -
63 - /**#@-*/
64 -
65 - /**
66 - * Create an Image object from an image name
67 - *
68 - * @param string $name name of the image, used to create a title object using Title::makeTitleSafe
69 - * @return Image
70 - * @public
71 - */
72 - public static function newFromName( $name ) {
73 - $title = Title::makeTitleSafe( NS_IMAGE, $name );
74 - if ( is_object( $title ) ) {
75 - return new Image( $title );
76 - } else {
77 - return NULL;
78 - }
79 - }
80 -
81 - /**
82 - * Obsolete factory function, use constructor
83 - * @param Title $title
84 - * @return Image
85 - * @deprecated
86 - */
87 - function newFromTitle( $title ) {
88 - return new Image( $title );
89 - }
90 -
91 - /**
92 - * Constructor
93 - * @param Title $title
94 - * @return void
95 - */
96 - function Image( $title, $timeframe=null ) {
97 - if( !is_object( $title ) ) {
98 - throw new MWException( 'Image constructor given bogus title.' );
99 - }
100 - $this->title =& $title;
101 - // Name used for hash dir
102 - $this->name = $title->getDBkey();
103 - $this->fileName = $this->name;
104 - // $timeframe is for getting images from a time period
105 - $this->timeframe = $timeframe;
106 - $this->oldimage = false;
107 -
108 - $this->metadata = '';
109 -
110 - $n = strrpos( $this->name, '.' );
111 - $this->extension = Image::normalizeExtension( $n ?
112 - substr( $this->name, $n + 1 ) : '' );
113 - $this->historyLine = 0;
114 -
115 - $this->dataLoaded = false;
116 - }
117 -
118 - /**
119 - * Normalize a file extension to the common form, and ensure it's clean.
120 - * Extensions with non-alphanumeric characters will be discarded.
121 - *
122 - * @param string $ext (without the .)
123 - * @return string
124 - */
125 - static function normalizeExtension( $ext ) {
126 - $lower = strtolower( $ext );
127 - $squish = array(
128 - 'htm' => 'html',
129 - 'jpeg' => 'jpg',
130 - 'mpeg' => 'mpg',
131 - 'tiff' => 'tif' );
132 - if( isset( $squish[$lower] ) ) {
133 - return $squish[$lower];
134 - } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) {
135 - return $lower;
136 - } else {
137 - return '';
138 - }
139 - }
140 -
141 - /**
142 - * Get the memcached keys
143 - * @return array[int]mixed Returns an array, first element is the local cache key, second is the shared cache key, if there is one
144 - */
145 - function getCacheKeys( ) {
146 - global $wgUseSharedUploads, $wgSharedUploadDBname, $wgCacheSharedUploads;
147 -
148 - $hashedName = md5($this->name);
149 - $keys = array( wfMemcKey( 'Image', $hashedName ) );
150 - if ( $wgUseSharedUploads && $wgSharedUploadDBname && $wgCacheSharedUploads ) {
151 - $keys[] = wfForeignMemcKey( $wgSharedUploadDBname, false, 'Image', $hashedName );
152 - }
153 - return $keys;
154 - }
155 -
156 - /**
157 - * Try to load image metadata from memcached. Returns true on success.
158 - */
159 - function loadFromCache() {
160 - global $wgUseSharedUploads, $wgMemc;
161 - wfProfileIn( __METHOD__ );
162 - $this->dataLoaded = false;
163 - $keys = $this->getCacheKeys();
164 - $cachedValues = $wgMemc->get( $keys[0] );
165 -
166 - // Check if the key existed and belongs to this version of MediaWiki
167 - if (!empty($cachedValues) && is_array($cachedValues)
168 - && isset($cachedValues['version']) && ( $cachedValues['version'] == MW_IMAGE_VERSION )
169 - && isset( $cachedValues['mime'] ) && isset( $cachedValues['metadata'] ) )
170 - {
171 - if ( $wgUseSharedUploads && $cachedValues['fromShared']) {
172 - # if this is shared file, we need to check if image
173 - # in shared repository has not changed
174 - if ( isset( $keys[1] ) ) {
175 - $commonsCachedValues = $wgMemc->get( $keys[1] );
176 - if (!empty($commonsCachedValues) && is_array($commonsCachedValues)
177 - && isset($commonsCachedValues['version'])
178 - && ( $commonsCachedValues['version'] == MW_IMAGE_VERSION )
179 - && isset($commonsCachedValues['mime'])) {
180 - wfDebug( "Pulling image metadata from shared repository cache\n" );
181 - $this->name = $commonsCachedValues['name'];
182 - $this->imagePath = $commonsCachedValues['imagePath'];
183 - $this->fileExists = $commonsCachedValues['fileExists'];
184 - $this->width = $commonsCachedValues['width'];
185 - $this->height = $commonsCachedValues['height'];
186 - $this->bits = $commonsCachedValues['bits'];
187 - $this->type = $commonsCachedValues['type'];
188 - $this->mime = $commonsCachedValues['mime'];
189 - $this->metadata = $commonsCachedValues['metadata'];
190 - $this->size = $commonsCachedValues['size'];
191 - $this->fromSharedDirectory = true;
192 - $this->dataLoaded = true;
193 - $this->imagePath = $this->getFullPath(true);
194 - }
195 - }
196 - } else {
197 - wfDebug( "Pulling image metadata from local cache\n" );
198 - $this->name = $cachedValues['name'];
199 - $this->imagePath = $cachedValues['imagePath'];
200 - $this->fileExists = $cachedValues['fileExists'];
201 - $this->width = $cachedValues['width'];
202 - $this->height = $cachedValues['height'];
203 - $this->bits = $cachedValues['bits'];
204 - $this->type = $cachedValues['type'];
205 - $this->mime = $cachedValues['mime'];
206 - $this->metadata = $cachedValues['metadata'];
207 - $this->size = $cachedValues['size'];
208 - $this->fromSharedDirectory = false;
209 - $this->dataLoaded = true;
210 - $this->imagePath = $this->getFullPath();
211 - }
212 - }
213 - if ( $this->dataLoaded ) {
214 - wfIncrStats( 'image_cache_hit' );
215 - } else {
216 - wfIncrStats( 'image_cache_miss' );
217 - }
218 -
219 - wfProfileOut( __METHOD__ );
220 - return $this->dataLoaded;
221 - }
222 -
223 - /**
224 - * Save the image metadata to memcached
225 - */
226 - function saveToCache() {
227 - global $wgMemc, $wgUseSharedUploads;
228 - $this->load();
229 - $keys = $this->getCacheKeys();
230 - // We can't cache negative metadata for non-existent files,
231 - // because if the file later appears in commons, the local
232 - // keys won't be purged.
233 - if ( $this->fileExists || !$wgUseSharedUploads ) {
234 - $cachedValues = array(
235 - 'version' => MW_IMAGE_VERSION,
236 - 'name' => $this->name,
237 - 'imagePath' => $this->imagePath,
238 - 'fileExists' => $this->fileExists,
239 - 'fromShared' => $this->fromSharedDirectory,
240 - 'width' => $this->width,
241 - 'height' => $this->height,
242 - 'bits' => $this->bits,
243 - 'type' => $this->type,
244 - 'mime' => $this->mime,
245 - 'metadata' => $this->metadata,
246 - 'size' => $this->size );
247 -
248 - $wgMemc->set( $keys[0], $cachedValues, 60 * 60 * 24 * 7 ); // A week
249 - } else {
250 - // However we should clear them, so they aren't leftover
251 - // if we've deleted the file.
252 - $wgMemc->delete( $keys[0] );
253 - }
254 - }
255 -
256 - /**
257 - * Load metadata from the file itself
258 - */
259 - function loadFromFile() {
260 - global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang;
261 - wfProfileIn( __METHOD__ );
262 - $this->imagePath = $this->getFullPath();
263 - $this->fileExists = file_exists( $this->imagePath );
264 - $this->fromSharedDirectory = false;
265 - $gis = array();
266 -
267 - if (!$this->fileExists) wfDebug(__METHOD__.': '.$this->imagePath." not found locally!\n");
268 -
269 - # If the file is not found, and a shared upload directory is used, look for it there.
270 - if (!$this->fileExists && $wgUseSharedUploads && $wgSharedUploadDirectory) {
271 - # In case we're on a wgCapitalLinks=false wiki, we
272 - # capitalize the first letter of the filename before
273 - # looking it up in the shared repository.
274 - $sharedImage = Image::newFromName( $wgContLang->ucfirst($this->name) );
275 - $this->fileExists = $sharedImage && file_exists( $sharedImage->getFullPath(true) );
276 - if ( $this->fileExists ) {
277 - $this->name = $sharedImage->name;
278 - $this->imagePath = $this->getFullPath(true);
279 - $this->fromSharedDirectory = true;
280 - }
281 - }
282 -
283 -
284 - if ( $this->fileExists ) {
285 - $magic=& MimeMagic::singleton();
286 -
287 - $this->mime = $magic->guessMimeType($this->imagePath,true);
288 - $this->type = $magic->getMediaType($this->imagePath,$this->mime);
289 - $handler = MediaHandler::getHandler( $this->mime );
290 -
291 - # Get size in bytes
292 - $this->size = filesize( $this->imagePath );
293 -
294 - # Height, width and metadata
295 - if ( $handler ) {
296 - $gis = $handler->getImageSize( $this, $this->imagePath );
297 - $this->metadata = $handler->getMetadata( $this, $this->imagePath );
298 - } else {
299 - $gis = false;
300 - $this->metadata = '';
301 - }
302 -
303 - wfDebug(__METHOD__.': '.$this->imagePath." loaded, ".$this->size." bytes, ".$this->mime.".\n");
304 - }
305 - else {
306 - $this->mime = NULL;
307 - $this->type = MEDIATYPE_UNKNOWN;
308 - $this->metadata = '';
309 - wfDebug(__METHOD__.': '.$this->imagePath." NOT FOUND!\n");
310 - }
311 -
312 - if( $gis ) {
313 - $this->width = $gis[0];
314 - $this->height = $gis[1];
315 - } else {
316 - $this->width = 0;
317 - $this->height = 0;
318 - }
319 -
320 - #NOTE: $gis[2] contains a code for the image type. This is no longer used.
321 -
322 - #NOTE: we have to set this flag early to avoid load() to be called
323 - # be some of the functions below. This may lead to recursion or other bad things!
324 - # as ther's only one thread of execution, this should be safe anyway.
325 - $this->dataLoaded = true;
326 -
327 - if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits'];
328 - else $this->bits = 0;
329 -
330 - wfProfileOut( __METHOD__ );
331 - }
332 -
333 - /**
334 - * Load image metadata from the DB
335 - */
336 - function loadFromDB() {
337 - global $wgUseSharedUploads, $wgSharedUploadDBname, $wgSharedUploadDBprefix, $wgContLang;
338 - wfProfileIn( __METHOD__ );
339 -
340 - $dbr = wfGetDB( DB_SLAVE );
341 - // Our we we looking for images from a certain timeframe?
342 - // Selective restore can make this become borked
343 - // --use of oi_deleted avoids this
344 - $frame = $this->timeframe ? "img_timestamp < {$this->timeframe}" : '1 = 1';
345 - // Try the current image
346 - $result = $dbr->select( 'image',
347 - array( 'img_size', 'img_width', 'img_height', 'img_bits',
348 - 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ),
349 - array( 'img_name' => $this->name, $frame ),
350 - __METHOD__ );
351 - $row = $dbr->fetchObject($result);
352 - // Try older images if not found...
353 - if ( $this->timeframe && !$row ) {
354 - $result = $dbr->select( 'oldimage',
355 - array( 'oi_archive_name','oi_width as img_width','oi_height as img_height','oi_bits as img_bits',
356 - 'oi_size as img_size','oi_media_type as img_media_type', 'oi_metadata as img_metadata',
357 - 'oi_major_mime as img_major_mime','oi_minor_mime as img_minor_mime','oi_deleted'),
358 - array( 'oi_name' => $this->name, "oi_timestamp < {$this->timeframe}" ),
359 - __METHOD__,
360 - array('ORDER BY' => 'oi_timestamp DESC', 'LIMIT' => 1) );
361 - if ( $row = $dbr->fetchObject($result) ) {
362 - # Set our name to the correct file name
363 - if ( $row->oi_deleted & Image::DELETED_FILE ) {
364 - $row = null; // public only
365 - } else {
366 - $this->fileName = $row->oi_archive_name;
367 - $this->oldimage = true;
368 - }
369 - }
370 - }
371 - if ( $row ) {
372 - $this->fromSharedDirectory = false;
373 - $this->fileExists = true;
374 -
375 - $this->imagePath = $this->getFullPath();
376 - $this->loadFromRow( $row );
377 - // Check for rows from a previous schema, quietly upgrade them
378 - $this->maybeUpgradeRow();
379 - } elseif ( $wgUseSharedUploads && $wgSharedUploadDBname ) {
380 - # In case we're on a wgCapitalLinks=false wiki, we
381 - # capitalize the first letter of the filename before
382 - # looking it up in the shared repository.
383 - $name = $wgContLang->ucfirst($this->name);
384 - $dbc = Image::getCommonsDB();
385 - // Try the current image
386 - $result = $dbc->select( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}image",
387 - array('img_size', 'img_width', 'img_height', 'img_bits',
388 - 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ),
389 - array( 'img_name' => $name, $frame ),
390 - __METHOD__ );
391 - // Try older images if not found...
392 - if ( !$row && $this->timeframe ) {
393 - $result = $dbc->select( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}oldimage",
394 - array( 'oi_archive_name','oi_width as img_width','oi_height as img_height','oi_bits as img_bits',
395 - 'oi_size as img_size','oi_media_type as img_media_type', 'oi_metadata as img_metadata',
396 - 'oi_major_mime as img_major_mime','oi_minor_mime as img_minor_mime','oi_deleted'),
397 - array( 'oi_name' => $this->name, "oi_timestamp < {$this->timeframe}" ),
398 - __METHOD__,
399 - array('ORDER BY' => 'oi_timestamp DESC', 'LIMIT' => 1) );
400 - // If we found one...
401 - if ( $row = $dbr->fetchObject($result) ) {
402 - # Set our name to the correct file name
403 - if ( $row->oi_deleted & Image::DELETED_FILE ) {
404 - $row = null; // public only
405 - } else {
406 - $this->fileName = $row->oi_archive_name;
407 - $this->oldimage = true;
408 - }
409 - }
410 - }
411 - if ( $row ) {
412 - $this->fromSharedDirectory = true;
413 - $this->fileExists = true;
414 - $this->imagePath = $this->getFullPath(true);
415 - $this->name = $name;
416 - $this->loadFromRow( $row );
417 - // Check for rows from a previous schema, quietly upgrade them
418 - $this->maybeUpgradeRow();
419 - }
420 - }
421 -
422 - if ( !$row ) {
423 - $this->size = 0;
424 - $this->width = 0;
425 - $this->height = 0;
426 - $this->bits = 0;
427 - $this->type = 0;
428 - $this->fileExists = false;
429 - $this->fromSharedDirectory = false;
430 - $this->metadata = '';
431 - $this->mime = false;
432 - }
433 -
434 - # Unconditionally set loaded=true, we don't want the accessors constantly rechecking
435 - $this->dataLoaded = true;
436 - wfProfileOut( __METHOD__ );
437 - }
438 -
439 - /*
440 - * Load image metadata from a DB result row
441 - */
442 - function loadFromRow( &$row ) {
443 - $this->size = isset($row->img_size) ? $row->img_size : null;
444 - $this->width = isset($row->img_width) ? $row->img_width : null;
445 - $this->height = isset($row->img_height) ? $row->img_height : null;
446 - $this->bits = isset($row->img_bits) ? $row->img_bits : null;
447 - $this->type = isset($row->img_media_type) ? $row->img_media_type : null;
448 -
449 - $major = isset($row->img_major_mime) ? $row->img_major_mime : null;
450 - $minor = isset($row->img_minor_mime) ? $row->img_minor_mime : null;
451 -
452 - if (!$major) $this->mime = "unknown/unknown";
453 - else {
454 - if (!$minor) $minor= "unknown";
455 - $this->mime = $major.'/'.$minor;
456 - }
457 - $this->metadata = isset($row->img_metadata) ? $row->img_metadata : null;
458 -
459 - $this->dataLoaded = true;
460 - }
461 -
462 - /**
463 - * Load image metadata from cache or DB, unless already loaded
464 - */
465 - function load() {
466 - global $wgSharedUploadDBname, $wgUseSharedUploads;
467 - if ( !$this->dataLoaded ) {
468 - if ( !$this->loadFromCache() ) {
469 - $this->loadFromDB();
470 - if ( !$wgSharedUploadDBname && $wgUseSharedUploads ) {
471 - $this->loadFromFile();
472 - } elseif ( $this->fileExists || !$wgUseSharedUploads ) {
473 - // We can do negative caching for local images, because the cache
474 - // will be purged on upload. But we can't do it when shared images
475 - // are enabled, since updates to that won't purge foreign caches.
476 - $this->saveToCache();
477 - }
478 - }
479 - $this->dataLoaded = true;
480 - }
481 - }
482 -
483 - /**
484 - * Upgrade a row if it needs it
485 - * @return void
486 - */
487 - function maybeUpgradeRow() {
488 - if ( is_null($this->type) || $this->mime == 'image/svg' ) {
489 - $this->upgradeRow();
490 - } else {
491 - $handler = $this->getHandler();
492 - if ( $handler && !$handler->isMetadataValid( $this, $this->metadata ) ) {
493 - $this->upgradeRow();
494 - }
495 - }
496 - }
497 -
498 - /**
499 - * Fix assorted version-related problems with the image row by reloading it from the file
500 - */
501 - function upgradeRow() {
502 - global $wgDBname, $wgSharedUploadDBname;
503 - wfProfileIn( __METHOD__ );
504 -
505 - $this->loadFromFile();
506 -
507 - if ( $this->fromSharedDirectory ) {
508 - if ( !$wgSharedUploadDBname ) {
509 - wfProfileOut( __METHOD__ );
510 - return;
511 - }
512 -
513 - // Write to the other DB using selectDB, not database selectors
514 - // This avoids breaking replication in MySQL
515 - $dbw = Image::getCommonsDB();
516 - } else {
517 - $dbw = wfGetDB( DB_MASTER );
518 - }
519 -
520 - list( $major, $minor ) = self::splitMime( $this->mime );
521 -
522 - wfDebug(__METHOD__.': upgrading '.$this->name." to the current schema\n");
523 - // Is this an old or current image?
524 - if ( !$this->oldimage ) {
525 - $dbw->update( 'image',
526 - array(
527 - 'img_width' => $this->width,
528 - 'img_height' => $this->height,
529 - 'img_bits' => $this->bits,
530 - 'img_media_type' => $this->type,
531 - 'img_major_mime' => $major,
532 - 'img_minor_mime' => $minor,
533 - 'img_metadata' => $this->metadata,
534 - ), array( 'img_name' => $this->name ), __METHOD__
535 - );
536 - } else {
537 - $dbw->update( 'oldimage',
538 - array(
539 - 'oi_width' => $this->width,
540 - 'oi_height' => $this->height,
541 - 'oi_bits' => $this->bits,
542 - 'oi_media_type' => $this->type,
543 - 'oi_major_mime' => $major,
544 - 'oi_minor_mime' => $minor,
545 - 'oi_metadata' => $this->metadata,
546 - ), array( 'oi_archive_name' => $this->fileName ), __METHOD__
547 - );
548 - }
549 - if ( $this->fromSharedDirectory ) {
550 - $dbw->selectDB( $wgDBname );
551 - }
552 - wfProfileOut( __METHOD__ );
553 - }
554 -
555 - /**
556 - * Split an internet media type into its two components; if not
557 - * a two-part name, set the minor type to 'unknown'.
558 - *
559 - * @param string $mime "text/html" etc
560 - * @return array ("text", "html") etc
561 - */
562 - static function splitMime( $mime ) {
563 - if( strpos( $mime, '/' ) !== false ) {
564 - return explode( '/', $mime, 2 );
565 - } else {
566 - return array( $mime, 'unknown' );
567 - }
568 - }
569 -
570 - /**
571 - * Return the name of this image
572 - * @public
573 - */
574 - function getName() {
575 - return $this->name;
576 - }
577 -
578 - /**
579 - * Return the associated title object
580 - * @public
581 - */
582 - function getTitle() {
583 - return $this->title;
584 - }
585 -
586 - /**
587 - * Return the URL of the image file
588 - * @public
589 - */
590 - function getURL() {
591 - if ( !$this->url ) {
592 - $this->load();
593 - if($this->fileExists) {
594 - $this->url = Image::imageUrl( $this->name, $this->fromSharedDirectory );
595 - } else {
596 - $this->url = '';
597 - }
598 - }
599 - return $this->url;
600 - }
601 -
602 - function getViewURL() {
603 - if( $this->mustRender()) {
604 - if( $this->canRender() ) {
605 - return $this->createThumb( $this->getWidth() );
606 - }
607 - else {
608 - wfDebug('Image::getViewURL(): supposed to render '.$this->name.' ('.$this->mime."), but can't!\n");
609 - return $this->getURL(); #hm... return NULL?
610 - }
611 - } else {
612 - return $this->getURL();
613 - }
614 - }
615 -
616 - /**
617 - * Return the image path of the image in the
618 - * local file system as an absolute path
619 - * @public
620 - */
621 - function getImagePath() {
622 - $this->load();
623 - return $this->imagePath;
624 - }
625 -
626 - /**
627 - * @return mixed Return the width of the image; returns false on error.
628 - * @param int $page Page number to find the width of.
629 - * @public
630 - */
631 - function getWidth( $page = 1 ) {
632 - $this->load();
633 - if ( $this->isMultipage() ) {
634 - $dim = $this->getHandler()->getPageDimensions( $this, $page );
635 - if ( $dim ) {
636 - return $dim['width'];
637 - } else {
638 - return false;
639 - }
640 - } else {
641 - return $this->width;
642 - }
643 - }
644 -
645 - /**
646 - * @return mixed Return the height of the image; Returns false on error.
647 - * @param int $page Page number to find the height of.
648 - * @public
649 - */
650 - function getHeight( $page = 1 ) {
651 - $this->load();
652 - if ( $this->isMultipage() ) {
653 - $dim = $this->getHandler()->getPageDimensions( $this, $page );
654 - if ( $dim ) {
655 - return $dim['height'];
656 - } else {
657 - return false;
658 - }
659 - } else {
660 - return $this->height;
661 - }
662 - }
663 -
664 - /**
665 - * Get handler-specific metadata
666 - */
667 - function getMetadata() {
668 - $this->load();
669 - return $this->metadata;
670 - }
671 -
672 - /**
673 - * @return int the size of the image file, in bytes
674 - * @public
675 - */
676 - function getSize() {
677 - $this->load();
678 - return $this->size;
679 - }
680 -
681 - /**
682 - * @return string the mime type of the file.
683 - */
684 - function getMimeType() {
685 - $this->load();
686 - return $this->mime;
687 - }
688 -
689 - /**
690 - * Return the type of the media in the file.
691 - * Use the value returned by this function with the MEDIATYPE_xxx constants.
692 - */
693 - function getMediaType() {
694 - $this->load();
695 - return $this->type;
696 - }
697 -
698 - /**
699 - * Checks if the file can be presented to the browser as a bitmap.
700 - *
701 - * Currently, this checks if the file is an image format
702 - * that can be converted to a format
703 - * supported by all browsers (namely GIF, PNG and JPEG),
704 - * or if it is an SVG image and SVG conversion is enabled.
705 - *
706 - * @todo remember the result of this check.
707 - * @return boolean
708 - */
709 - function canRender() {
710 - $handler = $this->getHandler();
711 - return $handler && $handler->canRender();
712 - }
713 -
714 - /**
715 - * Return true if the file is of a type that can't be directly
716 - * rendered by typical browsers and needs to be re-rasterized.
717 - *
718 - * This returns true for everything but the bitmap types
719 - * supported by all browsers, i.e. JPEG; GIF and PNG. It will
720 - * also return true for any non-image formats.
721 - *
722 - * @return bool
723 - */
724 - function mustRender() {
725 - $handler = $this->getHandler();
726 - return $handler && $handler->mustRender();
727 - }
728 -
729 - /**
730 - * Determines if this media file may be shown inline on a page.
731 - *
732 - * This is currently synonymous to canRender(), but this could be
733 - * extended to also allow inline display of other media,
734 - * like flash animations or videos. If you do so, please keep in mind that
735 - * that could be a security risk.
736 - */
737 - function allowInlineDisplay() {
738 - return $this->canRender();
739 - }
740 -
741 - /**
742 - * Determines if this media file is in a format that is unlikely to
743 - * contain viruses or malicious content. It uses the global
744 - * $wgTrustedMediaFormats list to determine if the file is safe.
745 - *
746 - * This is used to show a warning on the description page of non-safe files.
747 - * It may also be used to disallow direct [[media:...]] links to such files.
748 - *
749 - * Note that this function will always return true if allowInlineDisplay()
750 - * or isTrustedFile() is true for this file.
751 - *
752 - * @return boolean
753 - */
754 - function isSafeFile() {
755 - if ($this->allowInlineDisplay()) return true;
756 - if ($this->isTrustedFile()) return true;
757 -
758 - global $wgTrustedMediaFormats;
759 -
760 - $type= $this->getMediaType();
761 - $mime= $this->getMimeType();
762 - #wfDebug("Image::isSafeFile: type= $type, mime= $mime\n");
763 -
764 - if (!$type || $type===MEDIATYPE_UNKNOWN) return false; #unknown type, not trusted
765 - if ( in_array( $type, $wgTrustedMediaFormats) ) return true;
766 -
767 - if ($mime==="unknown/unknown") return false; #unknown type, not trusted
768 - if ( in_array( $mime, $wgTrustedMediaFormats) ) return true;
769 -
770 - return false;
771 - }
772 -
773 - /**
774 - * Returns true if the file is flagged as trusted. Files flagged that way
775 - * can be linked to directly, even if that is not allowed for this type of
776 - * file normally.
777 - *
778 - * This is a dummy function right now and always returns false. It could be
779 - * implemented to extract a flag from the database. The trusted flag could be
780 - * set on upload, if the user has sufficient privileges, to bypass script-
781 - * and html-filters. It may even be coupled with cryptographics signatures
782 - * or such.
783 - * @return boolean
784 - */
785 - function isTrustedFile() {
786 - #this could be implemented to check a flag in the database,
787 - #look for signatures, etc
788 - return false;
789 - }
790 -
791 - /**
792 - * Return the escapeLocalURL of this image
793 - * @param string $query URL query string
794 - * @public
795 - */
796 - function getEscapeLocalURL( $query=false) {
797 - return $this->getTitle()->escapeLocalURL( $query );
798 - }
799 -
800 - /**
801 - * Return the escapeFullURL of this image
802 - * @public
803 - */
804 - function getEscapeFullURL() {
805 - $this->getTitle();
806 - return $this->title->escapeFullURL();
807 - }
808 -
809 - /**
810 - * Return the URL of an image, provided its name.
811 - *
812 - * @param string $name Name of the image, without the leading "Image:"
813 - * @param boolean $fromSharedDirectory Should this be in $wgSharedUploadPath?
814 - * @return string URL of $name image
815 - * @public
816 - */
817 - static function imageUrl( $name, $fromSharedDirectory = false ) {
818 - global $wgUploadPath,$wgUploadBaseUrl,$wgSharedUploadPath;
819 - if($fromSharedDirectory) {
820 - $base = '';
821 - $path = $wgSharedUploadPath;
822 - } else {
823 - $base = $wgUploadBaseUrl;
824 - $path = $wgUploadPath;
825 - }
826 - $url = "{$base}{$path}" . wfGetHashPath($name, $fromSharedDirectory) . "{$name}";
827 - return wfUrlencode( $url );
828 - }
829 -
830 - /**
831 - * Returns true if the image file exists on disk.
832 - * @return boolean Whether image file exist on disk.
833 - * @public
834 - */
835 - function exists() {
836 - $this->load();
837 - return $this->fileExists;
838 - }
839 -
840 - /**
841 - * @todo document
842 - * @param string $thumbName
843 - * @param string $subdir
844 - * @return string
845 - * @private
846 - */
847 - function thumbUrlFromName( $thumbName, $subdir = 'thumb' ) {
848 - global $wgUploadPath, $wgUploadBaseUrl, $wgSharedUploadPath;
849 - if($this->fromSharedDirectory) {
850 - $base = '';
851 - $path = $wgSharedUploadPath;
852 - } else {
853 - $base = $wgUploadBaseUrl;
854 - $path = $wgUploadPath;
855 - }
856 - if ( Image::isHashed( $this->fromSharedDirectory ) ) {
857 - $hashdir = wfGetHashPath($this->name, $this->fromSharedDirectory) .
858 - wfUrlencode( $this->name );
859 - } else {
860 - $hashdir = '';
861 - }
862 - $url = "{$base}{$path}/{$subdir}{$hashdir}/" . wfUrlencode( $thumbName );
863 - return $url;
864 - }
865 -
866 - /**
867 - * @deprecated Use $image->transform()->getUrl() or thumbUrlFromName()
868 - */
869 - function thumbUrl( $width, $subdir = 'thumb' ) {
870 - $name = $this->thumbName( array( 'width' => $width ) );
871 - if ( strval( $name ) !== '' ) {
872 - return array( false, $this->thumbUrlFromName( $name, $subdir ) );
873 - } else {
874 - return array( false, false );
875 - }
876 - }
877 -
878 - /**
879 - * @return mixed
880 - */
881 - function getTransformScript() {
882 - global $wgSharedThumbnailScriptPath, $wgThumbnailScriptPath;
883 - if ( $this->fromSharedDirectory ) {
884 - $script = $wgSharedThumbnailScriptPath;
885 - } else {
886 - $script = $wgThumbnailScriptPath;
887 - }
888 - if ( $script ) {
889 - return "$script?f=" . urlencode( $this->name );
890 - } else {
891 - return false;
892 - }
893 - }
894 -
895 - /**
896 - * Get a ThumbnailImage which is the same size as the source
897 - * @param mixed $page
898 - * @return MediaTransformOutput
899 - */
900 - function getUnscaledThumb( $page = false ) {
901 - if ( $page ) {
902 - $params = array(
903 - 'page' => $page,
904 - 'width' => $this->getWidth( $page )
905 - );
906 - } else {
907 - $params = array( 'width' => $this->getWidth() );
908 - }
909 - return $this->transform( $params );
910 - }
911 -
912 - /**
913 - * Return the file name of a thumbnail with the specified parameters
914 - *
915 - * @param array $params Handler-specific parameters
916 - * @return string file name of a thumbnail with the specified parameters
917 - * @private
918 - */
919 - function thumbName( $params ) {
920 - $handler = $this->getHandler();
921 - if ( !$handler ) {
922 - return null;
923 - }
924 - list( $thumbExt, /* $thumbMime */ ) = self::getThumbType( $this->extension, $this->mime );
925 - $thumbName = $handler->makeParamString( $params ) . '-' . $this->fileName;
926 - if ( $thumbExt != $this->extension ) {
927 - $thumbName .= ".$thumbExt";
928 - }
929 - return $thumbName;
930 - }
931 -
932 - /**
933 - * Create a thumbnail of the image having the specified width/height.
934 - * The thumbnail will not be created if the width is larger than the
935 - * image's width. Let the browser do the scaling in this case.
936 - * The thumbnail is stored on disk and is only computed if the thumbnail
937 - * file does not exist OR if it is older than the image.
938 - * Returns the URL.
939 - *
940 - * Keeps aspect ratio of original image. If both width and height are
941 - * specified, the generated image will be no bigger than width x height,
942 - * and will also have correct aspect ratio.
943 - *
944 - * @param integer $width maximum width of the generated thumbnail
945 - * @param integer $height maximum height of the image (optional)
946 - * @public
947 - */
948 - function createThumb( $width, $height = -1 ) {
949 - $params = array( 'width' => $width );
950 - if ( $height != -1 ) {
951 - $params['height'] = $height;
952 - }
953 - $thumb = $this->transform( $params );
954 - if( is_null( $thumb ) || $thumb->isError() ) return '';
955 - return $thumb->getUrl();
956 - }
957 -
958 - /**
959 - * As createThumb, but returns a ThumbnailImage object. This can
960 - * provide access to the actual file, the real size of the thumb,
961 - * and can produce a convenient <img> tag for you.
962 - *
963 - * For non-image formats, this may return a filetype-specific icon.
964 - *
965 - * @param integer $width maximum width of the generated thumbnail
966 - * @param integer $height maximum height of the image (optional)
967 - * @param boolean $render True to render the thumbnail if it doesn't exist,
968 - * false to just return the URL
969 - *
970 - * @return ThumbnailImage or null on failure
971 - * @public
972 - *
973 - * @deprecated use transform()
974 - */
975 - function getThumbnail( $width, $height=-1, $render = true ) {
976 - $params = array( 'width' => $width );
977 - if ( $height != -1 ) {
978 - $params['height'] = $height;
979 - }
980 - $flags = $render ? self::RENDER_NOW : 0;
981 - return $this->transform( $params, $flags );
982 - }
983 -
984 - /**
985 - * Transform a media file
986 - *
987 - * @param array[string]mixed $params An associative array of handler-specific parameters.
988 - * Typical keys are width, height and page.
989 - * @param integer $flags A bitfield, may contain self::RENDER_NOW to force rendering
990 - * @return MediaTransformOutput
991 - */
992 - function transform( $params, $flags = 0 ) {
993 - global $wgGenerateThumbnailOnParse, $wgUseSquid, $wgIgnoreImageErrors;
994 -
995 - wfProfileIn( __METHOD__ );
996 - do {
997 - $handler = $this->getHandler();
998 - if ( !$handler || !$handler->canRender() ) {
999 - // not a bitmap or renderable image, don't try.
1000 - $thumb = $this->iconThumb();
1001 - break;
1002 - }
1003 -
1004 - $script = $this->getTransformScript();
1005 - if ( $script && !($flags & self::RENDER_NOW) ) {
1006 - // Use a script to transform on client request
1007 - $thumb = $handler->getScriptedTransform( $this, $script, $params );
1008 - break;
1009 - }
1010 -
1011 - $normalisedParams = $params;
1012 - $handler->normaliseParams( $this, $normalisedParams );
1013 - $thumbName = $this->thumbName( $normalisedParams );
1014 - $thumbPath = wfImageThumbDir( $this->name, $this->fromSharedDirectory ) . "/$thumbName";
1015 - $thumbUrl = $this->thumbUrlFromName( $thumbName );
1016 -
1017 -
1018 - if ( !$wgGenerateThumbnailOnParse && !($flags & self::RENDER_NOW ) ) {
1019 - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params );
1020 - break;
1021 - }
1022 -
1023 - wfDebug( "Doing stat for $thumbPath\n" );
1024 - $this->migrateThumbFile( $thumbName );
1025 - if ( file_exists( $thumbPath ) ) {
1026 - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params );
1027 - break;
1028 - }
1029 -
1030 - $thumb = $handler->doTransform( $this, $thumbPath, $thumbUrl, $params );
1031 -
1032 - // Ignore errors if requested
1033 - if ( !$thumb ) {
1034 - $thumb = null;
1035 - } elseif ( $thumb->isError() ) {
1036 - $this->lastError = $thumb->toText();
1037 - if ( $wgIgnoreImageErrors && !($flags & self::RENDER_NOW) ) {
1038 - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params );
1039 - }
1040 - }
1041 -
1042 - if ( $wgUseSquid ) {
1043 - wfPurgeSquidServers( array( $thumbUrl ) );
1044 - }
1045 - } while (false);
1046 -
1047 - wfProfileOut( __METHOD__ );
1048 - return $thumb;
1049 - }
1050 -
1051 - /**
1052 - * Fix thumbnail files from 1.4 or before, with extreme prejudice
1053 - * @param string $thumbName File name of thumbnail.
1054 - * @return void
1055 - */
1056 - function migrateThumbFile( $thumbName ) {
1057 - $thumbDir = wfImageThumbDir( $this->name, $this->fromSharedDirectory );
1058 - $thumbPath = "$thumbDir/$thumbName";
1059 - if ( is_dir( $thumbPath ) ) {
1060 - // Directory where file should be
1061 - // This happened occasionally due to broken migration code in 1.5
1062 - // Rename to broken-*
1063 - global $wgUploadDirectory;
1064 - for ( $i = 0; $i < 100 ; $i++ ) {
1065 - $broken = "$wgUploadDirectory/broken-$i-$thumbName";
1066 - if ( !file_exists( $broken ) ) {
1067 - rename( $thumbPath, $broken );
1068 - break;
1069 - }
1070 - }
1071 - // Doesn't exist anymore
1072 - clearstatcache();
1073 - }
1074 - if ( is_file( $thumbDir ) ) {
1075 - // File where directory should be
1076 - unlink( $thumbDir );
1077 - // Doesn't exist anymore
1078 - clearstatcache();
1079 - }
1080 - }
1081 -
1082 - /**
1083 - * Get a MediaHandler instance for this image
1084 - */
1085 - function getHandler() {
1086 - return MediaHandler::getHandler( $this->getMimeType() );
1087 - }
1088 -
1089 - /**
1090 - * Get a ThumbnailImage representing a file type icon
1091 - * @return ThumbnailImage
1092 - */
1093 - function iconThumb() {
1094 - global $wgStylePath, $wgStyleDirectory;
1095 -
1096 - $icons = array( 'fileicon-' . $this->extension . '.png', 'fileicon.png' );
1097 - foreach( $icons as $icon ) {
1098 - $path = '/common/images/icons/' . $icon;
1099 - $filepath = $wgStyleDirectory . $path;
1100 - if( file_exists( $filepath ) ) {
1101 - return new ThumbnailImage( $wgStylePath . $path, 120, 120 );
1102 - }
1103 - }
1104 - return null;
1105 - }
1106 -
1107 - /**
1108 - * Get last thumbnailing error.
1109 - * Largely obsolete.
1110 - * @return mixed
1111 - */
1112 - function getLastError() {
1113 - return $this->lastError;
1114 - }
1115 -
1116 - /**
1117 - * Get all thumbnail names previously generated for this image
1118 - * @param boolean $shared
1119 - * @return array[]string
1120 - */
1121 - function getThumbnails( $shared = false ) {
1122 - if ( Image::isHashed( $shared ) ) {
1123 - $this->load();
1124 - $files = array();
1125 - $dir = wfImageThumbDir( $this->name, $shared );
1126 -
1127 - if ( is_dir( $dir ) ) {
1128 - $handle = opendir( $dir );
1129 -
1130 - if ( $handle ) {
1131 - while ( false !== ( $file = readdir($handle) ) ) {
1132 - if ( $file[0] != '.' ) {
1133 - $files[] = $file;
1134 - }
1135 - }
1136 - closedir( $handle );
1137 - }
1138 - }
1139 - } else {
1140 - $files = array();
1141 - }
1142 -
1143 - return $files;
1144 - }
1145 -
1146 - /**
1147 - * Refresh metadata in memcached, but don't touch thumbnails or squid
1148 - * @return void
1149 - */
1150 - function purgeMetadataCache() {
1151 - clearstatcache();
1152 - $this->loadFromFile();
1153 - $this->saveToCache();
1154 - }
1155 -
1156 - /**
1157 - * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid
1158 - * @param array $archiveFiles
1159 - * @param boolean $shared
1160 - * @return void
1161 - */
1162 - function purgeCache( $archiveFiles = array(), $shared = false ) {
1163 - global $wgUseSquid;
1164 -
1165 - // Refresh metadata cache
1166 - $this->purgeMetadataCache();
1167 -
1168 - // Delete thumbnails
1169 - $files = $this->getThumbnails( $shared );
1170 - $dir = wfImageThumbDir( $this->name, $shared );
1171 - $urls = array();
1172 - foreach ( $files as $file ) {
1173 - # Check that the base image name is part of the thumb name
1174 - # This is a basic sanity check to avoid erasing unrelated directories
1175 - if ( strpos( $file, $this->name ) !== false ) {
1176 - $url = $this->thumbUrlFromName( $file );
1177 - $urls[] = $url;
1178 - @unlink( "$dir/$file" );
1179 - }
1180 - }
1181 -
1182 - // Purge the squid
1183 - if ( $wgUseSquid ) {
1184 - $urls[] = $this->getURL();
1185 - foreach ( $archiveFiles as $file ) {
1186 - $urls[] = wfImageArchiveUrl( $file );
1187 - }
1188 - wfPurgeSquidServers( $urls );
1189 - }
1190 - }
1191 -
1192 - /**
1193 - * Purge the image description page, but don't go after
1194 - * pages using the image. Use when modifying file history
1195 - * but not the current data.
1196 - * @return void
1197 - */
1198 - function purgeDescription() {
1199 - $page = Title::makeTitle( NS_IMAGE, $this->name );
1200 - $page->invalidateCache();
1201 - $page->purgeSquid();
1202 - }
1203 -
1204 - /**
1205 - * Purge metadata and all affected pages when the image is created,
1206 - * deleted, or majorly updated.
1207 - * @param array $urlArray A set of additional URLs may be passed to purge,
1208 - * such as specific image files which have changed (param not used?)
1209 - * @return void
1210 - */
1211 - function purgeEverything( $urlArr=array() ) {
1212 - // Delete thumbnails and refresh image metadata cache
1213 - $this->purgeCache();
1214 - $this->purgeDescription();
1215 -
1216 - // Purge cache of all pages using this image
1217 - $update = new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' );
1218 - $update->doUpdate();
1219 - }
1220 -
1221 - /**
1222 - * Return the image history of this image, line by line.
1223 - * starts with current version, then old versions.
1224 - * uses $this->historyLine to check which line to return:
1225 - * 0 return line for current version
1226 - * 1 query for old versions, return first one
1227 - * 2, ... return next old version from above query
1228 - *
1229 - * @public
1230 - * @return mixed false on no next history, object otherwise.
1231 - */
1232 - function nextHistoryLine() {
1233 - $dbr = wfGetDB( DB_SLAVE );
1234 -
1235 - if ( $this->historyLine == 0 ) {// called for the first time, return line from cur
1236 - $this->historyRes = $dbr->select( 'image',
1237 - array(
1238 - 'img_size',
1239 - 'img_description',
1240 - 'img_user','img_user_text',
1241 - 'img_timestamp',
1242 - 'img_width',
1243 - 'img_height',
1244 - '0 AS oi_deleted',
1245 - "'' AS oi_archive_name"
1246 - ),
1247 - array( 'img_name' => $this->title->getDBkey() ),
1248 - __METHOD__
1249 - );
1250 - if ( 0 == $dbr->numRows( $this->historyRes ) ) {
1251 - return FALSE;
1252 - }
1253 - } else if ( $this->historyLine == 1 ) {
1254 - $this->historyRes = $dbr->select( 'oldimage',
1255 - array(
1256 - 'oi_size AS img_size',
1257 - 'oi_description AS img_description',
1258 - 'oi_user AS img_user',
1259 - 'oi_user_text AS img_user_text',
1260 - 'oi_timestamp AS img_timestamp',
1261 - 'oi_width as img_width',
1262 - 'oi_height as img_height',
1263 - 'oi_archive_name',
1264 - 'oi_deleted'
1265 - ),
1266 - array( 'oi_name' => $this->title->getDBkey() ),
1267 - __METHOD__,
1268 - array( 'ORDER BY' => 'oi_timestamp DESC' )
1269 - );
1270 - }
1271 - $this->historyLine ++;
1272 -
1273 - return $dbr->fetchObject( $this->historyRes );
1274 - }
1275 -
1276 - /**
1277 - * Reset the history pointer to the first element of the history
1278 - * @public
1279 - * @return void
1280 - */
1281 - function resetHistory() {
1282 - $this->historyLine = 0;
1283 - }
1284 -
1285 - /**
1286 - * Return the full filesystem path to the file. Note that this does
1287 - * not mean that a file actually exists under that location.
1288 - *
1289 - * This path depends on whether directory hashing is active or not,
1290 - * i.e. whether the images are all found in the same directory,
1291 - * or in hashed paths like /images/3/3c.
1292 - *
1293 - * @public
1294 - * @param boolean $fromSharedDirectory Return the path to the file
1295 - * in a shared repository (see $wgUseSharedRepository and related
1296 - * options in DefaultSettings.php) instead of a local one.
1297 - * @return string Full filesystem path to the file.
1298 - */
1299 - function getFullPath( $fromSharedRepository = false ) {
1300 - global $wgUploadDirectory, $wgSharedUploadDirectory;
1301 -
1302 - $dir = $fromSharedRepository ? $wgSharedUploadDirectory :
1303 - $wgUploadDirectory;
1304 - // Is this an old version?
1305 - $subdir = $this->oldimage ? '/archive' : '';
1306 - // $wgSharedUploadDirectory may be false, if thumb.php is used
1307 - if ( $dir ) {
1308 - $fullpath = $dir . $subdir . wfGetHashPath($this->name, $fromSharedRepository) . $this->fileName;
1309 - } else {
1310 - $fullpath = false;
1311 - }
1312 - return $fullpath;
1313 - }
1314 -
1315 - /**
1316 - * @param boolean $shared
1317 - * @return bool
1318 - */
1319 - public static function isHashed( $shared ) {
1320 - global $wgHashedUploadDirectory, $wgHashedSharedUploadDirectory;
1321 - return $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory;
1322 - }
1323 -
1324 - /**
1325 - * Record an image upload in the upload log and the image table
1326 - * @param string $oldver
1327 - * @param string $desc
1328 - * @param string $license
1329 - * @param string $copyStatus
1330 - * @param string $source
1331 - * @param boolean $watch
1332 - * @return boolean
1333 - */
1334 - function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) {
1335 - global $wgUser, $wgUseCopyrightUpload;
1336 -
1337 - $dbw = wfGetDB( DB_MASTER );
1338 -
1339 - // Delete thumbnails and refresh the metadata cache
1340 - $this->purgeCache();
1341 -
1342 - // Fail now if the image isn't there
1343 - if ( !$this->fileExists || $this->fromSharedDirectory ) {
1344 - wfDebug( "Image::recordUpload: File ".$this->imagePath." went missing!\n" );
1345 - return false;
1346 - }
1347 -
1348 - if ( $wgUseCopyrightUpload ) {
1349 - if ( $license != '' ) {
1350 - $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
1351 - }
1352 - $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" .
1353 - '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
1354 - "$licensetxt" .
1355 - '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
1356 - } else {
1357 - if ( $license != '' ) {
1358 - $filedesc = $desc == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n";
1359 - $textdesc = $filedesc .
1360 - '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n";
1361 - } else {
1362 - $textdesc = $desc;
1363 - }
1364 - }
1365 -
1366 - $now = $dbw->timestamp();
1367 -
1368 - #split mime type
1369 - if (strpos($this->mime,'/')!==false) {
1370 - list($major,$minor)= explode('/',$this->mime,2);
1371 - }
1372 - else {
1373 - $major= $this->mime;
1374 - $minor= "unknown";
1375 - }
1376 -
1377 - # Test to see if the row exists using INSERT IGNORE
1378 - # This avoids race conditions by locking the row until the commit, and also
1379 - # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
1380 - $dbw->insert( 'image',
1381 - array(
1382 - 'img_name' => $this->name,
1383 - 'img_size'=> $this->size,
1384 - 'img_width' => intval( $this->width ),
1385 - 'img_height' => intval( $this->height ),
1386 - 'img_bits' => $this->bits,
1387 - 'img_media_type' => $this->type,
1388 - 'img_major_mime' => $major,
1389 - 'img_minor_mime' => $minor,
1390 - 'img_timestamp' => $now,
1391 - 'img_description' => $desc,
1392 - 'img_user' => $wgUser->getID(),
1393 - 'img_user_text' => $wgUser->getName(),
1394 - 'img_metadata' => $this->metadata
1395 - ),
1396 - __METHOD__,
1397 - 'IGNORE'
1398 - );
1399 -
1400 - if( $dbw->affectedRows() == 0 ) {
1401 - # Collision, this is an update of an image
1402 - # Insert previous contents into oldimage
1403 - $dbw->insertSelect( 'oldimage', 'image',
1404 - array(
1405 - 'oi_name' => 'img_name',
1406 - 'oi_archive_name' => $dbw->addQuotes( $oldver ),
1407 - 'oi_size' => 'img_size',
1408 - 'oi_width' => 'img_width',
1409 - 'oi_height' => 'img_height',
1410 - 'oi_bits' => 'img_bits',
1411 - 'oi_timestamp' => 'img_timestamp',
1412 - 'oi_description' => 'img_description',
1413 - 'oi_user' => 'img_user',
1414 - 'oi_user_text' => 'img_user_text',
1415 - 'oi_media_type' => 'img_media_type',
1416 - 'oi_major_mime' => 'img_major_mime',
1417 - 'oi_minor_mime' => 'img_minor_mime',
1418 - 'oi_metadata' => 'img_metadata',
1419 - ), array( 'img_name' => $this->name ), __METHOD__
1420 - );
1421 -
1422 - # Update the current image row
1423 - $dbw->update( 'image',
1424 - array( /* SET */
1425 - 'img_size' => $this->size,
1426 - 'img_width' => intval( $this->width ),
1427 - 'img_height' => intval( $this->height ),
1428 - 'img_bits' => $this->bits,
1429 - 'img_media_type' => $this->type,
1430 - 'img_major_mime' => $major,
1431 - 'img_minor_mime' => $minor,
1432 - 'img_timestamp' => $now,
1433 - 'img_description' => $desc,
1434 - 'img_user' => $wgUser->getID(),
1435 - 'img_user_text' => $wgUser->getName(),
1436 - 'img_metadata' => $this->metadata,
1437 - ), array( /* WHERE */
1438 - 'img_name' => $this->name
1439 - ), __METHOD__
1440 - );
1441 - } else {
1442 - # This is a new image
1443 - # Update the image count
1444 - $site_stats = $dbw->tableName( 'site_stats' );
1445 - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ );
1446 - }
1447 -
1448 - $descTitle = $this->getTitle();
1449 - $article = new Article( $descTitle );
1450 - $minor = false;
1451 - $watch = $watch || $wgUser->isWatched( $descTitle );
1452 - $suppressRC = true; // There's already a log entry, so don't double the RC load
1453 -
1454 - if( $descTitle->exists() ) {
1455 - // TODO: insert a null revision into the page history for this update.
1456 - if( $watch ) {
1457 - $wgUser->addWatch( $descTitle );
1458 - }
1459 -
1460 - # Invalidate the cache for the description page
1461 - $descTitle->invalidateCache();
1462 - $descTitle->purgeSquid();
1463 - } else {
1464 - // New image; create the description page.
1465 - $article->insertNewArticle( $textdesc, $desc, $minor, $watch, $suppressRC );
1466 - }
1467 -
1468 - # Hooks, hooks, the magic of hooks...
1469 - wfRunHooks( 'FileUpload', array( $this ) );
1470 -
1471 - # Add the log entry
1472 - $log = new LogPage( 'upload' );
1473 - $log->addEntry( 'upload', $descTitle, $desc );
1474 -
1475 - # Commit the transaction now, in case something goes wrong later
1476 - # The most important thing is that images don't get lost, especially archives
1477 - $dbw->immediateCommit();
1478 -
1479 - # Invalidate cache for all pages using this image
1480 - $update = new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' );
1481 - $update->doUpdate();
1482 -
1483 - return true;
1484 - }
1485 -
1486 - /**
1487 - * Get an array of Title objects which are articles which use this image
1488 - * Also adds their IDs to the link cache
1489 - *
1490 - * This is mostly copied from Title::getLinksTo()
1491 - *
1492 - * @deprecated Use HTMLCacheUpdate, this function uses too much memory
1493 - * @param string $options
1494 - * @return array[int]Title
1495 - */
1496 - function getLinksTo( $options = '' ) {
1497 - wfProfileIn( __METHOD__ );
1498 -
1499 - if ( $options ) {
1500 - $db = wfGetDB( DB_MASTER );
1501 - } else {
1502 - $db = wfGetDB( DB_SLAVE );
1503 - }
1504 - $linkCache =& LinkCache::singleton();
1505 -
1506 - list( $page, $imagelinks ) = $db->tableNamesN( 'page', 'imagelinks' );
1507 - $encName = $db->addQuotes( $this->name );
1508 - $sql = "SELECT page_namespace,page_title,page_id FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options";
1509 - $res = $db->query( $sql, __METHOD__ );
1510 -
1511 - $retVal = array();
1512 - if ( $db->numRows( $res ) ) {
1513 - while ( $row = $db->fetchObject( $res ) ) {
1514 - if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
1515 - $linkCache->addGoodLinkObj( $row->page_id, $titleObj );
1516 - $retVal[] = $titleObj;
1517 - }
1518 - }
1519 - }
1520 - $db->freeResult( $res );
1521 - wfProfileOut( __METHOD__ );
1522 - return $retVal;
1523 - }
1524 -
1525 - /**
1526 - * @return array
1527 - */
1528 - function getExifData() {
1529 - $handler = $this->getHandler();
1530 - if ( !$handler || $handler->getMetadataType( $this ) != 'exif' ) {
1531 - return array();
1532 - }
1533 - if ( !$this->metadata ) {
1534 - return array();
1535 - }
1536 - $exif = unserialize( $this->metadata );
1537 - if ( !$exif ) {
1538 - return array();
1539 - }
1540 - unset( $exif['MEDIAWIKI_EXIF_VERSION'] );
1541 - $format = new FormatExif( $exif );
1542 -
1543 - return $format->getFormattedData();
1544 - }
1545 -
1546 - /**
1547 - * Returns true if the image does not come from the shared
1548 - * image repository.
1549 - *
1550 - * @return bool
1551 - */
1552 - function isLocal() {
1553 - return !$this->fromSharedDirectory;
1554 - }
1555 -
1556 - /**
1557 - * Was this image ever deleted from the wiki?
1558 - *
1559 - * @return bool
1560 - */
1561 - function wasDeleted() {
1562 - $title = Title::makeTitle( NS_IMAGE, $this->name );
1563 - return ( $title->isDeleted() > 0 );
1564 - }
1565 -
1566 - /**
1567 - * Delete all versions of the image.
1568 - *
1569 - * Moves the files into an archive directory (or deletes them)
1570 - * and removes the database rows.
1571 - *
1572 - * Cache purging is done; logging is caller's responsibility.
1573 - *
1574 - * @param string $reason
1575 - * @param boolean $suppress
1576 - * @return boolean true on success, false on some kind of failure
1577 - */
1578 - function delete( $reason, $suppress=false ) {
1579 - $transaction = new FSTransaction();
1580 - $urlArr = array( $this->getURL() );
1581 -
1582 - if( !FileStore::lock() ) {
1583 - wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" );
1584 - return false;
1585 - }
1586 -
1587 - try {
1588 - $dbw = wfGetDB( DB_MASTER );
1589 - $dbw->begin();
1590 -
1591 - // Delete old versions
1592 - $result = $dbw->select( 'oldimage',
1593 - array( 'oi_archive_name' ),
1594 - array( 'oi_name' => $this->name ) );
1595 -
1596 - while( $row = $dbw->fetchObject( $result ) ) {
1597 - $oldName = $row->oi_archive_name;
1598 -
1599 - $transaction->add( $this->prepareDeleteOld( $oldName, $reason, $suppress ) );
1600 -
1601 - // We'll need to purge this URL from caches...
1602 - $urlArr[] = wfImageArchiveUrl( $oldName );
1603 - }
1604 - $dbw->freeResult( $result );
1605 -
1606 - // And the current version...
1607 - $transaction->add( $this->prepareDeleteCurrent( $reason, $suppress ) );
1608 -
1609 - $dbw->immediateCommit();
1610 - } catch( MWException $e ) {
1611 - wfDebug( __METHOD__.": db error, rolling back file transactions\n" );
1612 - $transaction->rollback();
1613 - FileStore::unlock();
1614 - throw $e;
1615 - }
1616 -
1617 - wfDebug( __METHOD__.": deleted db items, applying file transactions\n" );
1618 - $transaction->commit();
1619 - FileStore::unlock();
1620 -
1621 -
1622 - // Update site_stats
1623 - $site_stats = $dbw->tableName( 'site_stats' );
1624 - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images-1", __METHOD__ );
1625 -
1626 - $this->purgeEverything( $urlArr );
1627 -
1628 - return true;
1629 - }
1630 -
1631 -
1632 - /**
1633 - * Delete an old version of the image.
1634 - *
1635 - * Moves the file into an archive directory (or deletes it)
1636 - * and removes the database row.
1637 - *
1638 - * Cache purging is done; logging is caller's responsibility.
1639 - *
1640 - * @param string $archiveName
1641 - * @param string $reason
1642 - * @param boolean $suppress
1643 - * @throws MWException or FSException on database or filestore failure
1644 - * @return boolean true on success, false on some kind of failure
1645 - */
1646 - function deleteOld( $archiveName, $reason, $suppress=false ) {
1647 - $transaction = new FSTransaction();
1648 - $urlArr = array();
1649 -
1650 - if( !FileStore::lock() ) {
1651 - wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" );
1652 - return false;
1653 - }
1654 -
1655 - $transaction = new FSTransaction();
1656 - try {
1657 - $dbw = wfGetDB( DB_MASTER );
1658 - $dbw->begin();
1659 - $transaction->add( $this->prepareDeleteOld( $archiveName, $reason, $suppress ) );
1660 - $dbw->immediateCommit();
1661 - } catch( MWException $e ) {
1662 - wfDebug( __METHOD__.": db error, rolling back file transaction\n" );
1663 - $transaction->rollback();
1664 - FileStore::unlock();
1665 - throw $e;
1666 - }
1667 -
1668 - wfDebug( __METHOD__.": deleted db items, applying file transaction\n" );
1669 - $transaction->commit();
1670 - FileStore::unlock();
1671 -
1672 - $this->purgeDescription();
1673 -
1674 - // Squid purging
1675 - global $wgUseSquid;
1676 - if ( $wgUseSquid ) {
1677 - $urlArr = array(
1678 - wfImageArchiveUrl( $archiveName ),
1679 - );
1680 - wfPurgeSquidServers( $urlArr );
1681 - }
1682 - return true;
1683 - }
1684 -
1685 - /**
1686 - * Delete the current version of a file.
1687 - * May throw a database error.
1688 - * @param string $reason
1689 - * @param boolean $suppress
1690 - * @return FStransaction on success, false on failure
1691 - */
1692 - private function prepareDeleteCurrent( $reason, $suppress=false ) {
1693 - return $this->prepareDeleteVersion(
1694 - $this->getFullPath(),
1695 - $reason,
1696 - 'image',
1697 - array(
1698 - 'fa_name' => 'img_name',
1699 - 'fa_archive_name' => 'NULL',
1700 - 'fa_size' => 'img_size',
1701 - 'fa_width' => 'img_width',
1702 - 'fa_height' => 'img_height',
1703 - 'fa_metadata' => 'img_metadata',
1704 - 'fa_bits' => 'img_bits',
1705 - 'fa_media_type' => 'img_media_type',
1706 - 'fa_major_mime' => 'img_major_mime',
1707 - 'fa_minor_mime' => 'img_minor_mime',
1708 - 'fa_description' => 'img_description',
1709 - 'fa_user' => 'img_user',
1710 - 'fa_user_text' => 'img_user_text',
1711 - 'fa_timestamp' => 'img_timestamp' ),
1712 - array( 'img_name' => $this->name ),
1713 - $suppress,
1714 - __METHOD__ );
1715 - }
1716 -
1717 - /**
1718 - * Delete a given older version of a file.
1719 - * May throw a database error.
1720 - * @param string $archiveName
1721 - * @param string $reason
1722 - * @param boolean $suppress
1723 - * @return FStransaction on success, false on failure
1724 - */
1725 - private function prepareDeleteOld( $archiveName, $reason, $suppress=false ) {
1726 - // Stored as either <time>!<name> or <time>!<key>
1727 - list($timestamp,$img) = explode('!',$archiveName,2);
1728 - // Is this image using a filestore key (hidden)?
1729 - if( $img != $this->name && FileStore::validKey($img) ) {
1730 - $group = 'hidden';
1731 -
1732 - $hiddenstore = FileStore::get( $group );
1733 - $oldpath = $hiddenstore->filePath( $img );
1734 - } else {
1735 - $oldpath = wfImageArchiveDir( $this->name ) . DIRECTORY_SEPARATOR . $archiveName;
1736 - }
1737 - return $this->prepareDeleteVersion(
1738 - $oldpath,
1739 - $reason,
1740 - 'oldimage',
1741 - array(
1742 - 'fa_name' => 'oi_name',
1743 - 'fa_archive_name' => 'oi_archive_name',
1744 - 'fa_size' => 'oi_size',
1745 - 'fa_width' => 'oi_width',
1746 - 'fa_height' => 'oi_height',
1747 - 'fa_metadata' => 'NULL',
1748 - 'fa_bits' => 'oi_bits',
1749 - 'fa_media_type' => 'NULL',
1750 - 'fa_major_mime' => 'NULL',
1751 - 'fa_minor_mime' => 'NULL',
1752 - 'fa_description' => 'oi_description',
1753 - 'fa_user' => 'oi_user',
1754 - 'fa_user_text' => 'oi_user_text',
1755 - 'fa_timestamp' => 'oi_timestamp',
1756 - 'fa_deleted' => 'oi_deleted' ),
1757 - array(
1758 - 'oi_name' => $this->name,
1759 - 'oi_archive_name' => $archiveName ),
1760 - $suppress,
1761 - __METHOD__ );
1762 - }
1763 -
1764 - /**
1765 - * Do the dirty work of backing up an image row and its file
1766 - * (if $wgSaveDeletedFiles is on) and removing the originals.
1767 - *
1768 - * Must be run while the file store is locked and a database
1769 - * transaction is open to avoid race conditions.
1770 - *
1771 - * @return FSTransaction
1772 - */
1773 - private function prepareDeleteVersion( $path, $reason, $table, $fieldMap, $where, $suppress=false, $fname ) {
1774 - global $wgUser, $wgSaveDeletedFiles;
1775 -
1776 - // Dupe the file into the file store
1777 - if( file_exists( $path ) ) {
1778 - if( $wgSaveDeletedFiles ) {
1779 - $group = 'deleted';
1780 -
1781 - $store = FileStore::get( $group );
1782 - $key = FileStore::calculateKey( $path, $this->extension );
1783 - $transaction = $store->insert( $key, $path, FileStore::DELETE_ORIGINAL );
1784 - } else {
1785 - $group = null;
1786 - $key = null;
1787 - $transaction = FileStore::deleteFile( $path );
1788 - }
1789 - } else {
1790 - wfDebug( __METHOD__." deleting already-missing '$path'; moving on to database\n" );
1791 - $group = null;
1792 - $key = null;
1793 - $transaction = new FSTransaction(); // empty
1794 - }
1795 -
1796 - if( $transaction === false ) {
1797 - // Fail to restore?
1798 - wfDebug( __METHOD__.": import to file store failed, aborting\n" );
1799 - throw new MWException( "Could not archive and delete file $path" );
1800 - return false;
1801 - }
1802 -
1803 - // Bitfields to further suppress the image content
1804 - if ( $suppress ) {
1805 - $bitfield = 0;
1806 - # We will have to follow up with a thumb purge
1807 - # and a file move to a private directory
1808 - $bitfield |= self::DELETED_FILE;
1809 - $bitfield |= self::DELETED_COMMENT;
1810 - $bitfield |= self::DELETED_USER;
1811 - $bitfield |= self::DELETED_RESTRICTED;
1812 - // This should be 15...
1813 - $fieldMap['fa_deleted'] = $bitfield;
1814 - }
1815 -
1816 - $dbw = wfGetDB( DB_MASTER );
1817 - $storageMap = array(
1818 - 'fa_storage_group' => $dbw->addQuotes( $group ),
1819 - 'fa_storage_key' => $dbw->addQuotes( $key ),
1820 -
1821 - 'fa_deleted_user' => $dbw->addQuotes( $wgUser->getId() ),
1822 - 'fa_deleted_timestamp' => $dbw->timestamp(),
1823 - 'fa_deleted_reason' => $dbw->addQuotes( $reason ) );
1824 - $allFields = array_merge( $storageMap, $fieldMap );
1825 -
1826 - try {
1827 - if( $wgSaveDeletedFiles ) {
1828 - $dbw->insertSelect( 'filearchive', $table, $allFields, $where, $fname );
1829 - }
1830 - $dbw->delete( $table, $where, $fname );
1831 - } catch( DBQueryError $e ) {
1832 - // Something went horribly wrong!
1833 - // Leave the file as it was...
1834 - wfDebug( __METHOD__.": database error, rolling back file transaction\n" );
1835 - $transaction->rollback();
1836 - throw $e;
1837 - }
1838 -
1839 - return $transaction;
1840 - }
1841 -
1842 - /**
1843 - * Restore all or specified deleted revisions to the given file.
1844 - * Permissions and logging are left to the caller.
1845 - *
1846 - * May throw database exceptions on error.
1847 - *
1848 - * @param string $timestamp, restore all revisions since this time
1849 - * @return the number of file revisions restored if successful,
1850 - * or false on failure
1851 - */
1852 - function restore( $timestamp = 0, $Unsuppress = false ) {
1853 - global $wgUser;
1854 -
1855 - if( !FileStore::lock() ) {
1856 - wfDebug( __METHOD__." could not acquire filestore lock\n" );
1857 - return false;
1858 - }
1859 -
1860 - $transaction = new FSTransaction();
1861 - try {
1862 - $dbw = wfGetDB( DB_MASTER );
1863 - $dbw->begin();
1864 -
1865 - // Make sure there is a page for this image
1866 - $page = $dbw->selectRow( 'page',
1867 - array( 'page_id', 'page_latest' ),
1868 - array( 'page_namespace' => $this->title->getNamespace(),
1869 - 'page_title' => $this->title->getDBkey() ),
1870 - __METHOD__ );
1871 - if( !$page )
1872 - return false;
1873 -
1874 - // Re-confirm whether this image presently exists;
1875 - // if no we'll need to create an image record for the
1876 - // first item we restore. Grab the timestamp
1877 - $exists = $dbw->selectField( 'image', '1',
1878 - array( 'img_name' => $this->name ),
1879 - __METHOD__,
1880 - array('ORDER BY' => 'img_timestamp DESC') );
1881 -
1882 - // Fetch all or selected archived revisions for the file,
1883 - // sorted from the most recent to the oldest.
1884 - $conditions = array( 'fa_name' => $this->name );
1885 - if( $timestamp ) {
1886 - $conditions[] = "fa_timestamp >= {$timestamp}";
1887 - }
1888 -
1889 - $result = $dbw->select( 'filearchive', '*',
1890 - $conditions,
1891 - __METHOD__,
1892 - array( 'ORDER BY' => 'fa_timestamp DESC' ) );
1893 -
1894 - if( $dbw->numRows( $result ) == 0 ) {
1895 - // Nothing to do.
1896 - wfDebug( __METHOD__.": nothing to do\n" );
1897 - $dbw->rollback();
1898 - FileStore::unlock();
1899 - return true;
1900 - }
1901 -
1902 - $revisions = 0;
1903 - while( $row = $dbw->fetchObject( $result ) ) {
1904 - $revisions++;
1905 - $store = FileStore::get( $row->fa_storage_group );
1906 - if( !$store ) {
1907 - wfDebug( __METHOD__.": skipping row with no file.\n" );
1908 - continue;
1909 - }
1910 - // Are there no live revisions?
1911 - if( $revisions == 1 && !$exists ) {
1912 - // We don't currently handle well changing the top revision's settings
1913 - if ( !$Unsuppress && $row->fa_deleted ) {
1914 - wfDebug( __METHOD__.": restoration would result in a deleted top revision\n" );
1915 - $dbw->rollback();
1916 - FileStore::unlock();
1917 - return false;
1918 - }
1919 -
1920 - $destDir = wfImageDir( $row->fa_name );
1921 - if ( !is_dir( $destDir ) ) {
1922 - wfMkdirParents( $destDir );
1923 - }
1924 - $destPath = $destDir . DIRECTORY_SEPARATOR . $row->fa_name;
1925 -
1926 - // We may have to fill in data if this was originally
1927 - // an archived file revision.
1928 - if( is_null( $row->fa_metadata ) ) {
1929 - $tempFile = $store->filePath( $row->fa_storage_key );
1930 -
1931 - $magic = MimeMagic::singleton();
1932 - $mime = $magic->guessMimeType( $tempFile, true );
1933 - $media_type = $magic->getMediaType( $tempFile, $mime );
1934 - list( $major_mime, $minor_mime ) = self::splitMime( $mime );
1935 - $handler = MediaHandler::getHandler( $mime );
1936 - if ( $handler ) {
1937 - $metadata = $handler->getMetadata( $image, $tempFile );
1938 - } else {
1939 - $metadata = '';
1940 - }
1941 - } else {
1942 - $metadata = $row->fa_metadata;
1943 - $major_mime = $row->fa_major_mime;
1944 - $minor_mime = $row->fa_minor_mime;
1945 - $media_type = $row->fa_media_type;
1946 - }
1947 -
1948 - $table = 'image';
1949 - $fields = array(
1950 - 'img_name' => $row->fa_name,
1951 - 'img_size' => $row->fa_size,
1952 - 'img_width' => $row->fa_width,
1953 - 'img_height' => $row->fa_height,
1954 - 'img_metadata' => $metadata,
1955 - 'img_bits' => $row->fa_bits,
1956 - 'img_media_type' => $media_type,
1957 - 'img_major_mime' => $major_mime,
1958 - 'img_minor_mime' => $minor_mime,
1959 - 'img_description' => $row->fa_description,
1960 - 'img_user' => $row->fa_user,
1961 - 'img_user_text' => $row->fa_user_text,
1962 - 'img_timestamp' => $row->fa_timestamp );
1963 - } else {
1964 - // Does this image already exists?
1965 - $archiveName = $row->fa_archive_name;
1966 - if( $archiveName == '' ) {
1967 - // This was originally a current version; we
1968 - // have to devise a new archive name for it.
1969 - // Format is <timestamp of archiving>!<name>
1970 - $archiveName = wfTimestamp( TS_MW, $row->fa_deleted_timestamp ) . '!' . $row->fa_name;
1971 - }
1972 -
1973 - list($timestamp,$img) = explode('!',$archiveName,2);
1974 - // Is this image hidden?
1975 - if( !$Unsuppress && $row->fa_deleted & Image::DELETED_FILE ) {
1976 - $group = 'hidden';
1977 - // Upon restoration, this should go into the hidden directory
1978 - $hiddenstore = FileStore::get( $group );
1979 - $destPath = $hiddenstore->filePath( $row->fa_storage_key );
1980 - // Follow the usual <timestamp>!<key> convention for hidden files
1981 - $archiveName = "{$timestamp}!{$row->fa_storage_key}";
1982 - // Does the archivename use a filestore key? (was hidden when deleted)
1983 - } else if( $img != $row->fa_name && FileStore::validKey($img) ) {
1984 - // Follow the usual <timestamp>!<image> convention for old files
1985 - $archiveName = "{$timestamp}!{$row->fa_name}";
1986 - $destPath = $destDir . DIRECTORY_SEPARATOR . $archiveName;
1987 - } else {
1988 - $destDir = wfImageArchiveDir( $row->fa_name );
1989 -
1990 - if ( !is_dir( $destDir ) ) {
1991 - wfMkdirParents( $destDir );
1992 - }
1993 - $destPath = $destDir . DIRECTORY_SEPARATOR . $archiveName;
1994 - }
1995 -
1996 - $table = 'oldimage';
1997 - $fields = array(
1998 - 'oi_name' => $row->fa_name,
1999 - 'oi_archive_name' => $archiveName,
2000 - 'oi_size' => $row->fa_size,
2001 - 'oi_width' => $row->fa_width,
2002 - 'oi_height' => $row->fa_height,
2003 - 'oi_bits' => $row->fa_bits,
2004 - 'oi_description' => $row->fa_description,
2005 - 'oi_user' => $row->fa_user,
2006 - 'oi_user_text' => $row->fa_user_text,
2007 - 'oi_timestamp' => $row->fa_timestamp,
2008 - 'oi_deleted' => $Unsuppress ? 0 : $row->fa_deleted );
2009 - }
2010 -
2011 - $dbw->insert( $table, $fields, __METHOD__ );
2012 - // @todo this delete is not totally safe, potentially
2013 - $dbw->delete( 'filearchive',
2014 - array( 'fa_id' => $row->fa_id ),
2015 - __METHOD__ );
2016 -
2017 - // Check if any other stored revisions use this file;
2018 - // if so, we shouldn't remove the file from the deletion
2019 - // archives so they will still work.
2020 - $useCount = $dbw->selectField( 'filearchive',
2021 - 'COUNT(*)',
2022 - array(
2023 - 'fa_storage_group' => $row->fa_storage_group,
2024 - 'fa_storage_key' => $row->fa_storage_key ),
2025 - __METHOD__ );
2026 - if( $useCount == 0 ) {
2027 - wfDebug( __METHOD__.": nothing else using {$row->fa_storage_key}, will deleting after\n" );
2028 - $flags = FileStore::DELETE_ORIGINAL;
2029 - } else {
2030 - $flags = 0;
2031 - }
2032 -
2033 - $transaction->add( $store->export( $row->fa_storage_key, $destPath, $flags ) );
2034 - }
2035 -
2036 - $dbw->immediateCommit();
2037 - } catch( MWException $e ) {
2038 - wfDebug( __METHOD__." caught error, aborting\n" );
2039 - $transaction->rollback();
2040 - throw $e;
2041 - }
2042 -
2043 - $transaction->commit();
2044 - FileStore::unlock();
2045 -
2046 - if( $revisions > 0 ) {
2047 - if( !$exists ) {
2048 - wfDebug( __METHOD__." restored $revisions items, creating a new current\n" );
2049 -
2050 - // Update site_stats
2051 - $site_stats = $dbw->tableName( 'site_stats' );
2052 - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ );
2053 -
2054 - $this->purgeEverything();
2055 - } else {
2056 - wfDebug( __METHOD__." restored $revisions as archived versions\n" );
2057 - $this->purgeDescription();
2058 - }
2059 - }
2060 -
2061 - return $revisions;
2062 - }
2063 -
2064 - /**
2065 - * Returns 'true' if this image is a multipage document, e.g. a DJVU
2066 - * document.
2067 - *
2068 - * @return Bool
2069 - */
2070 - function isMultipage() {
2071 - $handler = $this->getHandler();
2072 - return $handler && $handler->isMultiPage();
2073 - }
2074 -
2075 - /**
2076 - * Returns the number of pages of a multipage document, or NULL for
2077 - * documents which aren't multipage documents
2078 - */
2079 - function pageCount() {
2080 - $handler = $this->getHandler();
2081 - if ( $handler && $handler->isMultiPage() ) {
2082 - return $handler->pageCount( $this );
2083 - } else {
2084 - return null;
2085 - }
2086 - }
2087 -
2088 - static function getCommonsDB() {
2089 - static $dbc;
2090 - global $wgLoadBalancer, $wgSharedUploadDBname;
2091 - if ( !isset( $dbc ) ) {
2092 - $i = $wgLoadBalancer->getGroupIndex( 'commons' );
2093 - $dbinfo = $wgLoadBalancer->mServers[$i];
2094 - $dbc = new Database( $dbinfo['host'], $dbinfo['user'],
2095 - $dbinfo['password'], $wgSharedUploadDBname );
2096 - }
2097 - return $dbc;
2098 - }
2099 -
2100 - /**
2101 - * Calculate the height of a thumbnail using the source and destination width
2102 - */
2103 - static function scaleHeight( $srcWidth, $srcHeight, $dstWidth ) {
2104 - // Exact integer multiply followed by division
2105 - if ( $srcWidth == 0 ) {
2106 - return 0;
2107 - } else {
2108 - return round( $srcHeight * $dstWidth / $srcWidth );
2109 - }
2110 - }
2111 -
2112 - /**
2113 - * Get an image size array like that returned by getimagesize(), or false if it
2114 - * can't be determined.
2115 - *
2116 - * @param string $fileName The filename
2117 - * @return array
2118 - */
2119 - function getImageSize( $fileName ) {
2120 - $handler = $this->getHandler();
2121 - return $handler->getImageSize( $this, $fileName );
2122 - }
2123 -
2124 - /**
2125 - * Get the thumbnail extension and MIME type for a given source MIME type
2126 - * @return array thumbnail extension and MIME type
2127 - */
2128 - static function getThumbType( $ext, $mime ) {
2129 - $handler = MediaHandler::getHandler( $mime );
2130 - if ( $handler ) {
2131 - return $handler->getThumbType( $ext, $mime );
2132 - } else {
2133 - return array( $ext, $mime );
2134 - }
2135 - }
2136 -
2137 -} //class
2138 -
2139 -/**
2140 - * @addtogroup Media
2141 - */
2142 -class OldImage
2143 -{
2144 - /**
2145 - * Returns a file object from the oldimage table
2146 - * @param $title, the corresponding image page title
2147 - * @param $name, the storage name
2148 - * @return bool, file was found?
2149 - */
2150 - function OldImage( $title, $name=null ) {
2151 - if( !is_object( $title ) || is_null($name) ) {
2152 - throw new MWException( 'Image constructor given bogus title.' );
2153 - }
2154 - if( $title->getNamespace() == NS_IMAGE ) {
2155 - $dbr = wfGetDB( DB_SLAVE );
2156 - $res = $dbr->select( 'oldimage',
2157 - array(
2158 - 'oi_name',
2159 - 'oi_archive_name',
2160 - 'oi_size',
2161 - 'oi_bits',
2162 - 'oi_width',
2163 - 'oi_height',
2164 - 'oi_metadata',
2165 - 'oi_media_type',
2166 - 'oi_major_mime',
2167 - 'oi_minor_mime',
2168 - 'oi_description',
2169 - 'oi_user',
2170 - 'oi_user_text',
2171 - 'oi_timestamp',
2172 - 'oi_deleted' ),
2173 - array(
2174 - 'oi_name' => $title->getDbKey(),
2175 - 'oi_archive_name' => $name ),
2176 - __METHOD__,
2177 - array( 'ORDER BY' => 'oi_timestamp DESC' ) );
2178 - // this revision does not exist?
2179 - if ( $dbr->numRows( $res ) == 0 ) {
2180 - return false;
2181 - }
2182 - $ret = $dbr->resultObject( $res );
2183 - $row = $ret->fetchObject();
2184 -
2185 - // initialize fields for filestore image object
2186 - $this->mName = $row->oi_name;
2187 - $this->mArchiveName = $row->oi_archive_name;
2188 - $this->mSize = $row->oi_size;
2189 - $this->mBits = $row->oi_bits;
2190 - $this->mWidth = $row->oi_width;
2191 - $this->mHeight = $row->oi_height;
2192 - $this->mMetaData = $row->oi_metadata;
2193 - $this->mMime = "{$row->oi_major_mime}/{$row->oi_minor_mime}";
2194 - $this->mType = $row->oi_media_type;
2195 - $this->mDescription = $row->oi_description;
2196 - $this->mUser = $row->oi_user;
2197 - $this->mUserText = $row->oi_user_text;
2198 - $this->mTimestamp = $row->oi_timestamp;
2199 - $this->mDeleted = $row->oi_deleted;
2200 -
2201 - $n = strrpos( $this->mName, '.' );
2202 - $this->extension = Image::normalizeExtension( $n ?
2203 - substr( $this->mName, $n + 1 ) : '' );
2204 - } else {
2205 - throw new MWException( 'This title does not correspond to an image page.' );
2206 - return false;
2207 - }
2208 - return true;
2209 - }
2210 -
2211 - /**
2212 - * int $field one of DELETED_* bitfield constants
2213 - * for file or revision rows
2214 - * @return bool
2215 - */
2216 - function isDeleted( $field ) {
2217 - return ($this->mDeleted & $field) == $field;
2218 - }
2219 -
2220 - /**
2221 - * Determine if the current user is allowed to view a particular
2222 - * field of this OldImage file, if it's marked as deleted.
2223 - * @param int $field
2224 - * @return bool
2225 - */
2226 - function userCan( $field ) {
2227 - if( ($this->mDeleted & $field) == $field ) {
2228 - global $wgUser;
2229 - $permission = ( $this->mDeleted & Image::DELETED_RESTRICTED ) == Image::DELETED_RESTRICTED
2230 - ? 'hiderevision'
2231 - : 'deleterevision';
2232 - wfDebug( "Checking for $permission due to $field match on $this->mDeleted\n" );
2233 - return $wgUser->isAllowed( $permission );
2234 - } else {
2235 - return true;
2236 - }
2237 - }
2238 -}
2239 -
2240 -/**
2241 - * @addtogroup Media
2242 - */
2243 -class ArchivedFile
2244 -{
2245 - /**
2246 - * Returns a file object from the filearchive table
2247 - * @param $title, the corresponding image page title
2248 - * @param $id, the image id, a unique key
2249 - * @param $key, optional storage key
2250 - * @return bool, file was found?
2251 - */
2252 - function ArchivedFile( $title, $id=0, $key='' ) {
2253 - if( !is_object( $title ) ) {
2254 - throw new MWException( 'Image constructor given bogus title.' );
2255 - }
2256 - $conds = ($id) ? "fa_id = $id" : "fa_storage_key = '$key'";
2257 - if( $title->getNamespace() == NS_IMAGE ) {
2258 - $dbr = wfGetDB( DB_SLAVE );
2259 - $res = $dbr->select( 'filearchive',
2260 - array(
2261 - 'fa_id',
2262 - 'fa_name',
2263 - 'fa_storage_key',
2264 - 'fa_storage_group',
2265 - 'fa_size',
2266 - 'fa_bits',
2267 - 'fa_width',
2268 - 'fa_height',
2269 - 'fa_metadata',
2270 - 'fa_media_type',
2271 - 'fa_major_mime',
2272 - 'fa_minor_mime',
2273 - 'fa_description',
2274 - 'fa_user',
2275 - 'fa_user_text',
2276 - 'fa_timestamp',
2277 - 'fa_deleted' ),
2278 - array(
2279 - 'fa_name' => $title->getDbKey(),
2280 - $conds ),
2281 - __METHOD__,
2282 - array( 'ORDER BY' => 'fa_timestamp DESC' ) );
2283 -
2284 - if ( $dbr->numRows( $res ) == 0 ) {
2285 - // this revision does not exist?
2286 - return false;
2287 - }
2288 - $ret = $dbr->resultObject( $res );
2289 - $row = $ret->fetchObject();
2290 -
2291 - // initialize fields for filestore image object
2292 - $this->mId = intval($row->fa_id);
2293 - $this->mName = $row->fa_name;
2294 - $this->mGroup = $row->fa_storage_group;
2295 - $this->mKey = $row->fa_storage_key;
2296 - $this->mSize = $row->fa_size;
2297 - $this->mBits = $row->fa_bits;
2298 - $this->mWidth = $row->fa_width;
2299 - $this->mHeight = $row->fa_height;
2300 - $this->mMetaData = $row->fa_metadata;
2301 - $this->mMime = "{$row->fa_major_mime}/{$row->fa_minor_mime}";
2302 - $this->mType = $row->fa_media_type;
2303 - $this->mDescription = $row->fa_description;
2304 - $this->mUser = $row->fa_user;
2305 - $this->mUserText = $row->fa_user_text;
2306 - $this->mTimestamp = $row->fa_timestamp;
2307 - $this->mDeleted = $row->fa_deleted;
2308 - } else {
2309 - throw new MWException( 'This title does not correspond to an image page.' );
2310 - return false;
2311 - }
2312 - return true;
2313 - }
2314 -
2315 - /**
2316 - * int $field one of DELETED_* bitfield constants
2317 - * for file or revision rows
2318 - * @return bool
2319 - */
2320 - function isDeleted( $field ) {
2321 - return ($this->mDeleted & $field) == $field;
2322 - }
2323 -
2324 - /**
2325 - * Determine if the current user is allowed to view a particular
2326 - * field of this FileStore image file, if it's marked as deleted.
2327 - * @param int $field
2328 - * @return bool
2329 - */
2330 - function userCan( $field ) {
2331 - if( ($this->mDeleted & $field) == $field ) {
2332 - global $wgUser;
2333 - $permission = ( $this->mDeleted & Image::DELETED_RESTRICTED ) == Image::DELETED_RESTRICTED
2334 - ? 'hiderevision'
2335 - : 'deleterevision';
2336 - wfDebug( "Checking for $permission due to $field match on $this->mDeleted\n" );
2337 - return $wgUser->isAllowed( $permission );
2338 - } else {
2339 - return true;
2340 - }
2341 - }
2342 -}
2343 -
2344 -/**
2345 - * Aliases for backwards compatibility with 1.6
2346 - */
2347 -define( 'MW_IMG_DELETED_FILE', Image::DELETED_FILE );
2348 -define( 'MW_IMG_DELETED_COMMENT', Image::DELETED_COMMENT );
2349 -define( 'MW_IMG_DELETED_USER', Image::DELETED_USER );
2350 -define( 'MW_IMG_DELETED_RESTRICTED', Image::DELETED_RESTRICTED );
2351 -
2352 -?>
Index: branches/phase3_rev_deleted/includes/ImageFunctions.php
@@ -1,114 +1,5 @@
22 <?php
3 -
43 /**
5 - * Returns the image directory of an image
6 - * The result is an absolute path.
7 - *
8 - * This function is called from thumb.php before Setup.php is included
9 - *
10 - * @param $fname String: file name of the image file.
11 - * @public
12 - */
13 -function wfImageDir( $fname ) {
14 - global $wgUploadDirectory, $wgHashedUploadDirectory;
15 -
16 - if (!$wgHashedUploadDirectory) { return $wgUploadDirectory; }
17 -
18 - $hash = md5( $fname );
19 - $dest = $wgUploadDirectory . '/' . $hash{0} . '/' . substr( $hash, 0, 2 );
20 -
21 - return $dest;
22 -}
23 -
24 -/**
25 - * Returns the image directory of an image's thumbnail
26 - * The result is an absolute path.
27 - *
28 - * This function is called from thumb.php before Setup.php is included
29 - *
30 - * @param $fname String: file name of the original image file
31 - * @param $shared Boolean: (optional) use the shared upload directory (default: 'false').
32 - * @public
33 - */
34 -function wfImageThumbDir( $fname, $shared = false ) {
35 - $base = wfImageArchiveDir( $fname, 'thumb', $shared );
36 - if ( Image::isHashed( $shared ) ) {
37 - $dir = "$base/$fname";
38 - } else {
39 - $dir = $base;
40 - }
41 -
42 - return $dir;
43 -}
44 -
45 -/**
46 - * Old thumbnail directory, kept for conversion
47 - */
48 -function wfDeprecatedThumbDir( $thumbName , $subdir='thumb', $shared=false) {
49 - return wfImageArchiveDir( $thumbName, $subdir, $shared );
50 -}
51 -
52 -/**
53 - * Returns the image directory of an image's old version
54 - * The result is an absolute path.
55 - *
56 - * This function is called from thumb.php before Setup.php is included
57 - *
58 - * @param $fname String: file name of the thumbnail file, including file size prefix.
59 - * @param $subdir String: subdirectory of the image upload directory that should be used for storing the old version. Default is 'archive'.
60 - * @param $shared Boolean use the shared upload directory (only relevant for other functions which call this one). Default is 'false'.
61 - * @public
62 - */
63 -function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) {
64 - global $wgUploadDirectory, $wgHashedUploadDirectory;
65 - global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory;
66 - $dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory;
67 - $hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory;
68 - if (!$hashdir) { return $dir.'/'.$subdir; }
69 - $hash = md5( $fname );
70 -
71 - return $dir.'/'.$subdir.'/'.$hash[0].'/'.substr( $hash, 0, 2 );
72 -}
73 -
74 -
75 -/*
76 - * Return the hash path component of an image path (URL or filesystem),
77 - * e.g. "/3/3c/", or just "/" if hashing is not used.
78 - *
79 - * @param $dbkey The filesystem / database name of the file
80 - * @param $fromSharedDirectory Use the shared file repository? It may
81 - * use different hash settings from the local one.
82 - */
83 -function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) {
84 - if( Image::isHashed( $fromSharedDirectory ) ) {
85 - $hash = md5($dbkey);
86 - return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/';
87 - } else {
88 - return '/';
89 - }
90 -}
91 -
92 -/**
93 - * Returns the image URL of an image's old version
94 - *
95 - * @param $name String: file name of the image file
96 - * @param $subdir String: (optional) subdirectory of the image upload directory that is used by the old version. Default is 'archive'
97 - * @public
98 - */
99 -function wfImageArchiveUrl( $name, $subdir='archive' ) {
100 - global $wgUploadPath, $wgHashedUploadDirectory;
101 -
102 - if ($wgHashedUploadDirectory) {
103 - $hash = md5( substr( $name, 15) );
104 - $url = $wgUploadPath.'/'.$subdir.'/' . $hash{0} . '/' .
105 - substr( $hash, 0, 2 ) . '/'.$name;
106 - } else {
107 - $url = $wgUploadPath.'/'.$subdir.'/'.$name;
108 - }
109 - return wfUrlencode($url);
110 -}
111 -
112 -/**
1134 * Return a rounded pixel equivalent for a labeled CSS/SVG length.
1145 * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers
1156 *
Index: branches/phase3_rev_deleted/includes/SpecialRevisiondelete.php
@@ -66,14 +66,14 @@
6767
6868 // For reviewing deleted files
6969 if ( $file ) {
70 - $oimage = new OldImage( $this->page, $file );
 70+ $oimage = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $page, $file );
7171 // Check if user is allowed to see this file
72 - if ( !$oimage->userCan(Image::DELETED_FILE) ) {
 72+ if( !$oimage->userCan(File::DELETED_FILE) ) {
7373 $wgOut->permissionRequired( 'hiderevision' );
7474 return false;
7575 } else {
7676 // Format for hidden images is <timestamp>!<key>
77 - list($ts,$key) = explode('!',$file);
 77+ list($ts,$key) = explode('!',$file,2);
7878 return $this->showFile( $key );
7979 }
8080 }
@@ -88,11 +88,11 @@
8989 $this->deletetype='arid';
9090 } else if( $oldimages ) {
9191 $this->ofiles = $oldimages;
92 - $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', Image::DELETED_FILE );
 92+ $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', File::DELETED_FILE );
9393 $this->deletetype='oldimage';
9494 } else if( $fileids ) {
9595 $this->afiles = $fileids;
96 - $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', Image::DELETED_FILE );
 96+ $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', File::DELETED_FILE );
9797 $this->deletetype='fileid';
9898 } else if( $logids ) {
9999 $this->events = $logids;
@@ -127,15 +127,6 @@
128128 }
129129
130130 /**
131 - * This sets any fields that are true to a bitfield to true on a given bitfield
132 - * @param $bitfield, running bitfield
133 - * @param $nbitfield, new bitfiled
134 - */
135 - function setBitfield( $bitfield, $nbitfield ) {
136 - return $bitfield | $nbitfield;
137 - }
138 -
139 - /**
140131 * This lets a user set restrictions for live and archived revisions
141132 * @param WebRequest $request
142133 */
@@ -166,7 +157,7 @@
167158 $UserAllowed=false;
168159 }
169160 $wgOut->addHtml( $this->historyLine( $rev ) );
170 - $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted );
 161+ $bitfields |= $rev->mDeleted;
171162 }
172163 // The archives...
173164 } else {
@@ -185,7 +176,7 @@
186177 $UserAllowed=false;
187178 }
188179 $wgOut->addHtml( $this->historyLine( $rev ) );
189 - $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted );
 180+ $bitfields |= $rev->mDeleted;
190181 }
191182 }
192183 $wgOut->addHtml( "</ul>" );
@@ -253,26 +244,27 @@
254245 // Our image may be hidden, if so it's name is formated as <time>!<key>
255246 // Otherwise, it will be <time>!<image> and the URL only needs to pass the time
256247 $archivename = ( strpos($name,'!')==false ) ? $name.'!'.$this->page->getDbKey() : $name;
257 - $oimage = new OldImage( $this->page, $archivename );
258 - if( !isset( $oimage->mName ) ) {
 248+
 249+ $oimage = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->page, $archivename );
 250+ if( !$oimage->exists() ) {
259251 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
260252 return;
261 - } else if( !$oimage->userCan(Revision::DELETED_RESTRICTED) ) {
 253+ } else if( !$oimage->userCan(File::DELETED_RESTRICTED) ) {
262254 // If a rev is hidden from sysops
263 - if( $action != 'submit') {
264 - $wgOut->permissionRequired( 'hiderevision' );
 255+ if( $action != 'submit' ) {
 256+ $wgOut->permissionRequired( 'hiderevision' );
265257 return;
266258 }
267259 $UserAllowed=false;
268260 }
269261 $wgOut->addHtml( $this->uploadLine( $oimage ) );
270 - $bitfields = $this->setBitfield( $bitfields, $oimage->mDeleted );
 262+ $bitfields |= $oimage->deleted;
271263 }
272264 // Archived files...
273265 } else {
274266 foreach( $this->afiles as $fileid ) {
275267 $file = new ArchivedFile( $this->page, $fileid );
276 - if( !isset( $file->mId ) ) {
 268+ if( !isset( $file->id ) ) {
277269 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
278270 return;
279271 } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) {
@@ -284,7 +276,7 @@
285277 $UserAllowed=false;
286278 }
287279 $wgOut->addHtml( $this->uploadLine( $file ) );
288 - $bitfields = $this->setBitfield( $bitfields, $file->mDeleted );
 280+ $bitfields |= $file->deleted;
289281 }
290282 }
291283 $wgOut->addHtml( "</ul>" );
@@ -360,7 +352,7 @@
361353 $UserAllowed=false;
362354 }
363355 $wgOut->addHtml( $this->logLine( $log, $event ) );
364 - $bitfields = $this->setBitfield( $bitfields, $event->log_deleted );
 356+ $bitfields |= $event->log_deleted;
365357 }
366358 $wgOut->addHtml( "</ul>" );
367359
@@ -438,7 +430,7 @@
439431 }
440432
441433 /**
442 - * @param OldImage or ArchivedFile $file
 434+ * @param OldLocalImage or ArchivedFile $file
443435 * This can work for old or archived revisions
444436 * @returns string
445437 */
@@ -446,19 +438,19 @@
447439 global $wgContLang, $wgTitle;
448440
449441 $target = $this->page->getPrefixedText();
450 - $date = $wgContLang->timeanddate( $file->mTimestamp, true );
 442+ $date = $wgContLang->timeanddate( $file->timestamp, true );
451443
452444 $del = '';
453445 // Special:Undelete for viewing archived images
454446 if( $this->deletetype=='fileid' ) {
455447 $undelete = SpecialPage::getTitleFor( 'Undelete' );
456 - $pageLink = $this->skin->makeKnownLinkObj( $undelete, $date, "target=$target&file=$file->mKey" );
 448+ $pageLink = $this->skin->makeKnownLinkObj( $undelete, $date, "target=$target&file=$file->key" );
457449 // Revisiondelete for viewing images
458450 } else {
459451 # Hidden files...
460 - if( $file->isDeleted(Image::DELETED_FILE) ) {
 452+ if( $file->isDeleted(File::DELETED_FILE) ) {
461453 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
462 - if( !$file->userCan(Image::DELETED_FILE) ) {
 454+ if( !$file->userCan(File::DELETED_FILE) ) {
463455 $pageLink = $date;
464456 } else {
465457 $pageLink = $this->skin->makeKnownLinkObj( $wgTitle, $date, "target=$target&file=$file->mArchiveName" );
@@ -466,18 +458,18 @@
467459 $pageLink = '<span class="history-deleted">' . $pageLink . '</span>';
468460 # Regular files...
469461 } else {
470 - $url = htmlspecialchars( wfImageArchiveUrl( $file->mArchiveName ) );
 462+ $url = $file->getUrlRel();
471463 $pageLink = "<a href=\"{$url}\">{$date}</a>";
472464 }
473465 }
474466
475467 $data = wfMsgHtml( 'widthheight',
476 - $wgContLang->formatNum( $file->mWidth ),
477 - $wgContLang->formatNum( $file->mHeight ) ) .
478 - ' (' . wfMsgHtml( 'nbytes', $wgContLang->formatNum( $file->mSize ) ) . ')';
 468+ $wgContLang->formatNum( $file->width ),
 469+ $wgContLang->formatNum( $file->height ) ) .
 470+ ' (' . wfMsgHtml( 'nbytes', $wgContLang->formatNum( $file->size ) ) . ')';
479471
480 - return
481 - "<li> $pageLink " . $this->skin->fileUserLink( $file ) . " $data " . $this->skin->fileComment( $file ) . "$del</li>";
 472+ #return "<li> $pageLink " . $this->skin->fileUserLink( $file ) . " $data " . $this->skin->fileComment( $file ) . "$del</li>";
 473+ return "<li> $pageLink $data $del</li>";
482474 }
483475
484476 /**
@@ -718,24 +710,24 @@
719711 // Our image may be hidden, if so it's name is formated as <time>!<key>
720712 // Otherwise, it will be <time>!<image> and the URL only needs to pass the time
721713 $archivename = ( strpos($name,'!')==false ) ? $name.'!'.$title->getDbKey() : $name;
722 - $oimage = new OldImage( $title, $archivename );
723 - if( !isset($oimage->mName) ) {
 714+ $oimage = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $archivename );
 715+ if( !$oimage->exists() ) {
724716 return false;
725 - } else if( !$oimage->userCan(Revision::DELETED_RESTRICTED) ) {
 717+ } else if( !$oimage->userCan(File::DELETED_RESTRICTED) ) {
726718 $UserAllowedAll=false;
727719 continue;
728720 }
729721
730722 $transaction = true;
731723 // Which revisions did we change anything about?
732 - if( $oimage->mDeleted != $bitfield ) {
 724+ if( $oimage->deleted != $bitfield ) {
733725 $count++;
734726
735727 $this->dbw->begin();
736728 $this->updateOldFiles( $oimage, $bitfield );
737729 // If this image is currently hidden...
738 - if( $oimage->mDeleted & Image::DELETED_FILE ) {
739 - if( $bitfield & Image::DELETED_FILE ) {
 730+ if( $oimage->deleted & File::DELETED_FILE ) {
 731+ if( $bitfield & File::DELETED_FILE ) {
740732 # Leave it alone if we are not changing this...
741733 $set[]=$name;
742734 $transaction = true;
@@ -745,7 +737,7 @@
746738 $set[]=$transaction;
747739 }
748740 // Is it just now becoming hidden?
749 - } else if( $bitfield & Image::DELETED_FILE ) {
 741+ } else if( $bitfield & File::DELETED_FILE ) {
750742 $transaction = $this->makeOldImagePrivate( $oimage );
751743 $set[]=$transaction;
752744 } else {
@@ -790,9 +782,9 @@
791783 // To work!
792784 foreach( $items as $fileid ) {
793785 $file = new ArchivedFile( $title, $fileid );
794 - if( !isset($file->mId) ) {
 786+ if( !isset($file->id) ) {
795787 return false;
796 - } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) {
 788+ } else if( !$file->userCan(File::DELETED_RESTRICTED) ) {
797789 $UserAllowedAll=false;
798790 continue;
799791 }
@@ -886,16 +878,16 @@
887879 return false;
888880 }
889881
890 - list($timestamp,$img) = explode('!',$oimage->mArchiveName,2);
 882+ list($timestamp,$img) = explode('!',$oimage->archive_name,2);
891883
892 - $oldpath = wfImageArchiveDir( $oimage->mName ) . DIRECTORY_SEPARATOR . $oimage->mArchiveName;
 884+ $oldpath = $oimage->getArchivePath() . DIRECTORY_SEPARATOR . $oimage->archive_name;
893885 // Dupe the file into the file store
894886 if( file_exists( $oldpath ) ) {
895887 $group = 'hidden';
896888 // Is our directory configured?
897889 if( $wgFileStore[$group]['directory'] ) {
898890 $store = FileStore::get( $group );
899 - $key = FileStore::calculateKey( $oldpath, $oimage->extension );
 891+ $key = FileStore::calculateKey( $oldpath, $oimage->getExtension() );
900892 $transaction->add( $store->insert( $key, $oldpath, FileStore::DELETE_ORIGINAL ) );
901893 } else {
902894 $group = null;
@@ -924,12 +916,12 @@
925917 if ( $key ) {
926918 $this->dbw->update( 'oldimage',
927919 array( 'oi_archive_name' => "{$timestamp}!{$key}" ),
928 - array( 'oi_name' => $oimage->mName, 'oi_archive_name' => $oimage->mArchiveName ),
 920+ array( 'oi_name' => $oimage->name, 'oi_archive_name' => $oimage->archive_name ),
929921 __METHOD__ );
930922 }
931923
932924 // Use of $timeframe for Image objects can create thumbnails of oldimages
933 - $imgtitle = Title::makeTitle( NS_IMAGE, $oimage->mName );
 925+ $imgtitle = Title::makeTitle( NS_IMAGE, $oimage->name );
934926 $image = new Image( $imgtitle );
935927 $image->purgeCache(); // Clear any thumbnails/purge squid cache
936928
@@ -963,25 +955,24 @@
964956 return false;
965957 }
966958
967 - $destDir = wfImageArchiveDir( $oimage->mName );
 959+ $destDir = $oimage->getArchivePath();
968960 if ( !is_dir( $destDir ) ) {
969961 wfMkdirParents( $destDir );
970962 }
971963 // Deleted versions have an archive_name like <timestamp>!<key>
972 - list($timestamp,$key) = explode('!',$oimage->mArchiveName);
973 - $archivename = "{$timestamp}!{$oimage->mName}";
 964+ list($timestamp,$key) = explode('!',$oimage->archive_name);
 965+ $archivename = "{$timestamp}!{$oimage->name}";
974966
975967 $destPath = $destDir . DIRECTORY_SEPARATOR . $archivename;
976968 // Check if any other stored revisions use this file;
977969 // if so, we shouldn't remove the file from the hidden
978970 // archives so they will still work.
979 - $useCount = $this->dbw->selectField( 'oldimage',
980 - 'COUNT(*)',
981 - array( 'oi_archive_name' => $oimage->mArchiveName, 'oi_name' => $oimage->mName ),
 971+ $useCount = $this->dbw->selectField( 'oldimage','COUNT(*)',
 972+ array( 'oi_archive_name' => $oimage->archive_name, 'oi_name' => $oimage->name ),
982973 __METHOD__ );
983974
984975 if( $useCount == 0 ) {
985 - wfDebug( __METHOD__.": nothing else using {$oimage->mArchiveName}, will deleting after\n" );
 976+ wfDebug( __METHOD__.": nothing else using {$oimage->archive_name}, will deleting after\n" );
986977 $flags = FileStore::DELETE_ORIGINAL;
987978 } else {
988979 $flags = 0;
@@ -993,8 +984,8 @@
994985 FileStore::unlock();
995986 // Re-insert the original archive_name, like <timestamp>!<name>
996987 $this->dbw->update( 'oldimage',
997 - array( 'oi_archive_name' => "{$timestamp}!{$oimage->mName}" ),
998 - array( 'oi_name' => $oimage->mName, 'oi_archive_name' => $oimage->mArchiveName ),
 988+ array( 'oi_archive_name' => "{$timestamp}!{$oimage->name}" ),
 989+ array( 'oi_name' => $oimage->name, 'oi_archive_name' => $oimage->archive_name ),
999990 __METHOD__ );
1000991
1001992 return $timestamp;
@@ -1032,7 +1023,7 @@
10331024 function updateOldFiles( $oimage, $bitfield ) {
10341025 $this->dbw->update( 'oldimage',
10351026 array( 'oi_deleted' => $bitfield ),
1036 - array( 'oi_archive_name' => $oimage->mArchiveName ),
 1027+ array( 'oi_archive_name' => $oimage->archive_name ),
10371028 'RevisionDeleter::updateOldFiles' );
10381029 }
10391030
@@ -1044,7 +1035,7 @@
10451036 function updateArchFiles( $file, $bitfield ) {
10461037 $this->dbw->update( 'filearchive',
10471038 array( 'fa_deleted' => $bitfield ),
1048 - array( 'fa_id' => $file->mId ),
 1039+ array( 'fa_id' => $file->id ),
10491040 'RevisionDeleter::updateArchFiles' );
10501041 }
10511042
Index: branches/phase3_rev_deleted/includes/OutputPage.php
@@ -54,6 +54,8 @@
5555 $this->mETag = false;
5656 $this->mRevisionId = null;
5757 $this->mNewSectionLink = false;
 58+ $this->mTemplateIds = array();
 59+ $this->mImageTimestamps = array();
5860 }
5961
6062 public function redirect( $url, $responsecode = '302' ) {
@@ -384,6 +386,10 @@
385387 }
386388 $this->mNoGallery = $parserOutput->getNoGallery();
387389 $this->mHeadItems = array_merge( $this->mHeadItems, (array)$parserOutput->mHeadItems );
 390+ // Versioning...
 391+ $this->mTemplateIds += (array)$parserOutput->mTemplateIds;
 392+ $this->mImageTimestamps += (array)$parserOutput->mImageTimestamps;
 393+
388394 wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
389395 }
390396
@@ -1246,12 +1252,12 @@
12471253 * @param int $lag Slave lag
12481254 */
12491255 public function showLagWarning( $lag ) {
1250 - global $wgSlaveLagWarning, $wgSlaveLagOhNo;
 1256+ global $wgSlaveLagWarning, $wgSlaveLagCritical;
12511257
12521258 if ($lag < $wgSlaveLagWarning)
12531259 return;
12541260
1255 - $message = $lag >= $wgSlaveLagOhNo ? 'lag-warn-high' : 'lag-warn-normal';
 1261+ $message = ($lag >= $wgSlaveLagCritical) ? 'lag-warn-high' : 'lag-warn-normal';
12561262 $warning = wfMsgHtml( $message, htmlspecialchars( $lag ) );
12571263 $this->addHtml( "<div class=\"mw-{$message}\">\n{$warning}\n</div>\n" );
12581264 }
Index: branches/phase3_rev_deleted/includes/Setup.php
@@ -54,6 +54,59 @@
5555 if( $wgReadOnlyFile === false ) $wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR";
5656 if( $wgFileCacheDirectory === false ) $wgFileCacheDirectory = "{$wgUploadDirectory}/cache";
5757
 58+/**
 59+ * Initialise $wgLocalFileRepo from backwards-compatible settings
 60+ */
 61+if ( !$wgLocalFileRepo ) {
 62+ $wgLocalFileRepo = array(
 63+ 'class' => 'LocalRepo',
 64+ 'name' => 'local',
 65+ 'directory' => $wgUploadDirectory,
 66+ 'url' => $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath,
 67+ 'hashLevels' => $wgHashedUploadDirectory ? 2 : 0,
 68+ 'thumbScriptUrl' => $wgThumbnailScriptPath,
 69+ 'transformVia404' => !$wgGenerateThumbnailOnParse,
 70+ );
 71+}
 72+/**
 73+ * Initialise shared repo from backwards-compatible settings
 74+ */
 75+if ( $wgUseSharedUploads ) {
 76+ if ( $wgSharedUploadDBname ) {
 77+ $wgForeignFileRepos[] = array(
 78+ 'class' => 'ForeignDBRepo',
 79+ 'name' => 'shared',
 80+ 'directory' => $wgSharedUploadDirectory,
 81+ 'url' => $wgSharedUploadPath,
 82+ 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
 83+ 'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
 84+ 'transformVia404' => !$wgGenerateThumbnailOnParse,
 85+ 'dbType' => $wgDBtype,
 86+ 'dbServer' => $wgDBserver,
 87+ 'dbUser' => $wgDBuser,
 88+ 'dbPassword' => $wgDBpassword,
 89+ 'dbName' => $wgSharedUploadDBname,
 90+ 'dbFlags' => DBO_DEFAULT,
 91+ 'tablePrefix' => $wgSharedUploadDBprefix,
 92+ 'hasSharedCache' => $wgCacheSharedUploads,
 93+ 'descBaseUrl' => $wgRepositoryBaseUrl,
 94+ 'fetchDescription' => $wgFetchCommonsDescriptions,
 95+ );
 96+ } else {
 97+ $wgForeignFileRepos[] = array(
 98+ 'class' => 'FSRepo',
 99+ 'name' => 'shared',
 100+ 'directory' => $wgSharedUploadDirectory,
 101+ 'url' => $wgSharedUploadPath,
 102+ 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
 103+ 'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
 104+ 'transformVia404' => !$wgGenerateThumbnailOnParse,
 105+ 'descBaseUrl' => $wgRepositoryBaseUrl,
 106+ 'fetchDescription' => $wgFetchCommonsDescriptions,
 107+ );
 108+ }
 109+}
 110+
58111 require_once( "$IP/includes/AutoLoader.php" );
59112
60113 wfProfileIn( $fname.'-exception' );
Index: branches/phase3_rev_deleted/includes/QueryPage.php
@@ -332,6 +332,8 @@
333333 $num = $dbr->numRows($res);
334334
335335 $this->preprocessResults( $dbr, $res );
 336+
 337+ $wgOut->addHtml( XML::openElement( 'div', array('class' => 'mw-spcontent') ) );
336338
337339 # Top header and navigation
338340 if( $shownavigation ) {
@@ -346,6 +348,7 @@
347349 # No results to show, so don't bother with "showing X of Y" etc.
348350 # -- just let the user know and give up now
349351 $wgOut->addHtml( '<p>' . wfMsgHtml( 'specialpage-empty' ) . '</p>' );
 352+ $wgOut->addHtml( XML::closeElement( 'div' ) );
350353 return;
351354 }
352355 }
@@ -364,6 +367,8 @@
365368 if( $shownavigation ) {
366369 $wgOut->addHtml( '<p>' . $paging . '</p>' );
367370 }
 371+
 372+ $wgOut->addHtml( XML::closeElement( 'div' ) );
368373
369374 return $num;
370375 }
@@ -427,11 +432,11 @@
428433 }
429434
430435 function openList( $offset ) {
431 - return "<ol start='" . ( $offset + 1 ) . "' class='special'>";
 436+ return "\n<ol start='" . ( $offset + 1 ) . "' class='special'>\n";
432437 }
433438
434439 function closeList() {
435 - return '</ol>';
 440+ return "</ol>\n";
436441 }
437442
438443 /**
Index: branches/phase3_rev_deleted/includes/SpecialUndelete.php
@@ -139,10 +139,10 @@
140140 }
141141
142142 function getRevisionConds( $timestamp, $id ) {
143 - if ( $id ) {
 143+ if( $id ) {
144144 $id = intval($id);
145145 return "ar_rev_id=$id";
146 - } else if ( $timestamp ) {
 146+ } else if( $timestamp ) {
147147 return "ar_timestamp=$timestamp";
148148 } else {
149149 return 'ar_rev_id=0';
@@ -277,7 +277,7 @@
278278 }
279279
280280 if( $restoreFiles && $filetimestamp >= 0 && $this->title->getNamespace() == NS_IMAGE ) {
281 - $img = new Image( $this->title );
 281+ $img = wfLocalFile( $this->title );
282282 $filesRestored = $img->restore( $filetimestamp, $Unsuppress );
283283 } else {
284284 $filesRestored = 0;
@@ -349,7 +349,7 @@
350350 array( 'rev_page' => $pageId ),
351351 __METHOD__ );
352352
353 - if ( $row = $dbw->fetchObject($result) ) {
 353+ if( $row = $dbw->fetchObject($result) ) {
354354 $previousTimestamp = $row->latest;
355355 $previousCreated = $row->created;
356356 } else {
@@ -396,7 +396,7 @@
397397 $ret = $dbw->resultObject( $result );
398398
399399 $rev_count = $dbw->numRows( $result );
400 - if ( $rev_count ) {
 400+ if( $rev_count ) {
401401 # We need to seek around as just using DESC in the ORDER BY
402402 # would leave the revisions inserted in the wrong order
403403 $first = $ret->fetchObject();
@@ -509,8 +509,7 @@
510510 $this->mDiff = $request->getVal( 'diff' );
511511 $this->mOldid = $request->getVal( 'oldid' );
512512
513 - $posted = $request->wasPosted() &&
514 - $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
 513+ $posted = $request->wasPosted() && $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
515514 $this->mRestore = $request->getCheck( 'restore' ) && $posted;
516515 $this->mPreview = $request->getCheck( 'preview' ) && $posted;
517516 $this->mComment = $request->getText( 'wpComment' );
@@ -520,21 +519,21 @@
521520 $this->mTarget = $par;
522521 $_GET['target'] = $par; // hack for Pager
523522 }
524 - if ( $wgUser->isAllowed( 'delete' ) && !$wgUser->isBlocked() ) {
 523+ if( $wgUser->isAllowed( 'delete' ) && !$wgUser->isBlocked() ) {
525524 $this->mAllowed = true;
526525 } else {
527526 $this->mAllowed = false;
528527 $this->mTimestamp = '';
529528 $this->mRestore = false;
530529 }
531 - if ( $this->mTarget !== "" ) {
 530+ if( $this->mTarget !== "" ) {
532531 $this->mTargetObj = Title::newFromURL( $this->mTarget );
533532 } else {
534533 $this->mTargetObj = NULL;
535534 }
536535 if( $this->mRestore ) {
537 - $this->mFileTimestamp = $request->getVal('imgrestorepoint');
538 - $this->mPageTimestamp = $request->getVal('restorepoint');
 536+ $this->mFileTimestamp = $request->getInt('imgrestorepoint');
 537+ $this->mPageTimestamp = $request->getInt('restorepoint');
539538 }
540539 $this->preCacheMessages();
541540 }
@@ -554,7 +553,7 @@
555554
556555 function execute() {
557556 global $wgOut, $wgUser;
558 - if ( $this->mAllowed ) {
 557+ if( $this->mAllowed ) {
559558 $wgOut->setPagetitle( wfMsgHtml( "undeletepage" ) );
560559 } else {
561560 $wgOut->setPagetitle( wfMsgHtml( "viewdeletedpage" ) );
@@ -562,7 +561,7 @@
563562
564563 if( is_null( $this->mTargetObj ) ) {
565564 # Not all users can just browse every deleted page from the list
566 - if ( $wgUser->isAllowed( 'browsearchive' ) ) {
 565+ if( $wgUser->isAllowed( 'browsearchive' ) ) {
567566 $this->showSearchForm();
568567
569568 # List undeletable articles
@@ -579,13 +578,13 @@
580579 return $this->showRevision( $this->mTimestamp );
581580 }
582581
583 - if ( $this->mDiff && $this->mOldid )
 582+ if( $this->mDiff && $this->mOldid )
584583 return $this->showDiff( $this->mDiff, $this->mOldid );
585584
586585 if( $this->mFile !== null ) {
587586 $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile );
588587 // Check if user is allowed to see this file
589 - if ( !$file->userCan( Image::DELETED_FILE ) ) {
 588+ if( !$file->userCan( File::DELETED_FILE ) ) {
590589 $wgOut->permissionRequired( 'hiderevision' );
591590 return false;
592591 } else {
@@ -727,7 +726,7 @@
728727 private function showDiff( $newid, $oldid ) {
729728 global $wgOut, $wgUser, $wgLang;
730729
731 - if ( is_null($this->mTargetObj) )
 730+ if( is_null($this->mTargetObj) )
732731 return;
733732 $skin = $wgUser->getSkin();
734733
@@ -735,7 +734,7 @@
736735 $oldRev = $archive->getRevision( null, $oldid );
737736 $newRev = $archive->getRevision( null, $newid );
738737
739 - if ( !$oldRev || !$newRev )
 738+ if( !$oldRev || !$newRev )
740739 return;
741740
742741 $oldTitle = $this->mTargetObj->getPrefixedText();
@@ -743,12 +742,12 @@
744743
745744 $oldminor = $newminor = '';
746745
747 - if ($oldRev->mMinorEdit == 1) {
 746+ if($oldRev->mMinorEdit == 1) {
748747 $oldminor = wfElement( 'span', array( 'class' => 'minor' ),
749748 wfMsg( 'minoreditletter') ) . ' ';
750749 }
751750
752 - if ($newRev->mMinorEdit == 1) {
 751+ if($newRev->mMinorEdit == 1) {
753752 $newminor = wfElement( 'span', array( 'class' => 'minor' ),
754753 wfMsg( 'minoreditletter') ) . ' ';
755754 }
@@ -807,7 +806,7 @@
808807 global $wgLang, $wgUser, $wgOut;
809808
810809 $this->sk = $wgUser->getSkin();
811 - if ( $this->mAllowed ) {
 810+ if( $this->mAllowed ) {
812811 $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
813812 } else {
814813 $wgOut->setPagetitle( wfMsg( 'viewdeletedpage' ) );
@@ -815,7 +814,7 @@
816815
817816 $archive = new PageArchive( $this->mTargetObj );
818817
819 - if ( $this->mAllowed ) {
 818+ if( $this->mAllowed ) {
820819 $wgOut->addWikiText( '<p>' . wfMsgHtml( "undeletehistory" ) . '</p>' );
821820 $wgOut->addHtml( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' );
822821 } else {
@@ -840,7 +839,7 @@
841840 $files->seek( 0 );
842841 }
843842
844 - if ( $this->mAllowed ) {
 843+ if( $this->mAllowed ) {
845844 $titleObj = SpecialPage::getTitleFor( "Undelete" );
846845 $action = $titleObj->getLocalURL( "action=submit" );
847846 # Start the form here
@@ -857,7 +856,7 @@
858857 'type' => 'delete' ) ) ) );
859858 $logViewer->showList( $wgOut );
860859 # Show relevant lines from the oversight log if user is allowed to see it:
861 - if ( $wgUser->isAllowed( 'oversight' ) ) {
 860+ if( $wgUser->isAllowed( 'oversight' ) ) {
862861 $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'oversight' ) ) . "</h2>\n" );
863862 $logViewer = new LogViewer(
864863 new LogReader(
@@ -873,7 +872,7 @@
874873 $table .= '<td colspan="2">' . wfMsgWikiHtml( 'undeleteextrahelp' ) . '</td></tr><tr>';
875874 $table .= '<td align="right"><strong>' . wfMsgHtml( 'undeletecomment' ) . '</strong></td>';
876875 $table .= '<td>' . wfInput( 'wpComment', 50, $this->mComment ) . '</td>';
877 - if ( $wgUser->isAllowed( 'oversight' ) ) {
 876+ if( $wgUser->isAllowed( 'oversight' ) ) {
878877 $table .= '</tr><tr><td>&nbsp;</td><td>';
879878 $table .= Xml::checkLabel( wfMsg( 'revdelete-unsuppress' ), 'wpUnsuppress', 'wpUnsuppress', false, array( 'tabindex' => '2' ) );
880879 }
@@ -905,7 +904,7 @@
906905 $wgOut->addHTML( "<li>" . wfRadio( "imgrestorepoint", -1, false ) . " " . wfMsgHtml('restorenone') . "</li>" );
907906 while( $row = $files->fetchObject() ) {
908907 $ts = wfTimestamp( TS_MW, $row->fa_timestamp );
909 - if ( $this->mAllowed && $row->fa_storage_key ) {
 908+ if( $this->mAllowed && $row->fa_storage_key ) {
910909 $checkBox = wfRadio( "imgrestorepoint", $ts, false );
911910 $key = urlencode( $row->fa_storage_key );
912911 $target = urlencode( $this->mTarget );
@@ -926,7 +925,7 @@
927926 $rd='';
928927 if( $wgUser->isAllowed( 'deleterevision' ) ) {
929928 $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
930 - if( !$this->userCan( $row, Image::DELETED_RESTRICTED ) ) {
 929+ if( !$this->userCan( $row, File::DELETED_RESTRICTED ) ) {
931930 // If revision was hidden from sysops
932931 $del = $this->message['rev-delundel'];
933932 } else {
@@ -935,7 +934,7 @@
936935 'target=' . urlencode( $this->mTarget ) .
937936 '&fileid=' . urlencode( $row->fa_id ) );
938937 // Bolden oversighted content
939 - if( $this->isDeleted( $row, Image::DELETED_RESTRICTED ) )
 938+ if( $this->isDeleted( $row, File::DELETED_RESTRICTED ) )
940939 $del = "<strong>$del</strong>";
941940 }
942941 $rd = "<tt>(<small>$del</small>)</tt>";
@@ -946,7 +945,7 @@
947946 $wgOut->addHTML( "</ul>" );
948947 }
949948
950 - if ( $this->mAllowed ) {
 949+ if( $this->mAllowed ) {
951950 # Slip in the hidden controls here
952951 $misc = wfHidden( 'target', $this->mTarget );
953952 $misc .= wfHidden( 'wpEditToken', $wgUser->editToken() );
@@ -962,15 +961,15 @@
963962 $stxt = '';
964963 $last = $this->message['last'];
965964 // We don't handle top edits with rev_deleted
966 - if ( $this->mAllowed ) {
 965+ if( $this->mAllowed ) {
967966 $ts = wfTimestamp( TS_MW, $row->ar_timestamp );
968967 $checkBox = wfRadio( "restorepoint", $ts, false );
969968 $titleObj = SpecialPage::getTitleFor( "Undelete" );
970969 $pageLink = $this->getPageLink( $row, $titleObj, $ts, $this->mTarget );
971970 # Last link
972 - if ( !$this->userCan( $row, Revision::DELETED_TEXT ) )
 971+ if( !$this->userCan( $row, Revision::DELETED_TEXT ) )
973972 $last = $this->message['last'];
974 - else if ( isset($this->prevId[$row->ar_rev_id]) )
 973+ else if( isset($this->prevId[$row->ar_rev_id]) )
975974 $last = $this->sk->makeKnownLinkObj( $titleObj, $this->message['last'], "target=" . $this->mTarget .
976975 "&diff=" . $row->ar_rev_id . "&oldid=" . $this->prevId[$row->ar_rev_id] );
977976 } else {
@@ -979,8 +978,8 @@
980979 }
981980
982981 $userLink = $this->getUser( $row );
983 - if (!is_null($size = $row->ar_len)) {
984 - if ($size == 0)
 982+ if(!is_null($size = $row->ar_len)) {
 983+ if($size == 0)
985984 $stxt = wfMsgHtml('historyempty');
986985 else
987986 $stxt = wfMsgHtml('historysize', $wgLang->formatNum( $size ) );
@@ -1018,11 +1017,11 @@
10191018 function getPageLink( $row, $titleObj, $ts, $target ) {
10201019 global $wgLang;
10211020
1022 - if ( !$this->userCan($row, Revision::DELETED_TEXT) ) {
 1021+ if( !$this->userCan($row, Revision::DELETED_TEXT) ) {
10231022 return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>';
10241023 } else {
10251024 $link = $this->sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), "target=$target&timestamp=$ts" );
1026 - if ( $this->isDeleted($row, Revision::DELETED_TEXT) )
 1025+ if( $this->isDeleted($row, Revision::DELETED_TEXT) )
10271026 $link = '<span class="history-deleted">' . $link . '</span>';
10281027 return $link;
10291028 }
@@ -1035,11 +1034,11 @@
10361035 function getFileLink( $row, $titleObj, $ts, $target, $key ) {
10371036 global $wgLang;
10381037
1039 - if ( !$this->userCan($row, Image::DELETED_FILE) ) {
 1038+ if( !$this->userCan($row, File::DELETED_FILE) ) {
10401039 return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>';
10411040 } else {
10421041 $link = $this->sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), "target=$target&file=$key" );
1043 - if ( $this->isDeleted($row, Image::DELETED_FILE) )
 1042+ if( $this->isDeleted($row, File::DELETED_FILE) )
10441043 $link = '<span class="history-deleted">' . $link . '</span>';
10451044 return $link;
10461045 }
@@ -1050,11 +1049,11 @@
10511050 * @return string
10521051 */
10531052 function getUser( $row ) {
1054 - if ( !$this->userCan($row, Revision::DELETED_USER) ) {
 1053+ if( !$this->userCan($row, Revision::DELETED_USER) ) {
10551054 return '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
10561055 } else {
10571056 $link = $this->sk->userLink( $row->ar_user, $row->ar_user_text ) . $this->sk->userToolLinks( $row->ar_user, $row->ar_user_text );
1058 - if ( $this->isDeleted($row, Revision::DELETED_USER) )
 1057+ if( $this->isDeleted($row, Revision::DELETED_USER) )
10591058 $link = '<span class="history-deleted">' . $link . '</span>';
10601059 return $link;
10611060 }
@@ -1065,11 +1064,11 @@
10661065 * @return string
10671066 */
10681067 function getFileUser( $row ) {
1069 - if ( !$this->userCan($row, Image::DELETED_USER) ) {
 1068+ if( !$this->userCan($row, File::DELETED_USER) ) {
10701069 return '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
10711070 } else {
10721071 $link = $this->sk->userLink( $row->fa_user, $row->fa_user_text ) . $this->sk->userToolLinks( $row->fa_user, $row->fa_user_text );
1073 - if ( $this->isDeleted($row, Image::DELETED_USER) )
 1072+ if( $this->isDeleted($row, File::DELETED_USER) )
10741073 $link = '<span class="history-deleted">' . $link . '</span>';
10751074 return $link;
10761075 }
@@ -1080,11 +1079,11 @@
10811080 * @return string
10821081 */
10831082 function getComment( $row ) {
1084 - if ( !$this->userCan($row, Revision::DELETED_COMMENT) ) {
 1083+ if( !$this->userCan($row, Revision::DELETED_COMMENT) ) {
10851084 return '<span class="history-deleted"><span class="comment">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>';
10861085 } else {
10871086 $link = $this->sk->commentBlock( $row->ar_comment );
1088 - if ( $this->isDeleted($row, Revision::DELETED_COMMENT) )
 1087+ if( $this->isDeleted($row, Revision::DELETED_COMMENT) )
10891088 $link = '<span class="history-deleted">' . $link . '</span>';
10901089 return $link;
10911090 }
@@ -1095,11 +1094,11 @@
10961095 * @return string
10971096 */
10981097 function getFileComment( $row ) {
1099 - if ( !$this->userCan($row, Image::DELETED_COMMENT) ) {
 1098+ if( !$this->userCan($row, File::DELETED_COMMENT) ) {
11001099 return '<span class="history-deleted"><span class="comment">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>';
11011100 } else {
11021101 $link = $this->sk->commentBlock( $row->fa_description );
1103 - if ( $this->isDeleted($row, Image::DELETED_COMMENT) )
 1102+ if( $this->isDeleted($row, File::DELETED_COMMENT) )
11041103 $link = '<span class="history-deleted">' . $link . '</span>';
11051104 return $link;
11061105 }
@@ -1111,10 +1110,10 @@
11121111 * @return bool
11131112 */
11141113 function isDeleted( $row, $field ) {
1115 - if ( isset($row->ar_deleted) )
 1114+ if( isset($row->ar_deleted) )
11161115 // page revisions
11171116 return ($row->ar_deleted & $field) == $field;
1118 - else if ( isset($row->fa_deleted) )
 1117+ else if( isset($row->fa_deleted) )
11191118 // files
11201119 return ($row->fa_deleted & $field) == $field;
11211120 return false;
@@ -1138,7 +1137,7 @@
11391138 return $wgUser->isAllowed( $permission );
11401139 } else if( isset($row->fa_deleted) && ($row->fa_deleted & $field) == $field ) {
11411140 // files
1142 - $permission = ( $row->fa_deleted & Image::DELETED_RESTRICTED ) == Image::DELETED_RESTRICTED
 1141+ $permission = ( $row->fa_deleted & File::DELETED_RESTRICTED ) == File::DELETED_RESTRICTED
11431142 ? 'hiderevision'
11441143 : 'deleterevision';
11451144 wfDebug( "Checking for $permission due to $field match on $row->fa_deleted\n" );
@@ -1197,9 +1196,9 @@
11981197 $rev_id = isset($rev_id) ? $rev_id : $row->ar_rev_id;
11991198 $batch->addObj( Title::makeTitleSafe( NS_USER, $row->ar_user_text ) );
12001199 $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ar_user_text ) );
1201 - if ( $rev_id > $row->ar_rev_id )
 1200+ if( $rev_id > $row->ar_rev_id )
12021201 $this->mForm->prevId[$rev_id] = $row->ar_rev_id;
1203 - else if ( $rev_id < $row->ar_rev_id )
 1202+ else if( $rev_id < $row->ar_rev_id )
12041203 $this->mForm->prevId[$row->ar_rev_id] = $rev_id;
12051204
12061205 $rev_id = $row->ar_rev_id;
Index: branches/phase3_rev_deleted/includes/SpecialUpload.php
@@ -27,6 +27,7 @@
2828 var $mUploadCopyStatus, $mUploadSource, $mReUpload, $mAction, $mUpload;
2929 var $mOname, $mSessionKey, $mStashed, $mDestFile, $mRemoveTempFile, $mSourceType;
3030 var $mUploadTempFileSize = 0;
 31+ var $mImage;
3132
3233 # Placeholders for text injection by hooks (must be HTML)
3334 # extensions should take care to _append_ to the present value
@@ -412,13 +413,13 @@
413414
414415 global $wgUser;
415416 $sk = $wgUser->getSkin();
416 - $image = new Image( $nt );
 417+ $image = wfLocalFile( $nt );
417418
418419 // Check for uppercase extension. We allow these filenames but check if an image
419420 // with lowercase extension exists already
420421 if ( $finalExt != strtolower( $finalExt ) ) {
421422 $nt_lc = Title::newFromText( $partname . '.' . strtolower( $finalExt ) );
422 - $image_lc = new Image( $nt_lc );
 423+ $image_lc = wfLocalFile( $nt_lc );
423424 }
424425
425426 if( $image->exists() ) {
@@ -452,7 +453,7 @@
453454 } elseif ( ( substr( $partname , 3, 3 ) == 'px-' || substr( $partname , 2, 3 ) == 'px-' ) && ereg( "[0-9]{2}" , substr( $partname , 0, 2) ) ) {
454455 # Check for filenames like 50px- or 180px-, these are mostly thumbnails
455456 $nt_thb = Title::newFromText( substr( $partname , strpos( $partname , '-' ) +1 ) . '.' . $finalExt );
456 - $image_thb = new Image( $nt_thb );
 457+ $image_thb = wfLocalFile( $nt_thb );
457458 if ($image_thb->exists() ) {
458459 # Check if an image without leading '180px-' (or similiar) exists
459460 $dlink = $sk->makeKnownLinkObj( $nt_thb);
@@ -500,8 +501,8 @@
501502 * Update the upload log and create the description page
502503 * if it's a new file.
503504 */
504 - $img = Image::newFromName( $this->mUploadSaveName );
505 - $success = $img->recordUpload( $this->mUploadOldVersion,
 505+ $this->mImage = wfLocalFile( $this->mUploadSaveName );
 506+ $success = $this->mImage->recordUpload( $this->mUploadOldVersion,
506507 $this->mUploadDescription,
507508 $this->mLicense,
508509 $this->mUploadCopyStatus,
@@ -512,7 +513,7 @@
513514 $this->showSuccess();
514515 wfRunHooks( 'UploadComplete', array( &$img ) );
515516 } else {
516 - // Image::recordUpload() fails if the image went missing, which is
 517+ // File::recordUpload() fails if the image went missing, which is
517518 // unlikely, hence the lack of a specialised message
518519 $wgOut->showFileNotFoundError( $this->mUploadSaveName );
519520 }
@@ -534,48 +535,13 @@
535536 function saveUploadedFile( $saveName, $tempName, $useRename = false ) {
536537 global $wgOut, $wgAllowCopyUploads;
537538
538 - if ( !$useRename AND $wgAllowCopyUploads AND $this->mSourceType == 'web' ) $useRename = true;
539 -
540 - $fname= "SpecialUpload::saveUploadedFile";
541 -
542 - $dest = wfImageDir( $saveName );
543 - $archive = wfImageArchiveDir( $saveName );
544 - if ( !is_dir( $dest ) ) wfMkdirParents( $dest );
545 - if ( !is_dir( $archive ) ) wfMkdirParents( $archive );
546 -
547 - $this->mSavedFile = "{$dest}/{$saveName}";
548 -
549 - if( is_file( $this->mSavedFile ) ) {
550 - $this->mUploadOldVersion = gmdate( 'YmdHis' ) . "!{$saveName}";
551 - wfSuppressWarnings();
552 - $success = rename( $this->mSavedFile, "${archive}/{$this->mUploadOldVersion}" );
553 - wfRestoreWarnings();
554 -
555 - if( ! $success ) {
556 - $wgOut->showFileRenameError( $this->mSavedFile,
557 - "${archive}/{$this->mUploadOldVersion}" );
558 - return false;
559 - }
560 - else wfDebug("$fname: moved file ".$this->mSavedFile." to ${archive}/{$this->mUploadOldVersion}\n");
561 - }
562 - else {
563 - $this->mUploadOldVersion = '';
564 - }
565 -
566 - wfSuppressWarnings();
567 - $success = $useRename
568 - ? rename( $tempName, $this->mSavedFile )
569 - : move_uploaded_file( $tempName, $this->mSavedFile );
570 - wfRestoreWarnings();
571 -
572 - if( ! $success ) {
573 - $wgOut->showFileCopyError( $tempName, $this->mSavedFile );
 539+ $image = wfLocalFile( $saveName );
 540+ $archiveName = $image->publish( $tempName, File::DELETE_SOURCE );
 541+ if ( WikiError::isError( $archiveName ) ) {
 542+ $this->showError( $archiveName );
574543 return false;
575 - } else {
576 - wfDebug("$fname: wrote tempfile $tempName to ".$this->mSavedFile."\n");
577544 }
578 -
579 - chmod( $this->mSavedFile, 0644 );
 545+ $this->mUploadOldVersion = $archiveName;
580546 return true;
581547 }
582548
@@ -593,19 +559,14 @@
594560 */
595561 function saveTempUploadedFile( $saveName, $tempName ) {
596562 global $wgOut;
597 - $archive = wfImageArchiveDir( $saveName, 'temp' );
598 - if ( !is_dir ( $archive ) ) wfMkdirParents( $archive );
599 - $stash = $archive . '/' . gmdate( "YmdHis" ) . '!' . $saveName;
600 -
601 - $success = $this->mRemoveTempFile
602 - ? rename( $tempName, $stash )
603 - : move_uploaded_file( $tempName, $stash );
604 - if ( !$success ) {
605 - $wgOut->showFileCopyError( $tempName, $stash );
 563+ $repo = RepoGroup::singleton()->getLocalRepo();
 564+ $result = $repo->storeTemp( $saveName, $tempName );
 565+ if ( WikiError::isError( $result ) ) {
 566+ $this->showError( $result );
606567 return false;
 568+ } else {
 569+ return $result;
607570 }
608 -
609 - return $stash;
610571 }
611572
612573 /**
@@ -662,7 +623,7 @@
663624 global $wgUser, $wgOut, $wgContLang;
664625
665626 $sk = $wgUser->getSkin();
666 - $ilink = $sk->makeMediaLink( $this->mUploadSaveName, Image::imageUrl( $this->mUploadSaveName ) );
 627+ $ilink = $sk->makeMediaLinkObj( $this->mImage->getTitle() );
667628 $dname = $wgContLang->getNsText( NS_IMAGE ) . ':'.$this->mUploadSaveName;
668629 $dlink = $sk->makeKnownLink( $dname, $dname );
669630
@@ -1274,15 +1235,10 @@
12751236 * @access private
12761237 */
12771238 function checkOverwrite( $name ) {
1278 - $img = Image::newFromName( $name );
1279 - if( is_null( $img ) ) {
1280 - // Uh... this shouldn't happen ;)
1281 - // But if it does, fall through to previous behavior
1282 - return false;
1283 - }
 1239+ $img = wfFindFile( $name );
12841240
12851241 $error = '';
1286 - if( $img->exists() ) {
 1242+ if( $img ) {
12871243 global $wgUser, $wgOut;
12881244 if( $img->isLocal() ) {
12891245 if( !self::userCanReUpload( $wgUser, $img->name ) ) {
@@ -1328,5 +1284,17 @@
13291285
13301286 return $user->getID() == $row->img_user;
13311287 }
 1288+
 1289+ /**
 1290+ * Display an error from a wikitext-formatted WikiError object
 1291+ */
 1292+ function showError( WikiError $error ) {
 1293+ global $wgOut;
 1294+ $wgOut->setPageTitle( wfMsg( "internalerror" ) );
 1295+ $wgOut->setRobotpolicy( "noindex,nofollow" );
 1296+ $wgOut->setArticleRelated( false );
 1297+ $wgOut->enableClientCache( false );
 1298+ $wgOut->addWikiText( $error->getMessage() );
 1299+ }
13321300 }
13331301 ?>
Index: branches/phase3_rev_deleted/includes/AutoLoader.php
@@ -96,9 +96,6 @@
9797 'HTMLCacheUpdateJob' => 'includes/HTMLCacheUpdate.php',
9898 'EnotifNotifyJob' => 'includes/JobQueue.php',
9999 'Http' => 'includes/HttpFunctions.php',
100 - 'Image' => 'includes/Image.php',
101 - 'OldImage' => 'includes/Image.php',
102 - 'ArchivedFile' => 'includes/Image.php',
103100 'IP' => 'includes/IP.php',
104101 'ThumbnailImage' => 'includes/Image.php',
105102 'ImageGallery' => 'includes/ImageGallery.php',
@@ -251,6 +248,19 @@
252249 'memcached' => 'includes/memcached-client.php',
253250 'EmaillingJob' => 'includes/JobQueue.php',
254251
 252+ # filerepo
 253+ 'ArchivedFile' => 'includes/filerepo/ArchivedFile.php',
 254+ 'File' => 'includes/filerepo/File.php',
 255+ 'ForeignDBFile' => 'includes/filerepo/ForeignDBFile.php',
 256+ 'ForeignDBRepo' => 'includes/filerepo/ForeignDBRepo.php',
 257+ 'FSRepo' => 'includes/filerepo/FSRepo.php',
 258+ 'Image' => 'includes/filerepo/LocalFile.php',
 259+ 'LocalFile' => 'includes/filerepo/LocalFile.php',
 260+ 'LocalRepo' => 'includes/filerepo/LocalRepo.php',
 261+ 'OldLocalFile' => 'includes/filerepo/OldLocalFile.php',
 262+ 'RepoGroup' => 'includes/filerepo/RepoGroup.php',
 263+ 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php',
 264+
255265 # Media
256266 'BitmapHandler' => 'includes/media/Bitmap.php',
257267 'BmpHandler' => 'includes/media/BMP.php',
Index: branches/phase3_rev_deleted/includes/Skin.php
@@ -740,8 +740,8 @@
741741 if ( $wgOut->isArticleRelated() ) {
742742 if ( $wgTitle->getNamespace() == NS_IMAGE ) {
743743 $name = $wgTitle->getDBkey();
744 - $image = new Image( $wgTitle );
745 - if( $image->exists() ) {
 744+ $image = wfFindFile( $wgTitle );
 745+ if( $image ) {
746746 $link = htmlspecialchars( $image->getURL() );
747747 $style = $this->getInternalLinkAttributes( $link, $name );
748748 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
Index: branches/phase3_rev_deleted/includes/DefaultSettings.php
@@ -190,6 +190,49 @@
191191 $wgFileStore['hidden']['url'] = null; // Private
192192 $wgFileStore['hidden']['hash'] = 3; // 3-level subdirectory split
193193
 194+/**#@+
 195+ * File repository structures
 196+ *
 197+ * $wgLocalFileRepo is a single repository structure, and $wgForeignFileRepo is
 198+ * a an array of such structures. Each repository structure is an associative
 199+ * array of properties configuring the repository.
 200+ *
 201+ * Properties required for all repos:
 202+ * class The class name for the repository. May come from the core or an extension.
 203+ * The core repository classes are LocalRepo, ForeignDBRepo, FSRepo.
 204+ *
 205+ * name A unique name for the repository.
 206+ *
 207+ * For all core repos:
 208+ * url Base public URL
 209+ * hashLevels The number of directory levels for hash-based division of files
 210+ * thumbScriptUrl The URL for thumb.php (optional, not recommended)
 211+ * transformVia404 Whether to skip media file transformation on parse and rely on a 404
 212+ * handler instead.
 213+ *
 214+ * These settings describe a foreign MediaWiki installation. They are optional, and will be ignored
 215+ * for local repositories:
 216+ * descBaseUrl URL of image description pages, e.g. http://en.wikipedia.org/wiki/Image:
 217+ * scriptDirUrl URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g.
 218+ * http://en.wikipedia.org/w
 219+ *
 220+ * articleUrl Equivalent to $wgArticlePath, e.g. http://en.wikipedia.org/wiki/$1
 221+ * fetchDescription Fetch the text of the remote file description page. Equivalent to
 222+ * $wgFetchCommonsDescriptions.
 223+ *
 224+ * ForeignDBRepo:
 225+ * dbType, dbServer, dbUser, dbPassword, dbName, dbFlags
 226+ * equivalent to the corresponding member of $wgDBservers
 227+ * tablePrefix Table prefix, the foreign wiki's $wgDBprefix
 228+ * hasSharedCache True if the wiki's shared cache is accessible via the local $wgMemc
 229+ *
 230+ * The default is to initialise these arrays from the MW<1.11 backwards compatible settings:
 231+ * $wgUploadPath, $wgThumbnailScriptPath, $wgSharedUploadDirectory, etc.
 232+ */
 233+$wgLocalFileRepo = false;
 234+$wgForeignFileRepos = array();
 235+/**#@-*/
 236+
194237 /**
195238 * Allowed title characters -- regex character class
196239 * Don't change this unless you know what you're doing
@@ -361,6 +404,10 @@
362405 * no file of the given name is found in the local repository (for [[Image:..]],
363406 * [[Media:..]] links). Thumbnails will also be looked for and generated in this
364407 * directory.
 408+ *
 409+ * Note that these configuration settings can now be defined on a per-
 410+ * repository basis for an arbitrary number of file repositories, using the
 411+ * $wgForeignFileRepos variable.
365412 */
366413 $wgUseSharedUploads = false;
367414 /** Full path on the web server where shared uploads can be found */
@@ -1136,7 +1183,7 @@
11371184 * to ensure that client-side caches don't keep obsolete copies of global
11381185 * styles.
11391186 */
1140 -$wgStyleVersion = '72';
 1187+$wgStyleVersion = '73';
11411188
11421189
11431190 # Server-side caching:
@@ -2019,7 +2066,13 @@
20202067 * @link http://en.wikipedia.org/w/index.php?title=User%3A%C6var_Arnfj%F6r%F0_Bjarmason%2Ftestme&diff=12356041&oldid=12355864
20212068 * @link http://en.wikipedia.org/wiki/Template%3AOS9
20222069 */
2023 - '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/'
 2070+ '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/',
 2071+
 2072+ /**
 2073+ * Google wireless transcoder, seems to eat a lot of chars alive
 2074+ * http://it.wikipedia.org/w/index.php?title=Luciano_Ligabue&diff=prev&oldid=8857361
 2075+ */
 2076+ '/^Mozilla\/4\.0 \(compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;\)/'
20242077 );
20252078
20262079 /**
@@ -2594,10 +2647,10 @@
25952648
25962649 /**
25972650 * If lag is higher than $wgSlaveLagWarning, show a warning in some special
2598 - * pages (like watchlist). If the lag is higher than $wgSlaveLagOhNo, show a
2599 - * more obvious warning.
 2651+ * pages (like watchlist). If the lag is higher than $wgSlaveLagCritical,
 2652+ * show a more obvious warning.
26002653 */
26012654 $wgSlaveLagWarning = 10;
2602 -$wgSlaveLagOhNo = 30;
 2655+$wgSlaveLagCritical = 30;
26032656
26042657 ?>
Index: branches/phase3_rev_deleted/includes/ImageQueryPage.php
@@ -30,8 +30,8 @@
3131 # $num [should update this to use a Pager]
3232 for( $i = 0; $i < $num && $row = $dbr->fetchObject( $res ); $i++ ) {
3333 $image = $this->prepareImage( $row );
34 - if( $image instanceof Image ) {
35 - $gallery->add( $image, $this->getCellHtml( $row ) );
 34+ if( $image ) {
 35+ $gallery->add( $image->getTitle(), $this->getCellHtml( $row ) );
3636 }
3737 }
3838
@@ -49,7 +49,7 @@
5050 $namespace = isset( $row->namespace ) ? $row->namespace : NS_IMAGE;
5151 $title = Title::makeTitleSafe( $namespace, $row->title );
5252 return ( $title instanceof Title && $title->getNamespace() == NS_IMAGE )
53 - ? new Image( $title )
 53+ ? wfFindFile( $title )
5454 : null;
5555 }
5656
Index: branches/phase3_rev_deleted/includes/SpecialLog.php
@@ -712,7 +712,7 @@
713713 // Restricted types
714714 if ( isset($wgLogRestrictions[$type]) ) {
715715 if ( $wgUser->isAllowed( $wgLogRestrictions[$type] ) ) {
716 - $out .= Xml::option( $text, $type, $selected ) . "\n";
 716+ $out .= Xml::option( $text, $type, $selected ) . "\n";
717717 }
718718 } else {
719719 $out .= Xml::option( $text, $type, $selected ) . "\n";
Index: branches/phase3_rev_deleted/includes/StreamFile.php
@@ -31,6 +31,9 @@
3232 header('Content-type: application/x-wiki');
3333 }
3434
 35+ global $wgContLanguageCode;
 36+ header( "Content-Disposition: inline;filename*=utf-8'$wgContLanguageCode'" . urlencode( basename( $fname ) ) );
 37+
3538 if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
3639 $modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
3740 $sinceTime = strtotime( $modsince );
Index: branches/phase3_rev_deleted/includes/MediaTransformOutput.php
@@ -1,7 +1,7 @@
22 <?php
33
44 /**
5 - * Base class for the output of MediaHandler::doTransform() and Image::transform().
 5+ * Base class for the output of MediaHandler::doTransform() and File::transform().
66 *
77 * @addtogroup Media
88 */
Index: branches/phase3_rev_deleted/includes/ImageGallery.php
@@ -17,6 +17,7 @@
1818 var $mImages, $mShowBytes, $mShowFilename;
1919 var $mCaption = false;
2020 var $mSkin = false;
 21+ var $mRevisionId = 0;
2122
2223 /**
2324 * Is the gallery on a wiki page (i.e. not a special page)
@@ -127,22 +128,26 @@
128129 /**
129130 * Add an image to the gallery.
130131 *
131 - * @param $image Image object that is added to the gallery
 132+ * @param $title Title object of the image that is added to the gallery
132133 * @param $html String: additional HTML text to be shown. The name and size of the image are always shown.
133134 */
134 - function add( $image, $html='' ) {
135 - $this->mImages[] = array( &$image, $html );
136 - wfDebug( "ImageGallery::add " . $image->getName() . "\n" );
 135+ function add( $title, $html='' ) {
 136+ if ( $title instanceof File ) {
 137+ // Old calling convention
 138+ $title = $title->getTitle();
 139+ }
 140+ $this->mImages[] = array( $title, $html );
 141+ wfDebug( "ImageGallery::add " . $title->getText() . "\n" );
137142 }
138143
139144 /**
140145 * Add an image at the beginning of the gallery.
141146 *
142 - * @param $image Image object that is added to the gallery
 147+ * @param $title Title object of the image that is added to the gallery
143148 * @param $html String: Additional HTML text to be shown. The name and size of the image are always shown.
144149 */
145 - function insert( $image, $html='' ) {
146 - array_unshift( $this->mImages, array( &$image, $html ) );
 150+ function insert( $title, $html='' ) {
 151+ array_unshift( $this->mImages, array( &$title, $html ) );
147152 }
148153
149154
@@ -195,12 +200,16 @@
196201 $params = array( 'width' => $this->mWidths, 'height' => $this->mHeights );
197202 $i = 0;
198203 foreach ( $this->mImages as $pair ) {
199 - $img =& $pair[0];
 204+ $nt = $pair[0];
200205 $text = $pair[1];
 206+
 207+ # Give extensions a chance to select the file revision for us
 208+ $time = false;
 209+ wfRunHooks( 'BeforeGalleryFindFile', array( &$this, &$nt, &$time ) );
201210
202 - $nt = $img->getTitle();
 211+ $img = wfFindFile( $nt, $time );
203212
204 - if( $nt->getNamespace() != NS_IMAGE ) {
 213+ if( $nt->getNamespace() != NS_IMAGE || !$img ) {
205214 # We're dealing with a non-image, spit out the name and be done with it.
206215 $thumbhtml = "\n\t\t\t".'<div style="height: '.($this->mHeights*1.25+2).'px;">'
207216 . htmlspecialchars( $nt->getText() ) . '</div>';
@@ -222,7 +231,7 @@
223232 //$ul = $sk->makeLink( $wgContLang->getNsText( Namespace::getUser() ) . ":{$ut}", $ut );
224233
225234 if( $this->mShowBytes ) {
226 - if( $img->exists() ) {
 235+ if( $img ) {
227236 $nb = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'),
228237 $wgLang->formatNum( $img->getSize() ) );
229238 } else {
Index: branches/phase3_rev_deleted/includes/SpecialNewimages.php
@@ -135,10 +135,9 @@
136136 $ut = $s->img_user_text;
137137
138138 $nt = Title::newFromText( $name, NS_IMAGE );
139 - $img = new Image( $nt );
140139 $ul = $sk->makeLinkObj( Title::makeTitle( NS_USER, $ut ), $ut );
141140
142 - $gallery->add( $img, "$ul<br />\n<i>".$wgLang->timeanddate( $s->img_timestamp, true )."</i><br />\n" );
 141+ $gallery->add( $nt, "$ul<br />\n<i>".$wgLang->timeanddate( $s->img_timestamp, true )."</i><br />\n" );
143142
144143 $timestamp = wfTimestamp( TS_MW, $s->img_timestamp );
145144 if( empty( $firstTimestamp ) ) {
Index: branches/phase3_rev_deleted/includes/Title.php
@@ -2407,13 +2407,12 @@
24082408 * Should a link should be displayed as a known link, just based on its title?
24092409 *
24102410 * Currently, a self-link with a fragment and special pages are in
2411 - * this category. Special pages never exist in the database. System
2412 - * messages that have defined default values are also always known.
 2411+ * this category. System messages that have defined default values are also
 2412+ * always known.
24132413 */
24142414 public function isAlwaysKnown() {
24152415 return ( $this->isExternal() ||
24162416 ( 0 == $this->mNamespace && "" == $this->mDbkeyform ) ||
2417 - ( NS_SPECIAL == $this->mNamespace ) ||
24182417 ( NS_MEDIAWIKI == $this->mNamespace && wfMsgWeirdKey( $this->mDbkeyform ) ) );
24192418 }
24202419
Index: branches/phase3_rev_deleted/includes/Linker.php
@@ -218,6 +218,19 @@
219219 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
220220 } else {
221221 wfProfileIn( $fname.'-immediate' );
 222+
 223+ # Handles links to special pages wich do not exist in the database:
 224+ if( $nt->getNamespace() == NS_SPECIAL ) {
 225+ if( SpecialPage::exists( $nt->getDbKey() ) ) {
 226+ $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
 227+ } else {
 228+ $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
 229+ }
 230+ wfProfileOut( $fname.'-immediate' );
 231+ wfProfileOut( $fname );
 232+ return $retVal;
 233+ }
 234+
222235 # Work out link colour immediately
223236 $aid = $nt->getArticleID() ;
224237 if ( 0 == $aid ) {
@@ -318,7 +331,9 @@
319332 $fname = 'Linker::makeBrokenLinkObj';
320333 wfProfileIn( $fname );
321334
322 - if ( '' == $query ) {
 335+ if( $nt->getNamespace() == NS_SPECIAL ) {
 336+ $q = $query;
 337+ } else if ( '' == $query ) {
323338 $q = 'action=edit';
324339 } else {
325340 $q = 'action=edit&'.$query;
@@ -412,15 +427,27 @@
413428 return $s;
414429 }
415430
416 - /** @todo document */
 431+ /** Creates the HTML source for images
 432+ * @param object $nt
 433+ * @param string $label label text
 434+ * @param string $alt alt text
 435+ * @param string $align horizontal alignment: none, left, center, right)
 436+ * @param array $params some format keywords: width, height, page, upright, upright_factor, frameless, border
 437+ * @param boolean $framed shows image in original size in a frame
 438+ * @param boolean $thumb shows image as thumbnail in a frame
 439+ * @param string $manual_thumb image name for the manual thumbnail
 440+ * @param string $valign vertical alignment: baseline, sub, super, top, text-top, middle, bottom, text-bottom
 441+ * @return string
 442+ */
417443 function makeImageLinkObj( $nt, $label, $alt, $align = '', $params = array(), $framed = false,
418 - $thumb = false, $manual_thumb = '', $valign = '', $upright = false, $upright_factor = 0, $timeframe=null )
 444+ $thumb = false, $manual_thumb = '', $valign = '', $time = false )
419445 {
420446 global $wgContLang, $wgUser, $wgThumbLimits, $wgThumbUpright;
421447
422 - $img = new Image( $nt, $timeframe );
 448+ $img = wfFindFile( $nt, $time );
423449
424 - if ( !$img->allowInlineDisplay() && $img->exists() ) {
 450+ if ( $img && !$img->allowInlineDisplay() ) {
 451+ wfDebug( __METHOD__.': '.$nt->getPrefixedDBkey()." does not allow inline display\n" );
425452 return $this->makeKnownLinkObj( $nt );
426453 }
427454
@@ -433,10 +460,9 @@
434461 $postfix = '</div>';
435462 $align = 'none';
436463 }
437 -
438 - if ( !isset( $params['width'] ) ) {
 464+ if ( $img && !isset( $params['width'] ) ) {
439465 $params['width'] = $img->getWidth( $page );
440 - if( $thumb || $framed ) {
 466+ if( $thumb || $framed || isset( $params['frameless'] ) ) {
441467 $wopt = $wgUser->getOption( 'thumbsize' );
442468
443469 if( !isset( $wgThumbLimits[$wopt] ) ) {
@@ -444,12 +470,12 @@
445471 }
446472
447473 // Reduce width for upright images when parameter 'upright' is used
448 - if ( $upright_factor == 0 ) {
449 - $upright_factor = $wgThumbUpright;
 474+ if ( !isset( $params['upright_factor'] ) || $params['upright_factor'] == 0 ) {
 475+ $params['upright_factor'] = $wgThumbUpright;
450476 }
451477 // Use width which is smaller: real image width or user preference width
452478 // For caching health: If width scaled down due to upright parameter, round to full __0 pixel to avoid the creation of a lot of odd thumbs
453 - $params['width'] = min( $params['width'], $upright ? round( $wgThumbLimits[$wopt] * $upright_factor, -1 ) : $wgThumbLimits[$wopt] );
 479+ $params['width'] = min( $params['width'], isset( $params['upright'] ) ? round( $wgThumbLimits[$wopt] * $params['upright_factor'], -1 ) : $wgThumbLimits[$wopt] );
454480 }
455481 }
456482
@@ -465,10 +491,10 @@
466492 if ( $align == '' ) {
467493 $align = $wgContLang->isRTL() ? 'left' : 'right';
468494 }
469 - return $prefix.$this->makeThumbLinkObj( $img, $label, $alt, $align, $params, $framed, $manual_thumb, $upright ).$postfix;
 495+ return $prefix.$this->makeThumbLinkObj( $nt, $img, $label, $alt, $align, $params, $framed, $manual_thumb ).$postfix;
470496 }
471497
472 - if ( $params['width'] && $img->exists() ) {
 498+ if ( $img && $params['width'] ) {
473499 # Create a resized image, without the additional thumbnail features
474500 $thumb = $img->transform( $params );
475501 } else {
@@ -485,9 +511,13 @@
486512 'alt' => $alt,
487513 'longdesc' => $u
488514 );
 515+
489516 if ( $valign ) {
490517 $imgAttribs['style'] = "vertical-align: $valign";
491518 }
 519+ if ( isset( $params['border'] ) ) {
 520+ $imgAttribs['class'] = "thumbborder";
 521+ }
492522 $linkAttribs = array(
493523 'href' => $u,
494524 'class' => 'image',
@@ -495,7 +525,7 @@
496526 );
497527
498528 if ( !$thumb ) {
499 - $s = $this->makeBrokenImageLinkObj( $img->getTitle() );
 529+ $s = $this->makeBrokenImageLinkObj( $nt );
500530 } else {
501531 $s = $thumb->toHtml( $imgAttribs, $linkAttribs );
502532 }
@@ -507,58 +537,69 @@
508538
509539 /**
510540 * Make HTML for a thumbnail including image, border and caption
511 - * $img is an Image object
 541+ * @param Title $nt
 542+ * @param Image $img Image object or false if it doesn't exist
512543 */
513 - function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manual_thumb = "", $upright = false ) {
 544+ function makeThumbLinkObj( Title $nt, $img, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manual_thumb = "" ) {
514545 global $wgStylePath, $wgContLang;
 546+ $exists = $img && $img->exists();
515547
516548 $page = isset( $params['page'] ) ? $params['page'] : false;
517549
518550 if ( empty( $params['width'] ) ) {
519551 // Reduce width for upright images when parameter 'upright' is used
520 - $params['width'] = $upright ? 130 : 180;
 552+ $params['width'] = isset( $params['upright'] ) ? 130 : 180;
521553 }
522554 $thumb = false;
523 - if ( $manual_thumb != '' ) {
524 - # Use manually specified thumbnail
525 - $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb );
526 - if( $manual_title ) {
527 - $manual_img = new Image( $manual_title );
528 - $thumb = $manual_img->getUnscaledThumb();
529 - }
530 - } elseif ( $framed ) {
531 - // Use image dimensions, don't scale
532 - $thumb = $img->getUnscaledThumb( $page );
 555+
 556+ if ( !$exists ) {
 557+ $outerWidth = $params['width'] + 2;
533558 } else {
534 - # Do not present an image bigger than the source, for bitmap-style images
535 - # This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour
536 - $srcWidth = $img->getWidth( $page );
537 - if ( $srcWidth && !$img->mustRender() && $params['width'] > $srcWidth ) {
538 - $params['width'] = $srcWidth;
 559+ if ( $manual_thumb != '' ) {
 560+ # Use manually specified thumbnail
 561+ $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb );
 562+ if( $manual_title ) {
 563+ $manual_img = wfFindFile( $manual_title );
 564+ if ( $manual_img ) {
 565+ $thumb = $manual_img->getUnscaledThumb();
 566+ } else {
 567+ $exists = false;
 568+ }
 569+ }
 570+ } elseif ( $framed ) {
 571+ // Use image dimensions, don't scale
 572+ $thumb = $img->getUnscaledThumb( $page );
 573+ } else {
 574+ # Do not present an image bigger than the source, for bitmap-style images
 575+ # This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour
 576+ $srcWidth = $img->getWidth( $page );
 577+ if ( $srcWidth && !$img->mustRender() && $params['width'] > $srcWidth ) {
 578+ $params['width'] = $srcWidth;
 579+ }
 580+ $thumb = $img->transform( $params );
539581 }
540 - $thumb = $img->transform( $params );
541 - }
542582
543 - if ( $thumb ) {
544 - $outerWidth = $thumb->getWidth() + 2;
545 - } else {
546 - $outerWidth = $params['width'] + 2;
 583+ if ( $thumb ) {
 584+ $outerWidth = $thumb->getWidth() + 2;
 585+ } else {
 586+ $outerWidth = $params['width'] + 2;
 587+ }
547588 }
548589
549590 $query = $page ? 'page=' . urlencode( $page ) : '';
550 - $u = $img->getTitle()->getLocalURL( $query );
 591+ $u = $nt->getLocalURL( $query );
551592
552593 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
553594 $magnifyalign = $wgContLang->isRTL() ? 'left' : 'right';
554595 $textalign = $wgContLang->isRTL() ? ' style="text-align:right"' : '';
555596
556597 $s = "<div class=\"thumb t{$align}\"><div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">";
557 - if ( !$thumb ) {
 598+ if( !$exists ) {
 599+ $s .= $this->makeBrokenImageLinkObj( $nt );
 600+ $zoomicon = '';
 601+ } elseif ( !$thumb ) {
558602 $s .= htmlspecialchars( wfMsg( 'thumbnail_error', '' ) );
559603 $zoomicon = '';
560 - } elseif( !$img->exists() ) {
561 - $s .= $this->makeBrokenImageLinkObj( $img->getTitle() );
562 - $zoomicon = '';
563604 } else {
564605 $imgAttribs = array(
565606 'alt' => $alt,
@@ -616,10 +657,10 @@
617658 return $s;
618659 }
619660
620 - /** @todo document */
621 - function makeMediaLink( $name, /* wtf?! */ $url, $alt = '' ) {
 661+ /** @deprecated use Linker::makeMediaLinkObj() */
 662+ function makeMediaLink( $name, $unused = '', $text = '' ) {
622663 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
623 - return $this->makeMediaLinkObj( $nt, $alt );
 664+ return $this->makeMediaLinkObj( $nt, $text );
624665 }
625666
626667 /**
@@ -637,13 +678,13 @@
638679 ### HOTFIX. Instead of breaking, return empty string.
639680 return $text;
640681 } else {
641 - $img = new Image( $title );
642 - if( $img->exists() ) {
 682+ $img = wfFindFile( $title );
 683+ if( $img ) {
643684 $url = $img->getURL();
644685 $class = 'internal';
645686 } else {
646687 $upload = SpecialPage::getTitleFor( 'Upload' );
647 - $url = $upload->getLocalUrl( 'wpDestFile=' . urlencode( $img->getName() ) );
 688+ $url = $upload->getLocalUrl( 'wpDestFile=' . urlencode( $title->getText() ) );
648689 $class = 'new';
649690 }
650691 $alt = htmlspecialchars( $title->getText() );
@@ -790,7 +831,7 @@
791832
792833 /**
793834 * Generate a user link if the current user is allowed to view it
794 - * @param $event, log item.
 835+ * @param $event, log row item.
795836 * @param $isPublic, bool, show only if all users can see it
796837 * @return string HTML
797838 */
@@ -815,19 +856,19 @@
816857
817858 /**
818859 * Generate a user link if the current user is allowed to view it
819 - * @param ArchivedFile or OldImage $file
 860+ * @param File $file
820861 * @param $isPublic, bool, show only if all users can see it
821862 * @return string HTML
822863 */
823864 function fileUserLink( $file, $isPublic = false ) {
824 - if( $file->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
 865+ if( $file->isDeleted( File::DELETED_USER ) && $isPublic ) {
825866 $link = wfMsgHtml( 'rev-deleted-user' );
826 - } else if( $file->userCan( Revision::DELETED_USER ) ) {
827 - $link = $this->userLink( $file->mUser, $file->mUserText );
 867+ } else if( $file->userCan( File::DELETED_USER ) ) {
 868+ $link = $this->userLink( $file->user, $file->userText );
828869 } else {
829870 $link = wfMsgHtml( 'rev-deleted-user' );
830871 }
831 - if( $file->isDeleted( Revision::DELETED_USER ) ) {
 872+ if( $file->isDeleted( File::DELETED_USER ) ) {
832873 return '<span class="history-deleted">' . $link . '</span>';
833874 }
834875 return $link;
@@ -883,7 +924,7 @@
884925
885926 /**
886927 * Generate a user tool link cluster if the current user is allowed to view it
887 - * @param ArchivedFile or OldImage $file
 928+ * @param File $file
888929 * @param $isPublic, bool, show only if all users can see it
889930 * @return string HTML
890931 */
@@ -891,8 +932,8 @@
892933 if( $file->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
893934 $link = wfMsgHtml( 'rev-deleted-user' );
894935 } else if( $file->userCan( Revision::DELETED_USER ) ) {
895 - $link = $this->userLink( $file->mUser, $file->mUserText ) .
896 - $this->userToolLinks( $file->mUser, $file->mUserText );
 936+ $link = $this->userLink( $file->user, $file->userText ) .
 937+ $this->userToolLinks( $file->user, $file->userText );
897938 } else {
898939 $link = wfMsgHtml( 'rev-deleted-user' );
899940 }
@@ -1094,18 +1135,18 @@
10951136 * Wrap and format the given file's comment block, if the current
10961137 * user is allowed to view it.
10971138 *
1098 - * @param ArchivedFile or OldImage $file
 1139+ * @param File $file
10991140 * @return string HTML
11001141 */
11011142 function fileComment( $file, $isPublic = false ) {
1102 - if( $file->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) {
 1143+ if( $file->isDeleted( File::DELETED_COMMENT ) && $isPublic ) {
11031144 $block = ' ' . wfMsgHtml( 'rev-deleted-comment' );
1104 - } else if( $file->userCan( Revision::DELETED_COMMENT ) ) {
1105 - $block = $this->commentBlock( $file->mDescription );
 1145+ } else if( $file->userCan( File::DELETED_COMMENT ) ) {
 1146+ $block = $this->commentBlock( $file->description );
11061147 } else {
11071148 $block = ' ' . wfMsgHtml( 'rev-deleted-comment' );
11081149 }
1109 - if( $file->isDeleted( Revision::DELETED_COMMENT ) ) {
 1150+ if( $file->isDeleted( File::DELETED_COMMENT ) ) {
11101151 return "<span class=\"history-deleted\">$block</span>";
11111152 }
11121153 return $block;
Index: branches/phase3_rev_deleted/includes/Parser.php
@@ -99,11 +99,6 @@
100100 # Persistent:
101101 var $mTagHooks, $mFunctionHooks, $mFunctionSynonyms, $mVariables;
102102
103 - # Are we trying to get revs from a certain timeframe?
104 - # Use $mTimeframe to set the revision to show as it was at that time
105 - # Deletions/moves can cause red linkage or templates to become mere links
106 - var $mTimeframe;
107 -
108103 # Cleared with clearState():
109104 var $mOutput, $mAutonumber, $mDTopen, $mStripState;
110105 var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
@@ -279,7 +274,7 @@
280275 * @param int $revid number to pass in {{REVISIONID}}
281276 * @return ParserOutput a ParserOutput
282277 */
283 - public function parse( $text, &$title, $options, $linestart = true, $clearState = true, $revid = null, $timeframe=null ) {
 278+ public function parse( $text, &$title, $options, $linestart = true, $clearState = true, $revid = null ) {
284279 /**
285280 * First pass--just handle <nowiki> sections, pass the rest off
286281 * to internalParse() which does all the real work.
@@ -296,9 +291,6 @@
297292
298293 $this->mOptions = $options;
299294 $this->mTitle =& $title;
300 - // This variable is used for gettings Templates/Images from a certain time
301 - $this->mTimeframe = $timeframe;
302 -
303295 $oldRevisionId = $this->mRevisionId;
304296 $oldRevisionTimestamp = $this->mRevisionTimestamp;
305297 if( $revid !== null ) {
@@ -408,12 +400,15 @@
409401 * Expand templates and variables in the text, producing valid, static wikitext.
410402 * Also removes comments.
411403 */
412 - function preprocess( $text, $title, $options ) {
 404+ function preprocess( $text, $title, $options, $revid = null ) {
413405 wfProfileIn( __METHOD__ );
414406 $this->clearState();
415407 $this->setOutputType( OT_PREPROCESS );
416408 $this->mOptions = $options;
417409 $this->mTitle = $title;
 410+ if( $revid !== null ) {
 411+ $this->mRevisionId = $revid;
 412+ }
418413 wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
419414 $text = $this->strip( $text, $this->mStripState );
420415 wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
@@ -1807,11 +1802,15 @@
18081803 $this->mOutput->addImage( $nt->getDBkey() );
18091804 continue;
18101805 } elseif( $ns == NS_SPECIAL ) {
1811 - $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix );
 1806+ if( SpecialPage::exists( $nt->getDBkey() ) ) {
 1807+ $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix );
 1808+ } else {
 1809+ $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix );
 1810+ }
18121811 continue;
18131812 } elseif( $ns == NS_IMAGE ) {
1814 - $img = new Image( $nt );
1815 - if( $img->exists() ) {
 1813+ $img = wfFindFile( $nt );
 1814+ if( $img ) {
18161815 // Force a blue link if the file exists; may be a remote
18171816 // upload on the shared repository, and we want to see its
18181817 // auto-generated page.
@@ -3268,18 +3267,25 @@
32693268 * Fetch the unparsed text of a template and register a reference to it.
32703269 */
32713270 function fetchTemplateAndtitle( $title ) {
3272 - $text = false;
 3271+ $text = $skip = false;
32733272 $finalTitle = $title;
32743273 // Loop to fetch the article, with up to 1 redirect
32753274 for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
3276 - # Are we trying to get revs from a certain timeframe?
3277 - if ( $this->mTimeframe ) {
3278 - $rev = Revision::newFromTimeframe( $title, $this->mTimeframe );
3279 - } else {
3280 - $rev = Revision::newFromTitle( $title );
 3275+ # Give extensions a chance to select the revision instead
 3276+ $id = false; // Assume current
 3277+ wfRunHooks( 'BeforeParserFetchTemplateAndtitle', array( &$this, &$title, &$skip, &$id ) );
 3278+
 3279+ if( $skip ) {
 3280+ $text = false;
 3281+ $this->mOutput->addTemplate( $title, $title->getArticleID(), 0 );
 3282+ break;
32813283 }
3282 - $this->mOutput->addTemplate( $title, $title->getArticleID() );
3283 - if ( $rev ) {
 3284+ $rev = $id ? Revision::newFromId( $id ) : Revision::newFromTitle( $title );
 3285+ $rev_id = $rev ? $rev->getId() : 0;
 3286+
 3287+ $this->mOutput->addTemplate( $title, $title->getArticleID(), $rev_id );
 3288+
 3289+ if( $rev ) {
32843290 $text = $rev->getText();
32853291 } elseif( $title->getNamespace() == NS_MEDIAWIKI ) {
32863292 global $wgLang;
@@ -4050,6 +4056,8 @@
40514057 $this->mOutput->addLink( $title, $id );
40524058 } elseif ( $linkCache->isBadLink( $pdbk ) ) {
40534059 $colours[$pdbk] = 0;
 4060+ } elseif ( $title->getNamespace() == NS_SPECIAL && !SpecialPage::exists( $pdbk ) ) {
 4061+ $colours[$pdbk] = 0;
40544062 } else {
40554063 # Not in the link cache, add it to the query
40564064 if ( !isset( $current ) ) {
@@ -4131,7 +4139,7 @@
41324140 }
41334141
41344142 // process categories, check if a category exists in some variant
4135 - foreach( $categories as $category){
 4143+ foreach( $categories as $category ){
41364144 $variants = $wgContLang->convertLinkToAllVariants($category);
41374145 foreach($variants as $variant){
41384146 if($variant != $category){
@@ -4353,6 +4361,7 @@
43544362 $ig->setShowFilename( false );
43554363 $ig->setParsing();
43564364 $ig->useSkin( $this->mOptions->getSkin() );
 4365+ $ig->mRevisionId = $this->mRevisionId;
43574366
43584367 if( isset( $params['caption'] ) ) {
43594368 $caption = $params['caption'];
@@ -4369,6 +4378,8 @@
43704379 if( isset( $params['heights'] ) ) {
43714380 $ig->setHeights( $params['heights'] );
43724381 }
 4382+
 4383+ wfRunHooks( 'parserBeforerenderImageGallery', array( &$this, &$ig ) );
43734384
43744385 $lines = explode( "\n", $text );
43754386 foreach ( $lines as $line ) {
@@ -4400,7 +4411,7 @@
44014412 );
44024413 $html = $pout->getText();
44034414
4404 - $ig->add( new Image( $nt ), $html );
 4415+ $ig->add( $nt, $html );
44054416
44064417 # Only add real images (bug #5586)
44074418 if ( $nt->getNamespace() == NS_IMAGE ) {
@@ -4425,7 +4436,9 @@
44264437 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
44274438 # * center center the image
44284439 # * framed Keep original image size, no magnify-button.
 4440+ # * frameless like 'thumb' but without a frame. Keeps user preferences for width
44294441 # * upright reduce width for upright images, rounded to full __0 px
 4442+ # * border draw a 1px border around the image
44304443 # vertical-align values (no % or length right now):
44314444 # * baseline
44324445 # * sub
@@ -4448,14 +4461,14 @@
44494462 $mwManualThumb =& MagicWord::get( 'img_manualthumb' );
44504463 $mwWidth =& MagicWord::get( 'img_width' );
44514464 $mwFramed =& MagicWord::get( 'img_framed' );
 4465+ $mwFrameless =& MagicWord::get( 'img_frameless' );
44524466 $mwUpright =& MagicWord::get( 'img_upright' );
 4467+ $mwBorder =& MagicWord::get( 'img_border' );
44534468 $mwPage =& MagicWord::get( 'img_page' );
44544469 $caption = '';
44554470
44564471 $params = array();
44574472 $framed = $thumb = false;
4458 - $upright = false;
4459 - $upright_factor = 0;
44604473 $manual_thumb = '' ;
44614474 $align = $valign = '';
44624475 $sk = $this->mOptions->getSkin();
@@ -4464,8 +4477,12 @@
44654478 if ( !is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
44664479 $thumb=true;
44674480 } elseif ( !is_null( $match = $mwUpright->matchVariableStartToEnd( $val ) ) ) {
4468 - $upright = true;
4469 - $upright_factor = floatval( $match );
 4481+ $params['upright'] = true;
 4482+ $params['upright_factor'] = floatval( $match );
 4483+ } elseif ( !is_null( $match = $mwFrameless->matchVariableStartToEnd( $val ) ) ) {
 4484+ $params['frameless'] = true;
 4485+ } elseif ( !is_null( $mwBorder->matchVariableStartToEnd( $val ) ) ) {
 4486+ $params['border'] = true;
44704487 } elseif ( ! is_null( $match = $mwManualThumb->matchVariableStartToEnd($val) ) ) {
44714488 # use manually specified thumbnail
44724489 $thumb=true;
@@ -4511,9 +4528,18 @@
45124529 $alt = $this->mStripState->unstripBoth( $alt );
45134530 $alt = Sanitizer::stripAllTags( $alt );
45144531
 4532+ # Give extensions a chance to select the file revision for us
 4533+ $link = $skip = $time = false;
 4534+ wfRunHooks( 'BeforeParserMakeImageLinkObj', array( &$this, &$nt, &$skip, &$time ) );
 4535+
45154536 # Linker does the rest
4516 - return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $params, $framed, $thumb, $manual_thumb,
4517 - $valign, $upright, $upright_factor, $this->mTimeframe );
 4537+ if( $skip ) {
 4538+ $link = $sk->makeLinkObj( $nt );
 4539+ } else {
 4540+ $link = $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $params, $framed, $thumb, $manual_thumb, $valign, $time );
 4541+ }
 4542+
 4543+ return $link;
45184544 }
45194545
45204546 /**
Index: branches/phase3_rev_deleted/includes/Revision.php
@@ -49,79 +49,6 @@
5050 'page_namespace' => $title->getNamespace(),
5151 'page_title' => $title->getDbkey() ) );
5252 }
53 -
54 - /**
55 - * Gets the revision that was current at said time
56 - * as accurately as possible. Archiving of individual
57 - * revisions can cause this to become borked.
58 - * --Use of rev_deleted instead avoids that.
59 - * History merges can break this
60 - * --Requiring either all restored revs to be all newer
61 - * --or all older to than those of the live page avoids that.
62 - *
63 - * --Also, if a page has archived revs, deletion should have
64 - * --the same limitations
65 - *
66 - * @param Database $db
67 - * @param Title $title
68 - * @param timestamp $timeframe, desired view time
69 - * @return Revision
70 - * @access public
71 - * @static
72 - */
73 - public static function newFromTimeframe( &$title, $timeframe ) {
74 - $relocated = true; // Assume true to begin with
75 - $isdeleted = false;
76 - $id = 0;
77 -
78 - $dbr = wfGetDB( DB_SLAVE );
79 - // Initial query conds...
80 - $d = "log_action='delete'";
81 - $r = '1 = 0'; // we don't care if it was restored yet
82 - $m = "log_action='move'";
83 - // Recursively check logs for page moves since $timeframe...
84 - while( $relocated ) {
85 - $result = $dbr->select( 'logging', array('log_params', 'log_action', 'log_id'),
86 - array("log_timestamp >= $timeframe", "log_id > $id",
87 - 'log_namespace' => $title->getNamespace(), 'log_title' => $title->getDbkey(),
88 - "($m) OR ($d) OR ($r)"),
89 - __METHOD__,
90 - array('ORDER BY' => 'log_timestamp ASC', 'LIMIT' => 1) );
91 - if( $row = $dbr->fetchObject($result) ) {
92 - // Was it deleted?
93 - if( $row->log_action=='delete' ) {
94 - $isdeleted = true;
95 - $d = '1 = 0';
96 - $r = "log_action='restore'";
97 - $m = '1 = 0';
98 - // Was it restored?
99 - } else if( $row->log_action=='restore' ) {
100 - // Check the restore point (format is <page time>\n<image time>)
101 - $restpoints = explode('\n',$row->log_params);
102 - if( $restpoints[0] >= 0 && $restpoints[0] <= $timeframe ) {
103 - $isdeleted = false; // our desired revision was restored
104 - $d = "log_action='delete'";
105 - $r = '1 = 0';
106 - $m = "log_action='move'";
107 - }
108 - // Was it moved?
109 - } else {
110 - $title = Title::newFromText( $row->log_params ); // New name is stored here
111 - }
112 - $id = $row->log_id;
113 - } else if( $isdeleted ) {
114 - return null;
115 - } else {
116 - $relocated = false;
117 - }
118 - }
119 - // Fetch the revision
120 - return Revision::newFromConds(
121 - array( "rev_timestamp < $timeframe",
122 - 'page_id=rev_page',
123 - 'page_namespace' => $title->getNamespace(),
124 - 'page_title' => $title->getDbkey() ) );
125 - }
12653
12754 /**
12855 * Load a page revision from a given revision ID number.
@@ -315,7 +242,7 @@
316243 'rev_len' ),
317244 $conditions,
318245 'Revision::fetchRow',
319 - array( 'ORDER BY' => 'rev_id DESC', 'LIMIT' => 1 ) );
 246+ array( 'LIMIT' => 1 ) );
320247 $ret = $db->resultObject( $res );
321248 return $ret;
322249 }
Index: branches/phase3_rev_deleted/includes/CategoryPage.php
@@ -147,7 +147,7 @@
148148 /**
149149 * Add a page in the image namespace
150150 */
151 - function addImage( $title, $sortkey, $pageLength, $isRedirect = false ) {
 151+ function addImage( Title $title, $sortkey, $pageLength, $isRedirect = false ) {
152152 if ( $this->showGallery ) {
153153 $image = new Image( $title );
154154 if( $this->flip ) {
@@ -222,7 +222,7 @@
223223
224224 if( $title->getNamespace() == NS_CATEGORY ) {
225225 $this->addSubcategory( $title, $x->cl_sortkey, $x->page_len );
226 - } elseif( $title->getNamespace() == NS_IMAGE ) {
 226+ } elseif( $this->showGallery && $title->getNamespace() == NS_IMAGE ) {
227227 $this->addImage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect );
228228 } else {
229229 $this->addPage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect );
Index: branches/phase3_rev_deleted/includes/ParserOutput.php
@@ -14,7 +14,9 @@
1515 $mTitleText, # title text of the chosen language variant
1616 $mLinks, # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken.
1717 $mTemplates, # 2-D map of NS/DBK to ID for the template references. ID=zero for broken.
 18+ $mTemplateIds, # 2-D map of NS/DBK to rev ID for the template references. ID=zero for broken.
1819 $mImages, # DB keys of the images used, in the array key only
 20+ $mImageTimestamps, # Map of DBK to rev ID for the template references. ID=zero for broken.
1921 $mExternalLinks, # External link URLs, in the key only
2022 $mHTMLtitle, # Display HTML title
2123 $mSubtitle, # Additional subtitle
@@ -41,10 +43,12 @@
4244 $this->mNewSection = false;
4345 $this->mNoGallery = false;
4446 $this->mHeadItems = array();
 47+ $this->mTemplateIds = array();
 48+ $this->mImageTimestamps = array();
4549 }
4650
4751 function getText() { return $this->mText; }
48 - function &getLanguageLinks() { return $this->mLanguageLinks; }
 52+ function &getLanguageLinks() { return $this->mLanguageLinks; }
4953 function getCategoryLinks() { return array_keys( $this->mCategories ); }
5054 function &getCategories() { return $this->mCategories; }
5155 function getCacheTime() { return $this->mCacheTime; }
@@ -66,7 +70,6 @@
6771 function setSubtitle( $st ) { return wfSetVar( $this->mSubtitle, $st ); }
6872
6973 function addCategory( $c, $sort ) { $this->mCategories[$c] = $sort; }
70 - function addImage( $name ) { $this->mImages[$name] = 1; }
7174 function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; }
7275 function addExternalLink( $url ) { $this->mExternalLinks[$url] = 1; }
7376
@@ -88,14 +91,33 @@
8992 }
9093 $this->mLinks[$ns][$dbk] = $id;
9194 }
 95+
 96+ function addImage( $name, $timestamp=NULL ) {
 97+ if( isset($this->mImages[$name]) )
 98+ return; // No repeated pointless DB calls!
 99+ $this->mImages[$name] = 1;
 100+ if( is_null($timestamp) ) {
 101+ wfProfileIn( __METHOD__ );
 102+ $dbr = wfGetDB(DB_SLAVE);
 103+ $timestamp = $dbr->selectField('image', 'img_timestamp',
 104+ array('img_name' => $name),
 105+ __METHOD__ );
 106+ }
 107+ $timestamp = $timestamp ? $timestamp : 0;
 108+ $this->mImageTimestamps[$name] = $timestamp; // For versioning
 109+ }
92110
93 - function addTemplate( $title, $id ) {
 111+ function addTemplate( $title, $page_id, $rev_id ) {
94112 $ns = $title->getNamespace();
95113 $dbk = $title->getDBkey();
96114 if ( !isset( $this->mTemplates[$ns] ) ) {
97115 $this->mTemplates[$ns] = array();
98116 }
99 - $this->mTemplates[$ns][$dbk] = $id;
 117+ $this->mTemplates[$ns][$dbk] = $page_id;
 118+ if ( !isset( $this->mTemplateIds[$ns] ) ) {
 119+ $this->mTemplateIds[$ns] = array();
 120+ }
 121+ $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning
100122 }
101123
102124 /**
Index: branches/phase3_rev_deleted/includes/ImagePage.php
@@ -18,6 +18,14 @@
1919 /* private */ var $img; // Image object this page is shown for
2020 var $mExtraDescription = false;
2121
 22+ function __construct( $title ) {
 23+ parent::__construct( $title );
 24+ $this->img = wfFindFile( $this->mTitle );
 25+ if ( !$this->img ) {
 26+ $this->img = wfLocalFile( $this->mTitle );
 27+ }
 28+ }
 29+
2230 /**
2331 * Handler for action=render
2432 * Include body text only; none of the image extras
@@ -31,8 +39,6 @@
3240 function view() {
3341 global $wgOut, $wgShowEXIF, $wgRequest, $wgUser;
3442
35 - $this->img = new Image( $this->mTitle );
36 -
3743 $diff = $wgRequest->getVal( 'diff' );
3844 $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) );
3945
@@ -160,7 +166,7 @@
161167 * shared upload server if possible.
162168 */
163169 function getContent() {
164 - if( $this->img && $this->img->fromSharedDirectory && 0 == $this->getID() ) {
 170+ if( $this->img && !$this->img->isLocal() && 0 == $this->getID() ) {
165171 return '';
166172 }
167173 return Article::getContent();
@@ -332,26 +338,26 @@
333339 $dirmark = $wgContLang->getDirMark();
334340 if (!$this->img->isSafeFile()) {
335341 $warning = wfMsg( 'mediawarning' );
336 - $wgOut->addWikiText( <<<END
 342+ $wgOut->addWikiText( <<<EOT
337343 <div class="fullMedia">$infores
338344 <span class="dangerousLink">[[Media:$filename|$filename]]</span>$dirmark
339345 <span class="fileInfo"> $info</span>
340346 </div>
341347
342348 <div class="mediaWarning">$warning</div>
343 -END
 349+EOT
344350 );
345351 } else {
346 - $wgOut->addWikiText( <<<END
 352+ $wgOut->addWikiText( <<<EOT
347353 <div class="fullMedia">$infores
348354 [[Media:$filename|$filename]]$dirmark <span class="fileInfo"> $info</span>
349355 </div>
350 -END
 356+EOT
351357 );
352358 }
353359 }
354360
355 - if($this->img->fromSharedDirectory) {
 361+ if(!$this->img->isLocal()) {
356362 $this->printSharedImageText();
357363 }
358364 } else {
@@ -365,27 +371,21 @@
366372 }
367373
368374 function printSharedImageText() {
369 - global $wgRepositoryBaseUrl, $wgFetchCommonsDescriptions, $wgOut, $wgUser;
 375+ global $wgOut, $wgUser;
370376
371 - $url = $wgRepositoryBaseUrl . urlencode($this->mTitle->getDBkey());
372 - $sharedtext = "<div class='sharedUploadNotice'>" . wfMsgWikiHtml("sharedupload");
373 - if ($wgRepositoryBaseUrl && !$wgFetchCommonsDescriptions) {
374 -
 377+ $descUrl = $this->img->getDescriptionUrl();
 378+ $descText = $this->img->getDescriptionText();
 379+ $s = "<div class='sharedUploadNotice'>" . wfMsgWikiHtml("sharedupload");
 380+ if ( $descUrl && !$descText) {
375381 $sk = $wgUser->getSkin();
376 - $title = SpecialPage::getTitleFor( 'Upload' );
377 - $link = $sk->makeKnownLinkObj($title, wfMsgHtml('shareduploadwiki-linktext'),
378 - array( 'wpDestFile' => urlencode( $this->img->getName() )));
379 - $sharedtext .= " " . wfMsgWikiHtml('shareduploadwiki', $link);
 382+ $link = $sk->makeExternalLink( $descUrl, wfMsg('shareduploadwiki-linktext') );
 383+ $s .= " " . wfMsgWikiHtml('shareduploadwiki', $link);
380384 }
381 - $sharedtext .= "</div>";
382 - $wgOut->addHTML($sharedtext);
 385+ $s .= "</div>";
 386+ $wgOut->addHTML($s);
383387
384 - if ($wgRepositoryBaseUrl && $wgFetchCommonsDescriptions) {
385 - $renderUrl = wfAppendQuery( $url, 'action=render' );
386 - wfDebug( "Fetching shared description from $renderUrl\n" );
387 - $text = Http::get( $renderUrl );
388 - if ($text)
389 - $this->mExtraDescription = $text;
 388+ if ( $descText ) {
 389+ $this->mExtraDescription = $descText;
390390 }
391391 }
392392
@@ -402,7 +402,7 @@
403403 function uploadLinksBox() {
404404 global $wgUser, $wgOut;
405405
406 - if( $this->img->fromSharedDirectory )
 406+ if( !$this->img->isLocal() )
407407 return;
408408
409409 $sk = $wgUser->getSkin();
@@ -441,7 +441,7 @@
442442 $line = $this->img->nextHistoryLine();
443443
444444 if ( $line ) {
445 - $list = new ImageHistoryList( $sk );
 445+ $list = new ImageHistoryList( $sk, $this->img );
446446 // Our top image
447447 $s = $list->beginImageHistoryList() .
448448 $list->imageHistoryLine( true, wfTimestamp(TS_MW, $line->img_timestamp),
@@ -533,8 +533,6 @@
534534 return;
535535 }
536536
537 - $this->img = new Image( $this->mTitle );
538 -
539537 # Deleting old images doesn't require confirmation
540538 if ( !is_null( $oldimage ) || $confirm ) {
541539 if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) {
@@ -658,41 +656,23 @@
659657 $wgOut->showErrorPage( 'internalerror', 'sessionfailure' );
660658 return;
661659 }
662 - $name = substr( $oldimage, 15 );
663660
664 - $dest = wfImageDir( $name );
665 - $archive = wfImageArchiveDir( $name );
666 - $curfile = "{$dest}/{$name}";
 661+ $sourcePath = $this->img->getArchiveVirtualUrl( $oldimage );
 662+ $result = $this->img->publish( $sourcePath );
667663
668 - if ( !is_dir( $dest ) ) wfMkdirParents( $dest );
669 - if ( !is_dir( $archive ) ) wfMkdirParents( $archive );
670 -
671 - if ( ! is_file( $curfile ) ) {
672 - $wgOut->showFileNotFoundError( htmlspecialchars( $curfile ) );
 664+ if ( WikiError::isError( $result ) ) {
 665+ $this->showError( $result );
673666 return;
674667 }
675 - $oldver = wfTimestampNow() . "!{$name}";
676668
677 - wfSuppressWarnings();
678 - if ( ! rename( $curfile, "${archive}/{$oldver}" ) ) {
679 - $wgOut->showFileRenameError( $curfile, "${archive}/{$oldver}" );
680 - return;
681 - }
682 - if ( ! copy( "{$archive}/{$oldimage}", $curfile ) ) {
683 - $wgOut->showFileCopyError( "${archive}/{$oldimage}", $curfile );
684 - return;
685 - }
686 - wfRestoreWarnings();
687 -
688669 # Record upload and update metadata cache
689 - $img = Image::newFromName( $name );
690 - $img->recordUpload( $oldver, wfMsg( "reverted" ) );
 670+ $this->img->recordUpload( $result, wfMsg( "reverted" ) );
691671
692672 $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
693673 $wgOut->setRobotpolicy( 'noindex,nofollow' );
694674 $wgOut->addHTML( wfMsg( 'imagereverted' ) );
695675
696 - $descTitle = $img->getTitle();
 676+ $descTitle = $this->img->getTitle();
697677 $wgOut->returnToMain( false, $descTitle->getPrefixedText() );
698678 }
699679
@@ -700,7 +680,6 @@
701681 * Override handling of action=purge
702682 */
703683 function doPurge() {
704 - $this->img = new Image( $this->mTitle );
705684 if( $this->img->exists() ) {
706685 wfDebug( "ImagePage::doPurge purging " . $this->img->getName() . "\n" );
707686 $update = new HTMLCacheUpdate( $this->mTitle, 'imagelinks' );
@@ -713,6 +692,18 @@
714693 parent::doPurge();
715694 }
716695
 696+ /**
 697+ * Display an error from a wikitext-formatted WikiError object
 698+ */
 699+ function showError( WikiError $error ) {
 700+ global $wgOut;
 701+ $wgOut->setPageTitle( wfMsg( "internalerror" ) );
 702+ $wgOut->setRobotpolicy( "noindex,nofollow" );
 703+ $wgOut->setArticleRelated( false );
 704+ $wgOut->enableClientCache( false );
 705+ $wgOut->addWikiText( $error->getMessage() );
 706+ }
 707+
717708 }
718709
719710 /**
@@ -720,8 +711,10 @@
721712 * @addtogroup Media
722713 */
723714 class ImageHistoryList {
724 - function ImageHistoryList( &$skin ) {
725 - $this->skin =& $skin;
 715+ var $img, $skin;
 716+ function ImageHistoryList( $skin, $img ) {
 717+ $this->skin = $skin;
 718+ $this->img = $img;
726719 }
727720
728721 function beginImageHistoryList() {
@@ -744,11 +737,12 @@
745738 $del = wfMsgHtml( 'rev-delundel' );
746739 $delall = wfMsgHtml( 'deleteimgcompletely' );
747740 $cur = wfMsgHtml( 'cur' );
 741+ $local = $this->img->isLocal();
748742
749743 if ( $iscur ) {
750 - $url = Image::imageUrl( $img );
 744+ $url = htmlspecialchars( $this->img->getURL() );
751745 $rlink = $cur;
752 - if ( $wgUser->isAllowed('delete') ) {
 746+ if ( $local && $wgUser->isAllowed('delete') ) {
753747 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
754748 '&action=delete' );
755749 $style = $this->skin->getInternalLinkAttributes( $link, $delall );
@@ -758,8 +752,8 @@
759753 $dlink = '';
760754 }
761755 } else {
762 - $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
763 - if( $wgUser->getID() != 0 && $wgTitle->userCan( 'edit' ) ) {
 756+ $url = htmlspecialchars( $this->img->getArchiveUrl( $img ) );
 757+ if( $local && $wgUser->getID() != 0 && $wgTitle->userCan( 'edit' ) ) {
764758 # Revert link, for public files only
765759 if ( $deleted ) {
766760 $rlink = wfMsgHtml( 'revertimg' );
@@ -811,13 +805,17 @@
812806 $dlink = '';
813807 }
814808 }
 809+
815810 # Hide deleted usernames
816811 if ( $this->isDeleted($deleted,Image::DELETED_USER) )
817812 $userlink = '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
818 - else
 813+ else if ( $local ) {
819814 $userlink = $this->skin->userLink( $user, $usertext ) . $this->skin->userToolLinks( $user, $usertext );
820 -
 815+ } else {
 816+ $userlink = htmlspecialchars( $usertext );
 817+ }
821818 $nbytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ), $wgLang->formatNum( $size ) );
 819+
822820 $widthheight = wfMsgHtml( 'widthheight', $width, $height );
823821 $style = $this->skin->getInternalLinkAttributes( $url, $datetime );
824822
Index: branches/phase3_rev_deleted/includes/SpecialImagelist.php
@@ -115,7 +115,9 @@
116116 case 'img_name':
117117 $name = $this->mCurrentRow->img_name;
118118 $link = $this->getSkin()->makeKnownLinkObj( Title::makeTitle( NS_IMAGE, $name ), $value );
119 - $download = Xml::element('a', array( "href" => Image::imageUrl( $name ) ), $this->mMessages['imgfile'] );
 119+ $image = wfLocalFile( $value );
 120+ $url = $image->getURL();
 121+ $download = Xml::element('a', array( "href" => $url ), $this->mMessages['imgfile'] );
120122 return "$link ($download)";
121123 case 'img_user_text':
122124 if ( $this->mCurrentRow->img_user ) {
Index: branches/phase3_rev_deleted/includes/SpecialBlockip.php
@@ -61,7 +61,7 @@
6262 $this->BlockCreateAccount = $wgRequest->getBool( 'wpCreateAccount', $byDefault );
6363 $this->BlockEnableAutoblock = $wgRequest->getBool( 'wpEnableAutoblock', $byDefault );
6464 # Re-check user's rights to hide names, very serious, defaults to 0
65 - $this->BlockHideName = $wgRequest->getBool( 'wpHideName', 0 ) && $wgUser->isAllowed( 'hideuser' );
 65+ $this->BlockHideName = ( $wgRequest->getBool( 'wpHideName', 0 ) && $wgUser->isAllowed( 'hideuser' ) ) ? 1 : 0;
6666 }
6767
6868 function showForm( $err ) {
@@ -196,7 +196,8 @@
197197 <td align=\"$alignRight\">{$mIpbreason}</td>
198198 <td>
199199 " . Xml::input( 'wpBlockReason', 45, $this->BlockReason,
200 - array( 'tabindex' => '5', 'id' => 'mw-bi-reason' ) ) . "
 200+ array( 'tabindex' => '5', 'id' => 'mw-bi-reason',
 201+ 'maxlength'=> '200' ) ) . "
201202 </td>
202203 </tr>
203204 <tr id='wpAnonOnlyRow'>
Index: branches/phase3_rev_deleted/includes/DatabasePostgres.php
@@ -561,7 +561,7 @@
562562 }
563563
564564 function affectedRows() {
565 - if( !isset( $this->mLastResult ) )
 565+ if( !isset( $this->mLastResult ) or ! $this->mLastResult )
566566 return 0;
567567
568568 return pg_affected_rows( $this->mLastResult );
Index: branches/phase3_rev_deleted/includes/ChangesList.php
@@ -593,7 +593,7 @@
594594 $chardiff = $rcObj->getCharacterDifference( $block[ count( $block ) - 1 ]->mAttribs['rc_old_len'],
595595 $block[0]->mAttribs['rc_new_len'] );
596596 if( $chardiff == '' ) {
597 - $r .= ' (';
 597+ $r .= ') ';
598598 } else {
599599 $r .= ' ' . $chardiff. ' . . ';
600600 }
Index: branches/phase3_rev_deleted/includes/SpecialWhatlinkshere.php
@@ -230,6 +230,12 @@
231231 $wgOut->addHTML( ' (' . implode( ', ', $props ) . ') ' );
232232 }
233233
 234+ //add whatlinkshere link
 235+ $whatlink = $this->skin->makeKnownLinkObj(
 236+ SpecialPage::getTitleFor( 'Whatlinkshere', $nt->getPrefixedDBkey() ),
 237+ wfMsgHtml( 'whatlinkshere-links' ) );
 238+ $wgOut->addHTML(" ($whatlink)" );
 239+
234240 if ( $row->page_is_redirect ) {
235241 if ( $level < 2 ) {
236242 $this->showIndirectLinks( $level + 1, $nt, 500 );
Index: branches/phase3_rev_deleted/includes/Defines.php
@@ -205,5 +205,61 @@
206206 define( 'LIST_NAMES', 3);
207207 define( 'LIST_OR', 4);
208208
 209+/**
 210+ * Unicode and normalisation related
 211+ */
 212+define( 'UNICODE_HANGUL_FIRST', 0xac00 );
 213+define( 'UNICODE_HANGUL_LAST', 0xd7a3 );
209214
 215+define( 'UNICODE_HANGUL_LBASE', 0x1100 );
 216+define( 'UNICODE_HANGUL_VBASE', 0x1161 );
 217+define( 'UNICODE_HANGUL_TBASE', 0x11a7 );
 218+
 219+define( 'UNICODE_HANGUL_LCOUNT', 19 );
 220+define( 'UNICODE_HANGUL_VCOUNT', 21 );
 221+define( 'UNICODE_HANGUL_TCOUNT', 28 );
 222+define( 'UNICODE_HANGUL_NCOUNT', UNICODE_HANGUL_VCOUNT * UNICODE_HANGUL_TCOUNT );
 223+
 224+define( 'UNICODE_HANGUL_LEND', UNICODE_HANGUL_LBASE + UNICODE_HANGUL_LCOUNT - 1 );
 225+define( 'UNICODE_HANGUL_VEND', UNICODE_HANGUL_VBASE + UNICODE_HANGUL_VCOUNT - 1 );
 226+define( 'UNICODE_HANGUL_TEND', UNICODE_HANGUL_TBASE + UNICODE_HANGUL_TCOUNT - 1 );
 227+
 228+define( 'UNICODE_SURROGATE_FIRST', 0xd800 );
 229+define( 'UNICODE_SURROGATE_LAST', 0xdfff );
 230+define( 'UNICODE_MAX', 0x10ffff );
 231+define( 'UNICODE_REPLACEMENT', 0xfffd );
 232+
 233+
 234+define( 'UTF8_HANGUL_FIRST', "\xea\xb0\x80" /*codepointToUtf8( UNICODE_HANGUL_FIRST )*/ );
 235+define( 'UTF8_HANGUL_LAST', "\xed\x9e\xa3" /*codepointToUtf8( UNICODE_HANGUL_LAST )*/ );
 236+
 237+define( 'UTF8_HANGUL_LBASE', "\xe1\x84\x80" /*codepointToUtf8( UNICODE_HANGUL_LBASE )*/ );
 238+define( 'UTF8_HANGUL_VBASE', "\xe1\x85\xa1" /*codepointToUtf8( UNICODE_HANGUL_VBASE )*/ );
 239+define( 'UTF8_HANGUL_TBASE', "\xe1\x86\xa7" /*codepointToUtf8( UNICODE_HANGUL_TBASE )*/ );
 240+
 241+define( 'UTF8_HANGUL_LEND', "\xe1\x84\x92" /*codepointToUtf8( UNICODE_HANGUL_LEND )*/ );
 242+define( 'UTF8_HANGUL_VEND', "\xe1\x85\xb5" /*codepointToUtf8( UNICODE_HANGUL_VEND )*/ );
 243+define( 'UTF8_HANGUL_TEND', "\xe1\x87\x82" /*codepointToUtf8( UNICODE_HANGUL_TEND )*/ );
 244+
 245+define( 'UTF8_SURROGATE_FIRST', "\xed\xa0\x80" /*codepointToUtf8( UNICODE_SURROGATE_FIRST )*/ );
 246+define( 'UTF8_SURROGATE_LAST', "\xed\xbf\xbf" /*codepointToUtf8( UNICODE_SURROGATE_LAST )*/ );
 247+define( 'UTF8_MAX', "\xf4\x8f\xbf\xbf" /*codepointToUtf8( UNICODE_MAX )*/ );
 248+define( 'UTF8_REPLACEMENT', "\xef\xbf\xbd" /*codepointToUtf8( UNICODE_REPLACEMENT )*/ );
 249+#define( 'UTF8_REPLACEMENT', '!' );
 250+
 251+define( 'UTF8_OVERLONG_A', "\xc1\xbf" );
 252+define( 'UTF8_OVERLONG_B', "\xe0\x9f\xbf" );
 253+define( 'UTF8_OVERLONG_C', "\xf0\x8f\xbf\xbf" );
 254+
 255+# These two ranges are illegal
 256+define( 'UTF8_FDD0', "\xef\xb7\x90" /*codepointToUtf8( 0xfdd0 )*/ );
 257+define( 'UTF8_FDEF', "\xef\xb7\xaf" /*codepointToUtf8( 0xfdef )*/ );
 258+define( 'UTF8_FFFE', "\xef\xbf\xbe" /*codepointToUtf8( 0xfffe )*/ );
 259+define( 'UTF8_FFFF', "\xef\xbf\xbf" /*codepointToUtf8( 0xffff )*/ );
 260+
 261+define( 'UTF8_HEAD', false );
 262+define( 'UTF8_TAIL', true );
 263+
 264+
 265+
210266 ?>
Index: branches/phase3_rev_deleted/includes/Article.php
@@ -371,6 +371,10 @@
372372 }
373373 }
374374
 375+ // FIXME: Horrible, horrible! This content-loading interface just plain sucks.
 376+ // We should instead work with the Revision object when we need it...
 377+ $this->mContent = $revision->userCan( Revision::DELETED_TEXT ) ? $revision->getRawText() : "";
 378+ //$this->mContent = $revision->getText();
375379 $this->mContent = $revision->revText(); // Loads if user is allowed
376380
377381 $this->mUser = $revision->getUser();
Index: branches/phase3_rev_deleted/includes/ExternalEdit.php
@@ -46,7 +46,7 @@
4747 $extension="wiki";
4848 } elseif($this->mMode=="file") {
4949 $type="Edit file";
50 - $image = new Image( $this->mTitle );
 50+ $image = wfLocalFile( $this->mTitle );
5151 $img_url = $image->getURL();
5252 if(strpos($img_url,"://")) {
5353 $url = $img_url;
Index: branches/phase3_rev_deleted/includes/GlobalFunctions.php
@@ -592,7 +592,7 @@
593593 } elseif ( in_array('parseinline', $options) ) {
594594 $string = $wgOut->parse( $string, true, true );
595595 $m = array();
596 - if( preg_match( "~^<p>(.*)\n?</p>$~", $string, $m ) ) {
 596+ if( preg_match( '/^<p>(.*)\n?<\/p>$/sU', $string, $m ) ) {
597597 $string = $m[1];
598598 }
599599 } elseif ( in_array('parsemag', $options) ) {
@@ -819,7 +819,7 @@
820820 if ( $po < 0 ) { $po = 0; }
821821 $q = "limit={$limit}&offset={$po}";
822822 if ( '' != $query ) { $q .= '&'.$query; }
823 - $plink = '<a href="' . $title->escapeLocalUrl( $q ) . "\">{$prev}</a>";
 823+ $plink = '<a href="' . $title->escapeLocalUrl( $q ) . "\" class=\"mw-prevlink\">{$prev}</a>";
824824 } else { $plink = $prev; }
825825
826826 $no = $offset + $limit;
@@ -829,7 +829,7 @@
830830 if ( $atend ) {
831831 $nlink = $next;
832832 } else {
833 - $nlink = '<a href="' . $title->escapeLocalUrl( $q ) . "\">{$next}</a>";
 833+ $nlink = '<a href="' . $title->escapeLocalUrl( $q ) . "\" class=\"mw-nextlink\">{$next}</a>";
834834 }
835835 $nums = wfNumLink( $offset, 20, $title, $query ) . ' | ' .
836836 wfNumLink( $offset, 50, $title, $query ) . ' | ' .
@@ -850,7 +850,7 @@
851851 $q .= 'limit='.$limit.'&offset='.$offset;
852852
853853 $fmtLimit = $wgLang->formatNum( $limit );
854 - $s = '<a href="' . $title->escapeLocalUrl( $q ) . "\">{$fmtLimit}</a>";
 854+ $s = '<a href="' . $title->escapeLocalUrl( $q ) . "\" class=\"mw-numlink\">{$fmtLimit}</a>";
855855 return $s;
856856 }
857857
@@ -2272,4 +2272,26 @@
22732273 $ret = $wgLoadBalancer->getConnection( $db, true, $groups );
22742274 return $ret;
22752275 }
 2276+
 2277+/**
 2278+ * Find a file.
 2279+ * Shortcut for RepoGroup::singleton()->findFile()
 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.
 2284+ * @return File, or false if the file does not exist
 2285+ */
 2286+function wfFindFile( $title, $time = false ) {
 2287+ return RepoGroup::singleton()->findFile( $title, $time );
 2288+}
 2289+
 2290+/**
 2291+ * Get an object referring to a locally registered file.
 2292+ * Returns a valid placeholder object if the file does not exist.
 2293+ */
 2294+function wfLocalFile( $title ) {
 2295+ return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
 2296+}
 2297+
22762298 ?>
Index: branches/phase3_rev_deleted/includes/SearchEngine.php
@@ -122,8 +122,8 @@
123123 # There may have been a funny upload, or it may be on a shared
124124 # file repository such as Wikimedia Commons.
125125 if( $title->getNamespace() == NS_IMAGE ) {
126 - $image = new Image( $title );
127 - if( $image->exists() ) {
 126+ $image = wfFindFile( $title );
 127+ if( $image ) {
128128 return $title;
129129 }
130130 }
Index: branches/phase3_rev_deleted/includes/SpecialMIMEsearch.php
@@ -66,7 +66,7 @@
6767 $text = $wgContLang->convert( $nt->getText() );
6868 $plink = $skin->makeLink( $nt->getPrefixedText(), $text );
6969
70 - $download = $skin->makeMediaLink( $nt->getText(), 'fuck me!', wfMsgHtml( 'download' ) );
 70+ $download = $skin->makeMediaLinkObj( $nt, wfMsgHtml( 'download' ) );
7171 $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'),
7272 $wgLang->formatNum( $result->img_size ) );
7373 $dimensions = wfMsgHtml( 'widthheight', $wgLang->formatNum( $result->img_width ),
Index: branches/phase3_rev_deleted/includes/memcached-client.php
@@ -152,7 +152,7 @@
153153 /**
154154 * At how many bytes should we compress?
155155 *
156 - * @var interger
 156+ * @var integer
157157 * @access private
158158 */
159159 var $_compress_threshold;
@@ -192,7 +192,7 @@
193193 /**
194194 * Total # of bit buckets we have
195195 *
196 - * @var interger
 196+ * @var integer
197197 * @access private
198198 */
199199 var $_bucketcount;
@@ -200,7 +200,7 @@
201201 /**
202202 * # of total servers we have
203203 *
204 - * @var interger
 204+ * @var integer
205205 * @access private
206206 */
207207 var $_active;
@@ -272,9 +272,9 @@
273273 * Adds a key/value to the memcache server if one isn't already set with
274274 * that key
275275 *
276 - * @param string $key Key to set with data
277 - * @param mixed $val Value to store
278 - * @param interger $exp (optional) Time to expire data at
 276+ * @param string $key Key to set with data
 277+ * @param mixed $val Value to store
 278+ * @param integer $exp (optional) Time to expire data at
279279 *
280280 * @return boolean
281281 * @access public
@@ -291,7 +291,7 @@
292292 * Decriment a value stored on the memcache server
293293 *
294294 * @param string $key Key to decriment
295 - * @param interger $amt (optional) Amount to decriment
 295+ * @param integer $amt (optional) Amount to decriment
296296 *
297297 * @return mixed FALSE on failure, value on success
298298 * @access public
@@ -308,7 +308,7 @@
309309 * Deletes a key from the server, optionally after $time
310310 *
311311 * @param string $key Key to delete
312 - * @param interger $time (optional) How long to wait before deleting
 312+ * @param integer $time (optional) How long to wait before deleting
313313 *
314314 * @return boolean TRUE on success, FALSE on failure
315315 * @access public
@@ -506,9 +506,9 @@
507507 * Increments $key (optionally) by $amt
508508 *
509509 * @param string $key Key to increment
510 - * @param interger $amt (optional) amount to increment
 510+ * @param integer $amt (optional) amount to increment
511511 *
512 - * @return interger New key value?
 512+ * @return integer New key value?
513513 * @access public
514514 */
515515 function incr ($key, $amt=1)
@@ -524,7 +524,7 @@
525525 *
526526 * @param string $key Key to set value as
527527 * @param mixed $value Value to store
528 - * @param interger $exp (optional) Experiation time
 528+ * @param integer $exp (optional) Experiation time
529529 *
530530 * @return boolean
531531 * @access public
@@ -582,7 +582,7 @@
583583 *
584584 * @param string $key Key to set value as
585585 * @param mixed $value Value to set
586 - * @param interger $exp (optional) Experiation time
 586+ * @param integer $exp (optional) Experiation time
587587 *
588588 * @return boolean TRUE on success
589589 * @access public
@@ -598,7 +598,7 @@
599599 /**
600600 * Sets the compression threshold
601601 *
602 - * @param interger $thresh Threshold to compress if larger than
 602+ * @param integer $thresh Threshold to compress if larger than
603603 *
604604 * @access public
605605 */
@@ -687,7 +687,7 @@
688688 /**
689689 * Connects $sock to $host, timing out after $timeout
690690 *
691 - * @param interger $sock Socket to connect
 691+ * @param integer $sock Socket to connect
692692 * @param string $host Host:IP to connect to
693693 *
694694 * @return boolean
@@ -807,11 +807,11 @@
808808 // {{{ _hashfunc()
809809
810810 /**
811 - * Creates a hash interger based on the $key
 811+ * Creates a hash integer based on the $key
812812 *
813813 * @param string $key Key to hash
814814 *
815 - * @return interger Hash value
 815+ * @return integer Hash value
816816 * @access private
817817 */
818818 function _hashfunc ($key)
@@ -830,9 +830,9 @@
831831 *
832832 * @param string $cmd Command to perform
833833 * @param string $key Key to perform it on
834 - * @param interger $amt Amount to adjust
 834+ * @param integer $amt Amount to adjust
835835 *
836 - * @return interger New value of $key
 836+ * @return integer New value of $key
837837 * @access private
838838 */
839839 function _incrdecr ($cmd, $key, $amt=1)
@@ -929,7 +929,7 @@
930930 * @param string $cmd Command to perform
931931 * @param string $key Key to act on
932932 * @param mixed $val What we need to store
933 - * @param interger $exp When it should expire
 933+ * @param integer $exp When it should expire
934934 *
935935 * @return boolean
936936 * @access private
Index: branches/phase3_rev_deleted/includes/SpecialImport.php
@@ -328,12 +328,9 @@
329329 } else {
330330 $created = false;
331331
332 - $result = $dbw->select( 'revision',
333 - array('MIN(rev_timestamp) as created', 'MAX(rev_timestamp) as latest'),
334 - array( 'rev_page' => $pageId ), __METHOD__ );
335 - $row = $dbw->fetchObject($result);
336 - // Don't make fucked up alternating page histories
337 - if( $row && $row->latest > $this->timestamp && $row->created < $this->timestamp ) {
 332+ $prior = Revision::loadFromTimestamp( $dbw, $this->title, $this->timestamp );
 333+ if( !is_null( $prior ) ) {
 334+ // FIXME: this could fail slightly for multiple matches :P
338335 wfDebug( __METHOD__ . ": skipping existing revision for [[" .
339336 $this->title->getPrefixedText() . "]], timestamp " .
340337 $this->timestamp . "\n" );
@@ -860,13 +857,13 @@
861858 }
862859 }
863860
864 - function newFromURL( $url ) {
 861+ function newFromURL( $url, $method = 'GET' ) {
865862 wfDebug( __METHOD__ . ": opening $url\n" );
866863 # Use the standard HTTP fetch function; it times out
867864 # quicker and sorts out user-agent problems which might
868865 # otherwise prevent importing from large sites, such
869866 # as the Wikimedia cluster, etc.
870 - $data = Http::get( $url );
 867+ $data = Http::request( $method, $url );
871868 if( $data !== false ) {
872869 $file = tmpfile();
873870 fwrite( $file, $data );
@@ -885,7 +882,8 @@
886883 } else {
887884 $params = $history ? 'history=1' : '';
888885 $url = $link->getFullUrl( $params );
889 - return ImportStreamSource::newFromURL( $url );
 886+ # For interwikis, use POST to avoid redirects.
 887+ return ImportStreamSource::newFromURL( $url, "POST" );
890888 }
891889 }
892890 }
Index: branches/phase3_rev_deleted/includes/SpecialPage.php
@@ -275,6 +275,30 @@
276276 }
277277
278278 /**
 279+ * Check if a given name exist as a special page or as a special page alias
 280+ * @param $name string: name of a special page
 281+ * @return boolean: true if a special page exists with this name
 282+ */
 283+ static function exists( $name ) {
 284+ global $wgContLang;
 285+ if ( !self::$mListInitialised ) {
 286+ self::initList();
 287+ }
 288+ if( !self::$mAliases ) {
 289+ self::initAliasList();
 290+ }
 291+
 292+ # Remove special pages inline parameters:
 293+ $bits = explode( '/', $name );
 294+ $name = $wgContLang->caseFold($bits[0]);
 295+
 296+ return
 297+ array_key_exists( $name, self::$mList )
 298+ or array_key_exists( $name, self::$mAliases )
 299+ ;
 300+ }
 301+
 302+ /**
279303 * Find the object with a given name and return it (or NULL)
280304 * @static
281305 * @param string $name
@@ -423,7 +447,7 @@
424448 wfProfileOut( __METHOD__ );
425449 return false;
426450 } elseif ( !$including ) {
427 - $wgTitle = $page->getTitle( $par );
 451+ $wgTitle = $page->getTitle();
428452 }
429453 $page->including( $including );
430454
Index: branches/phase3_rev_deleted/languages/messages/MessagesEn.php
@@ -282,6 +282,8 @@
283283 'img_center' => array( 1, 'center', 'centre' ),
284284 'img_framed' => array( 1, 'framed', 'enframed', 'frame' ),
285285 'img_page' => array( 1, 'page=$1', 'page $1' ),
 286+ 'img_upright' => array( 1, 'upright', 'upright=$1', 'upright $1' ),
 287+ 'img_border' => array( 1, 'border' ),
286288 'img_baseline' => array( 1, 'baseline' ),
287289 'img_sub' => array( 1, 'sub' ),
288290 'img_super' => array( 1, 'super', 'sup' ),
@@ -765,7 +767,9 @@
766768 'unexpected' => 'Unexpected value: "$1"="$2".',
767769 'formerror' => 'Error: could not submit form',
768770 'badarticleerror' => 'This action cannot be performed on this page.',
769 -'cannotdelete' => 'Could not delete the page or file specified. (It may have already been deleted by someone else.)',
 771+'cannotdelete' => 'Could not delete the page or file specified. It may have already been deleted by someone else.<br/>
 772+Pages will not be deleted if it will result in an alternating archive history between these and any archived
 773+revisions for this page. If such is the case, please move this page to another location and delete it there.',
770774 'badtitle' => 'Bad title',
771775 'badtitletext' => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title. It may contain one or more characters which cannot be used in titles.',
772776 'perfdisabled' => 'Sorry! This feature has been temporarily disabled because it slows the database down to the point that no one can use the wiki.',
@@ -1150,10 +1154,8 @@
11511155 the search function at [[Special:Undelete]].
11521156
11531157 Blocked users listed here can cannot edit their talk pages and thus can only communicate via email. Their accounts
1154 -will remain hidden only as long as they are blocked.
 1158+will remain hidden only as long as they are blocked.',
11551159
1156 -Content listed here should never be released to the general public unless it was hidden by mistake.',
1157 -
11581160 # Diffs
11591161 #
11601162 'difference' => '(Difference between revisions)',
@@ -1767,7 +1769,9 @@
17681770 'enotif_subject' => '{{SITENAME}} page $PAGETITLE has been $CHANGEDORCREATED by $PAGEEDITOR',
17691771 'enotif_lastvisited' => 'See $1 for all changes since your last visit.',
17701772 'enotif_lastdiff' => 'See $1 to view this change.',
 1773+'enotif_anon_editor' => 'anonymous user $1',
17711774 'enotif_body' => 'Dear $WATCHINGUSERNAME,
 1775+
17721776
17731777 The {{SITENAME}} page $PAGETITLE has been $CHANGEDORCREATED on $PAGEEDITDATE by $PAGEEDITOR, see $PAGETITLE_URL for the current version.
17741778
@@ -2928,6 +2932,11 @@
29292933 'livepreview-failed' => "Live preview failed!\nTry normal preview.",
29302934 'livepreview-error' => "Failed to connect: $1 \"$2\"\nTry normal preview.",
29312935
 2936+# Friendlier slave lag warnings
 2937+'lag-warn-normal' => 'Changes newer than $1 seconds may not be shown in this list.',
 2938+'lag-warn-high' => 'Due to high database server lag, changes newer than $1 seconds
 2939+may not be shown in this list.',
 2940+
29322941 );
29332942
29342943 ?>