Index: branches/FileBackend/phase3/includes/filerepo/file/TempLocalFile.php |
— | — | @@ -1,46 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * @file |
5 | | - * @ingroup FileRepo |
6 | | - */ |
7 | | - |
8 | | -/** |
9 | | - * This class is used to hold the location and do limited manipulation |
10 | | - * of files stored temporarily (usually this will be $wgTmpDirectory) |
11 | | - */ |
12 | | -class TempLocalFile { |
13 | | - protected $path; // path to local temp file directory |
14 | | - protected $canDelete; // whether this object should garbage collect the temp file |
15 | | - |
16 | | - /** |
17 | | - * Sets up the temporary file object |
18 | | - * |
19 | | - * @param String $path Path to temporary file on local disk |
20 | | - * @param Boolean $canDelete Whether this object should garbage collect the temp file |
21 | | - */ |
22 | | - public function __construct( $path, $canDelete = true ) { |
23 | | - $this->path = $path; |
24 | | - $this->canDelete = $canDelete; |
25 | | - } |
26 | | - |
27 | | - /** |
28 | | - * Returns the local path to the temp file |
29 | | - * |
30 | | - * @return String |
31 | | - */ |
32 | | - public function getPath() { |
33 | | - return $this->path; |
34 | | - } |
35 | | - |
36 | | - /** |
37 | | - * Cleans up after the temporary file. |
38 | | - * Currently this means removing it from the local disk. |
39 | | - */ |
40 | | - function __destruct() { |
41 | | - if ( $this->canDelete ) { |
42 | | - wfSuppressWarnings(); |
43 | | - unlink( $this->path ); |
44 | | - wfRestoreWarnings(); |
45 | | - } |
46 | | - } |
47 | | -} |
Index: branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php |
— | — | @@ -0,0 +1,36 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup FileRepo |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * This class is used to hold the location and do limited manipulation |
| 10 | + * of files stored temporarily (usually this will be $wgTmpDirectory) |
| 11 | + */ |
| 12 | +class TempFSFile extends FSFile { |
| 13 | + protected $canDelete; // whether this object should garbage collect the temp file |
| 14 | + |
| 15 | + /** |
| 16 | + * Sets up the temporary file object |
| 17 | + * |
| 18 | + * @param String $path Path to temporary file on local disk |
| 19 | + * @param Boolean $canDelete Whether this object should garbage collect the temp file |
| 20 | + */ |
| 21 | + public function __construct( $path, $canDelete = true ) { |
| 22 | + $this->path = $path; |
| 23 | + $this->canDelete = $canDelete; |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Cleans up after the temporary file. |
| 28 | + * Currently this means removing it from the local disk. |
| 29 | + */ |
| 30 | + function __destruct() { |
| 31 | + if ( $this->canDelete ) { |
| 32 | + wfSuppressWarnings(); |
| 33 | + unlink( $this->path ); |
| 34 | + wfRestoreWarnings(); |
| 35 | + } |
| 36 | + } |
| 37 | +} |
Property changes on: branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 38 | + native |
Index: branches/FileBackend/phase3/includes/filerepo/file/FSFile.php |
— | — | @@ -0,0 +1,144 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup FileRepo |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * Class representing a non-directory file on the file system |
| 10 | + */ |
| 11 | +class FSFile { |
| 12 | + protected $path; // path to file |
| 13 | + |
| 14 | + /** |
| 15 | + * Sets up the file object |
| 16 | + * |
| 17 | + * @param String $path Path to temporary file on local disk |
| 18 | + */ |
| 19 | + public function __construct( $path ) { |
| 20 | + $this->path = $path; |
| 21 | + } |
| 22 | + |
| 23 | + /** |
| 24 | + * Returns the file system path |
| 25 | + * |
| 26 | + * @return String |
| 27 | + */ |
| 28 | + public function getPath() { |
| 29 | + return $this->path; |
| 30 | + } |
| 31 | + |
| 32 | + /** |
| 33 | + * Checks if the file exists |
| 34 | + * |
| 35 | + * @return bool |
| 36 | + */ |
| 37 | + public function exists() { |
| 38 | + return ( file_exists( $this->path ) && !is_dir( $this->path ) ); |
| 39 | + } |
| 40 | + |
| 41 | + /** |
| 42 | + * Get an associative array containing information about |
| 43 | + * a file with the given storage path. |
| 44 | + * |
| 45 | + * @param $ext Mixed: the file extension, or true to extract it from the filename. |
| 46 | + * Set it to false to ignore the extension. |
| 47 | + * |
| 48 | + * @return array |
| 49 | + */ |
| 50 | + public function getProps( $ext = true ) { |
| 51 | + wfProfileIn( __METHOD__ ); |
| 52 | + wfDebug( __METHOD__.": Getting file info for $this->path\n" ); |
| 53 | + |
| 54 | + $info = self::placeholderProps(); |
| 55 | + $info['fileExists'] = $this->exists(); |
| 56 | + |
| 57 | + if ( $info['fileExists'] ) { |
| 58 | + $magic = MimeMagic::singleton(); |
| 59 | + |
| 60 | + # get the file extension |
| 61 | + if ( $ext === true ) { |
| 62 | + $i = strrpos( $this->path, '.' ); |
| 63 | + $ext = strtolower( $i ? substr( $this->path, $i + 1 ) : '' ); |
| 64 | + } |
| 65 | + |
| 66 | + # mime type according to file contents |
| 67 | + $info['file-mime'] = $magic->guessMimeType( $this->path, false ); |
| 68 | + # logical mime type |
| 69 | + $info['mime'] = $magic->improveTypeFromExtension( $info['file-mime'], $ext ); |
| 70 | + |
| 71 | + list( $info['major_mime'], $info['minor_mime'] ) = self::splitMime( $info['mime'] ); |
| 72 | + $info['media_type'] = $magic->getMediaType( $this->path, $info['mime'] ); |
| 73 | + |
| 74 | + # Get size in bytes |
| 75 | + $info['size'] = filesize( $this->path ); |
| 76 | + |
| 77 | + # Height, width and metadata |
| 78 | + $handler = MediaHandler::getHandler( $info['mime'] ); |
| 79 | + if ( $handler ) { |
| 80 | + $tempImage = (object)array(); |
| 81 | + $info['metadata'] = $handler->getMetadata( $tempImage, $this->path ); |
| 82 | + $gis = $handler->getImageSize( $tempImage, $this->path, $info['metadata'] ); |
| 83 | + if ( is_array( $gis ) ) { |
| 84 | + $info = $this->extractImageSizeInfo() + $info; |
| 85 | + } |
| 86 | + } |
| 87 | + $info['sha1'] = $this->sha1Base36(); |
| 88 | + |
| 89 | + wfDebug(__METHOD__.": $this->path loaded, {$info['size']} bytes, {$info['mime']}.\n"); |
| 90 | + } else { |
| 91 | + wfDebug(__METHOD__.": $this->path NOT FOUND!\n"); |
| 92 | + } |
| 93 | + |
| 94 | + wfProfileOut( __METHOD__ ); |
| 95 | + return $info; |
| 96 | + } |
| 97 | + |
| 98 | + public static function placeholderProps() { |
| 99 | + $info = array(); |
| 100 | + $info['mime'] = null; |
| 101 | + $info['media_type'] = MEDIATYPE_UNKNOWN; |
| 102 | + $info['metadata'] = ''; |
| 103 | + $info['sha1'] = ''; |
| 104 | + $info['width'] = 0; |
| 105 | + $info['height'] = 0; |
| 106 | + $info['bits'] = 0; |
| 107 | + return $info; |
| 108 | + } |
| 109 | + |
| 110 | + protected function extractImageSizeInfo( array $gis ) { |
| 111 | + $info = array(); |
| 112 | + # NOTE: $gis[2] contains a code for the image type. This is no longer used. |
| 113 | + $info['width'] = $gis[0]; |
| 114 | + $info['height'] = $gis[1]; |
| 115 | + if ( isset( $gis['bits'] ) ) { |
| 116 | + $info['bits'] = $gis['bits']; |
| 117 | + } else { |
| 118 | + $info['bits'] = 0; |
| 119 | + } |
| 120 | + return $info; |
| 121 | + } |
| 122 | + |
| 123 | + /** |
| 124 | + * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case |
| 125 | + * encoding, zero padded to 31 digits. |
| 126 | + * |
| 127 | + * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36 |
| 128 | + * fairly neatly. |
| 129 | + * |
| 130 | + * @return false|string False on failure |
| 131 | + */ |
| 132 | + public function sha1Base36() { |
| 133 | + wfProfileIn( __METHOD__ ); |
| 134 | + |
| 135 | + wfSuppressWarnings(); |
| 136 | + $hash = sha1_file( $this->path ); |
| 137 | + wfRestoreWarnings(); |
| 138 | + if ( $hash !== false ) { |
| 139 | + $hash = wfBaseConvert( $hash, 16, 36, 31 ); |
| 140 | + } |
| 141 | + |
| 142 | + wfProfileOut( __METHOD__ ); |
| 143 | + return $hash; |
| 144 | + } |
| 145 | +} |
Property changes on: branches/FileBackend/phase3/includes/filerepo/file/FSFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 146 | + native |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php |
— | — | @@ -15,9 +15,8 @@ |
16 | 16 | protected $fileMode; // file permission mode |
17 | 17 | |
18 | 18 | function __construct( array $config ) { |
19 | | - $this->name = $config['name']; |
| 19 | + parent::__construct( $config ); |
20 | 20 | $this->containerPaths = (array)$config['containerPaths']; |
21 | | - $this->lockManager = $config['lockManager']; |
22 | 21 | $this->fileMode = isset( $config['fileMode'] ) |
23 | 22 | ? $config['fileMode'] |
24 | 23 | : 0644; |
— | — | @@ -359,7 +358,7 @@ |
360 | 359 | if ( $source === null ) { |
361 | 360 | return false; // invalid storage path |
362 | 361 | } |
363 | | - return file_exists( $source ); |
| 362 | + return file_exists( $source ) && is_file( $source ); |
364 | 363 | } |
365 | 364 | |
366 | 365 | function getHashType() { |
— | — | @@ -375,11 +374,12 @@ |
376 | 375 | } |
377 | 376 | |
378 | 377 | function getFileProps( array $params ) { |
379 | | - list( $c, $source ) = $this->resolveVirtualPath( $params['source'] ); |
380 | | - if ( $source === null ) { |
381 | | - return null; // invalid storage path |
| 378 | + $tmpFile = $this->getLocalCopy( $params ); |
| 379 | + if ( !$tmpFile ) { |
| 380 | + return FSFile::placeholderProps(); |
| 381 | + } else { |
| 382 | + return $tmpFile->getProps(); |
382 | 383 | } |
383 | | - return File::getPropsFromPath( $source ); |
384 | 384 | } |
385 | 385 | |
386 | 386 | function getFileList( array $params ) { |
— | — | @@ -414,13 +414,21 @@ |
415 | 415 | return null; |
416 | 416 | } |
417 | 417 | |
| 418 | + // Get source file extension |
| 419 | + $i = strrpos( $source, '.' ); |
| 420 | + $ext = strtolower( $i ? substr( $source, $i + 1 ) : '' ); |
418 | 421 | // Create a new temporary file... |
419 | 422 | wfSuppressWarnings(); |
420 | | - $tmpPath = tempnam( wfTempDir(), 'file_localcopy' ); |
| 423 | + $initialTmpPath = tempnam( wfTempDir(), 'file_localcopy' ); |
421 | 424 | wfRestoreWarnings(); |
422 | | - if ( $tmpPath === false ) { |
| 425 | + if ( $initialTmpPath === false ) { |
423 | 426 | return null; |
424 | 427 | } |
| 428 | + // Apply the original extension |
| 429 | + $tmpPath = "{$initialTmpPath}.{$ext}"; |
| 430 | + if ( !rename( $initialTmpPath, $tmpPath ) ) { |
| 431 | + return null; |
| 432 | + } |
425 | 433 | |
426 | 434 | // Copy the source file over the temp file |
427 | 435 | wfSuppressWarnings(); |
— | — | @@ -432,7 +440,7 @@ |
433 | 441 | |
434 | 442 | $this->chmod( $tmpPath ); |
435 | 443 | |
436 | | - return new TempLocalFile( $tmpPath ); |
| 444 | + return new TempFSFile( $tmpPath ); |
437 | 445 | } |
438 | 446 | |
439 | 447 | /** |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php |
— | — | @@ -33,7 +33,7 @@ |
34 | 34 | */ |
35 | 35 | public function __construct( array $config ) { |
36 | 36 | $this->name = $config['name']; |
37 | | - $this->lockManager = $config['lockManger']; |
| 37 | + $this->lockManager = $config['lockManager']; |
38 | 38 | } |
39 | 39 | |
40 | 40 | /** |
— | — | @@ -165,12 +165,13 @@ |
166 | 166 | abstract public function getFileList( array $params ); |
167 | 167 | |
168 | 168 | /** |
169 | | - * Get a local copy on disk of the file at a storage path in the backend |
| 169 | + * Get a local copy on disk of the file at a storage path in the backend. |
| 170 | + * The temporary copy should have the same file extension as the source. |
170 | 171 | * $params include: |
171 | 172 | * source : source storage path |
172 | 173 | * |
173 | 174 | * @param Array $params |
174 | | - * @return TempLocalFile|null Temporary file or null on failure |
| 175 | + * @return TempFSFile|null Temporary file or null on failure |
175 | 176 | */ |
176 | 177 | abstract public function getLocalCopy( array $params ); |
177 | 178 | |