Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 168 |
|
0.00% |
0 / 22 |
CRAP | |
0.00% |
0 / 2 |
NSLocalFile | |
0.00% |
0 / 134 |
|
0.00% |
0 / 19 |
2162 | |
0.00% |
0 / 1 |
getRel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getThumbRel | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getArchiveRel | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getUrlRel | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getThumbUrl | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
thumbName | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
generateThumbName | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
getArchiveUrl | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getArchiveThumbRel | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getArchiveThumbUrl | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
purgeThumbList | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
30 | |||
getArchiveVirtualUrl | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getThumbVirtualUrl | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getFileNameStripped | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
publishTo | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
move | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
newFromTitle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
newFromRow | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
newFromKey | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
NSLocalFileMoveBatch | |
0.00% |
0 / 34 |
|
0.00% |
0 / 3 |
56 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
addOlds | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
30 | |||
getFileNameStripped | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | class NSLocalFile extends LocalFile { |
4 | /** |
5 | * Get the path of the file relative to the public zone root |
6 | */ |
7 | function getRel() { |
8 | return $this->getHashPath() . self::getFileNameStripped( $this->getName() ); |
9 | } |
10 | /** |
11 | * Get the path, relative to the thumbnail zone root, of the |
12 | * thumbnail directory or a particular file if $suffix is specified |
13 | * |
14 | * @param $suffix bool|string if not false, the name of a thumbnail file |
15 | * |
16 | * @return string |
17 | */ |
18 | function getThumbRel( $suffix = false ) { |
19 | $path = $this->getRel(); |
20 | if ( $suffix !== false ) { |
21 | /* This is the part that changed from LocalFile */ |
22 | $path .= '/' . self::getFileNameStripped( $suffix ); |
23 | /* End of changes */ |
24 | } |
25 | return $path; |
26 | } |
27 | |
28 | /** |
29 | * Get the path of an archived file relative to the public zone root |
30 | * |
31 | * @param $suffix bool|string if not false, the name of an archived thumbnail file |
32 | * |
33 | * @return string |
34 | */ |
35 | function getArchiveRel( $suffix = false ) { |
36 | $path = 'archive/' . $this->getHashPath(); |
37 | if ( $suffix === false ) { |
38 | $path = substr( $path, 0, -1 ); |
39 | } else { |
40 | /* This is the part that changed from LocalFile */ |
41 | $path .= '/' . self::getFileNameStripped( $suffix ); |
42 | /* End of changes */ |
43 | } |
44 | return $path; |
45 | } |
46 | |
47 | |
48 | |
49 | /** |
50 | * Get urlencoded relative path of the file |
51 | */ |
52 | function getUrlRel() { |
53 | return $this->getHashPath() . |
54 | rawurlencode( self::getFileNameStripped( $this->getName() ) ); |
55 | } |
56 | |
57 | /** |
58 | * Get the URL of the thumbnail directory, or a particular file if $suffix is specified |
59 | * |
60 | * @param $suffix bool|string if not false, the name of a thumbnail file |
61 | * |
62 | * @return string path |
63 | */ |
64 | function getThumbUrl( $suffix = false ) { |
65 | $path = $this->repo->getZoneUrl('thumb') . '/' . $this->getUrlRel(); |
66 | if ( $suffix !== false ) { |
67 | $path .= '/' . rawurlencode( self::getFileNameStripped( $suffix ) ); |
68 | } |
69 | return $path; |
70 | } |
71 | |
72 | |
73 | public function thumbName( $params, $flags = 0 ) { |
74 | $name = ( $this->repo && !( $flags & self::THUMB_FULL_NAME ) ) |
75 | /* This is the part that changed from LocalFile */ |
76 | ? $this->repo->nameForThumb( self::getFileNameStripped( $this->getName() ) ) |
77 | : self::getFileNameStripped( $this->getName() ); |
78 | /* End of changes */ |
79 | return $this->generateThumbName( $name, $params ); |
80 | } |
81 | |
82 | /** |
83 | * Generate a thumbnail file name from a name and specified parameters |
84 | * |
85 | * @param string $name |
86 | * @param array $params Parameters which will be passed to MediaHandler::makeParamString |
87 | * |
88 | * @return string |
89 | */ |
90 | public function generateThumbName( $name, $params ) { |
91 | if ( !$this->getHandler() ) { |
92 | return null; |
93 | } |
94 | $extension = $this->getExtension(); |
95 | list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( |
96 | $extension, $this->getMimeType(), $params ); |
97 | /* This is the part that changed from LocalFile */ |
98 | $thumbName = $this->handler->makeParamString( $params ) . '-' . |
99 | self::getFileNameStripped( $this->getName() ); |
100 | /* End of changes */ |
101 | if ( $thumbExt != $extension ) { |
102 | $thumbName .= ".$thumbExt"; |
103 | } |
104 | /* And also need to retain namespace changed from LocalFile */ |
105 | $bits = explode( ':',$this->getName() ); |
106 | if ( count($bits) > 1 ) $thumbName = $bits[0] . ":" . $thumbName; |
107 | /* End of changes */ |
108 | return $thumbName; |
109 | } |
110 | |
111 | /** |
112 | * Get the URL of the archive directory, or a particular file if $suffix is specified |
113 | * |
114 | * @param $suffix bool|string if not false, the name of an archived file |
115 | * |
116 | * @return string |
117 | */ |
118 | function getArchiveUrl( $suffix = false ) { |
119 | $this->assertRepoDefined(); |
120 | $ext = $this->getExtension(); |
121 | $path = $this->repo->getZoneUrl( 'public', $ext ) . '/archive/' . $this->getHashPath(); |
122 | if ( $suffix === false ) { |
123 | $path = substr( $path, 0, -1 ); |
124 | } else { |
125 | /* This is the part that changed from LocalFile */ |
126 | $path .= rawurlencode( self::getFileNameStripped( $suffix ) ); |
127 | /* End of changes */ |
128 | } |
129 | return $path; |
130 | } |
131 | |
132 | /** |
133 | * Get the path, relative to the thumbnail zone root, for an archived file's thumbs directory |
134 | * or a specific thumb if the $suffix is given. |
135 | * |
136 | * @param string $archiveName The timestamped name of an archived image |
137 | * @param bool|string $suffix If not false, the name of a thumbnail file |
138 | * @return string |
139 | */ |
140 | function getArchiveThumbRel( $archiveName, $suffix = false ) { |
141 | $path = 'archive/' . $this->getHashPath() . $archiveName . "/"; |
142 | if ( $suffix === false ) { |
143 | $path = substr( $path, 0, -1 ); |
144 | } else { |
145 | /* This is the part that changed from LocalFile */ |
146 | $path .= self::getFileNameStripped( $suffix ); |
147 | /* End of changes */ |
148 | } |
149 | |
150 | return $path; |
151 | } |
152 | |
153 | /** |
154 | * Get the URL of the archived file's thumbs, or a particular thumb if $suffix is specified |
155 | * |
156 | * @param string $archiveName The timestamped name of an archived image |
157 | * @param bool|string $suffix If not false, the name of a thumbnail file |
158 | * @return string |
159 | */ |
160 | function getArchiveThumbUrl( $archiveName, $suffix = false ) { |
161 | $this->assertRepoDefined(); |
162 | $ext = $this->getExtension(); |
163 | $path = $this->repo->getZoneUrl( 'thumb', $ext ) . '/archive/' . |
164 | $this->getHashPath() . rawurlencode( $archiveName ) . "/"; |
165 | if ( $suffix === false ) { |
166 | $path = substr( $path, 0, -1 ); |
167 | } else { |
168 | /* This is the part that changed from LocalFile */ |
169 | $path .= rawurlencode( self::getFileNameStripped( $suffix ) ); |
170 | /* End of changes */ |
171 | } |
172 | |
173 | return $path; |
174 | } |
175 | |
176 | /** |
177 | * Delete cached transformed files for the current version only. |
178 | * @param array $options |
179 | */ |
180 | protected function purgeThumbList( $dir, $files ) { |
181 | |
182 | $purgeList = []; |
183 | foreach ( $files as $file ) { |
184 | if ( $this->repo->supportsSha1URLs() ) { |
185 | $reference = $this->getSha1(); |
186 | } else { |
187 | //change from LocalFile.php here |
188 | $reference = $this->getFileNameStripped($this->getName()); |
189 | } |
190 | |
191 | # Check that the reference (filename or sha1) is part of the thumb name |
192 | # This is a basic sanity check to avoid erasing unrelated directories |
193 | if ( strpos( $file, $reference ) !== false |
194 | || strpos( $file, "-thumbnail" ) !== false // "short" thumb name |
195 | ) { |
196 | $purgeList[] = "{$dir}/{$file}"; |
197 | } |
198 | } |
199 | |
200 | # Delete the thumbnails |
201 | $this->repo->quickPurgeBatch( $purgeList ); |
202 | # Clear out the thumbnail directory if empty |
203 | $this->repo->quickCleanDir( $dir ); |
204 | } |
205 | /** |
206 | * Get the public zone virtual URL for an archived version source file |
207 | * |
208 | * @param $suffix bool|string if not false, the name of a thumbnail file |
209 | * |
210 | * @return string |
211 | */ |
212 | function getArchiveVirtualUrl( $suffix = false ) { |
213 | $this->assertRepoDefined(); |
214 | $path = $this->repo->getVirtualUrl() . '/public/archive/' . $this->getHashPath(); |
215 | if ( $suffix === false ) { |
216 | $path = substr( $path, 0, -1 ); |
217 | } else { |
218 | /* This is the part that changed from LocalFile */ |
219 | $path .= rawurlencode( self::getFileNameStripped( $suffix ) ); |
220 | /* End of changes */ |
221 | } |
222 | return $path; |
223 | } |
224 | |
225 | /** |
226 | * Get the virtual URL for a thumbnail file or directory |
227 | * |
228 | * @param $suffix bool|string if not false, the name of a thumbnail file |
229 | * |
230 | * @return string |
231 | */ |
232 | function getThumbVirtualUrl( $suffix = false ) { |
233 | $this->assertRepoDefined(); |
234 | $path = $this->repo->getVirtualUrl() . '/thumb/' . $this->getUrlRel(); |
235 | if ( $suffix !== false ) { |
236 | $path .= '/' . rawurlencode( $suffix ); |
237 | /* This is the part that changed from LocalFile */ |
238 | $path .= '/' . rawurlencode( self::getFileNameStripped( $suffix ) ); |
239 | /* End of changes */ |
240 | } |
241 | return $path; |
242 | } |
243 | |
244 | /** |
245 | * Strip namespace (if any) from file name |
246 | * |
247 | * @param $suffix the name of a thumbnail file |
248 | * |
249 | * @return string |
250 | */ |
251 | public static function getFileNameStripped($suffix) { |
252 | $iNsEndPos = strpos( $suffix, ":"); |
253 | if( $iNsEndPos ){ |
254 | $sRes = ''; |
255 | $iTsEndPos = strpos( $suffix, "!" ); |
256 | |
257 | if( $iTsEndPos ) { |
258 | $sRes = substr( $suffix, 0, $iTsEndPos +1 ); |
259 | } |
260 | $sRes .= substr( $suffix, $iNsEndPos +1, strlen( $suffix ) -1 ); |
261 | |
262 | return $sRes; |
263 | } else { |
264 | return $suffix; |
265 | } |
266 | } |
267 | |
268 | /** |
269 | * Move or copy a file to a specified location. Returns a FileRepoStatus |
270 | * object with the archive name in the "value" member on success. |
271 | * |
272 | * The archive name should be passed through to recordUpload for database |
273 | * registration. |
274 | * |
275 | * @param $srcPath String: local filesystem path to the source image |
276 | * @param $dstRel String: target relative path |
277 | * @param $flags Integer: a bitwise combination of: |
278 | * File::DELETE_SOURCE Delete the source file, i.e. move rather than copy |
279 | * @param $options array Optional additional parameters |
280 | * @return Status object. On success, the value member contains the |
281 | * archive name, or an empty string if it was a new file. |
282 | */ |
283 | function publishTo( $srcPath, $dstRel, $flags = 0, array $options = array() ) { |
284 | if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
285 | return $this->readOnlyFatalStatus(); |
286 | } |
287 | |
288 | $this->lock(); // begin |
289 | |
290 | $archiveName = wfTimestamp( TS_MW ) . '!'. $this->getName(); |
291 | /* This is the part that changed from LocalFile */ |
292 | $strippedArchiveName = wfTimestamp( TS_MW ) . '!'. self::getFileNameStripped( $this->getName() ); |
293 | $archiveRel = 'archive/' . $this->getHashPath() . $strippedArchiveName; |
294 | /* End of changes */ |
295 | $flags = $flags & File::DELETE_SOURCE ? LocalRepo::DELETE_SOURCE : 0; |
296 | $status = $this->repo->publish( $srcPath, $dstRel, $archiveRel, $flags, $options ); |
297 | |
298 | if ( $status->value == 'new' ) { |
299 | $status->value = ''; |
300 | } else { |
301 | $status->value = $archiveName; |
302 | } |
303 | |
304 | $this->purgeThumbnails(); |
305 | $this->unlock(); // done |
306 | |
307 | return $status; |
308 | } |
309 | |
310 | /** |
311 | * Move file to the new title |
312 | * |
313 | * Move current, old version and all thumbnails |
314 | * to the new filename. Old file is deleted. |
315 | * |
316 | * Cache purging is done; checks for validity |
317 | * and logging are caller's responsibility |
318 | * |
319 | * @param $target Title New file name |
320 | * @return Status object. |
321 | */ |
322 | function move( $target ) { |
323 | if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
324 | return $this->readOnlyFatalStatus(); |
325 | } |
326 | |
327 | wfDebugLog( 'imagemove', "Got request to move {$this->name} to " . $target->getText() ); |
328 | /* This is the part that changed from LocalFile */ |
329 | $batch = new NSLocalFileMoveBatch( $this, $target ); |
330 | /* End of changes */ |
331 | |
332 | $this->lock(); // begin |
333 | $batch->addCurrent(); |
334 | $archiveNames = $batch->addOlds(); |
335 | $status = $batch->execute(); |
336 | $this->unlock(); // done |
337 | |
338 | wfDebugLog( 'imagemove', "Finished moving {$this->name}" ); |
339 | |
340 | $this->purgeEverything(); |
341 | foreach ( $archiveNames as $archiveName ) { |
342 | $this->purgeOldThumbnails( $archiveName ); |
343 | } |
344 | if ( $status->isOK() ) { |
345 | // Now switch the object |
346 | $this->title = $target; |
347 | // Force regeneration of the name and hashpath |
348 | unset( $this->name ); |
349 | unset( $this->hashPath ); |
350 | // Purge the new image |
351 | $this->purgeEverything(); |
352 | } |
353 | |
354 | return $status; |
355 | } |
356 | |
357 | |
358 | /** Instantiating this class using "self" |
359 | * If you're reading this, you're problably wondering why on earth are the following static functions, which are copied |
360 | * verbatim from the original extended class "LocalFIle" included here? |
361 | * The answer is that "self", will instantiate the class the code is physically in, not the class extended from it. |
362 | * Without the inclusion of these methods in "NSLocalFile, "self" would instantiate a "LocalFile" class, not the |
363 | * "NSLocalFile" class we want it to. Since there are only two methods within the "LocalFile" class that use "self", |
364 | * I just copied that code into the new "NSLocalFile" extended class, and the copied code will instantiate the "NSLocalFIle" |
365 | * class instead of the "LocalFile" class (at least in PHP 5.2.4) |
366 | */ |
367 | |
368 | /** |
369 | * Create a NSLocalFile from a title |
370 | * Do not call this except from inside a repo class. |
371 | * |
372 | * Note: $unused param is only here to avoid an E_STRICT |
373 | */ |
374 | static function newFromTitle( $title, $repo, $unused = null ) { |
375 | return new self( $title, $repo ); |
376 | } |
377 | /** |
378 | * Create a NSLocalFile from a title |
379 | * Do not call this except from inside a repo class. |
380 | */ |
381 | |
382 | static function newFromRow( $row, $repo ) { |
383 | $title = Title::makeTitle( NS_FILE, $row->img_name ); |
384 | $file = new self( $title, $repo ); |
385 | $file->loadFromRow( $row ); |
386 | return $file; |
387 | } |
388 | |
389 | /** |
390 | * Create a NSLocalFile from a SHA-1 key |
391 | * Do not call this except from inside a repo class. |
392 | * |
393 | * Copy & paste from LocalFile to fix "late-static-binding" issue |
394 | * |
395 | * @param string $sha1 Base-36 SHA-1 |
396 | * @param LocalRepo $repo |
397 | * @param string|bool $timestamp MW_timestamp (optional) |
398 | * @return bool|LocalFile |
399 | */ |
400 | static function newFromKey( $sha1, $repo, $timestamp = false ) { |
401 | $dbr = $repo->getReplicaDB(); |
402 | |
403 | $conds = [ 'img_sha1' => $sha1 ]; |
404 | if ( $timestamp ) { |
405 | $conds['img_timestamp'] = $dbr->timestamp( $timestamp ); |
406 | } |
407 | |
408 | $fileQuery = static::getQueryInfo(); |
409 | $row = $dbr->selectRow( |
410 | $fileQuery['tables'], $fileQuery['fields'], $conds, __METHOD__, [], $fileQuery['joins'] |
411 | ); |
412 | if ( $row ) { |
413 | return static::newFromRow( $row, $repo ); |
414 | } else { |
415 | return false; |
416 | } |
417 | } |
418 | } |
419 | |
420 | /** |
421 | * Helper class for file movement |
422 | * @ingroup FileAbstraction |
423 | */ |
424 | class NSLocalFileMoveBatch extends LocalFileMoveBatch { |
425 | /** |
426 | * @param File $file |
427 | * @param Title $target |
428 | */ |
429 | public function __construct( LocalFile $file, Title $target ) { |
430 | parent::__construct( $file, $target ); |
431 | $this->oldRel = $this->oldHash . NSLocalFile::getFileNameStripped( $this->oldName ); |
432 | $this->newRel = $this->newHash . NSLocalFile::getFileNameStripped( $this->newName ); |
433 | } |
434 | |
435 | /** |
436 | * Add the old versions of the image to the batch |
437 | * @return array List of archive names from old versions |
438 | */ |
439 | function addOlds() { |
440 | /* This is the part that changed from LocalFile */ |
441 | $newName = $this->getFileNameStripped( $this->newName ); |
442 | /* End of changes */ |
443 | $archiveBase = 'archive'; |
444 | $this->olds = array(); |
445 | $this->oldCount = 0; |
446 | $archiveNames = array(); |
447 | |
448 | $result = $this->db->select( 'oldimage', |
449 | array( 'oi_archive_name', 'oi_deleted' ), |
450 | array( 'oi_name' => $this->oldName ), |
451 | __METHOD__ |
452 | ); |
453 | |
454 | foreach ( $result as $row ) { |
455 | $archiveNames[] = $row->oi_archive_name; |
456 | $oldName = $row->oi_archive_name; |
457 | $bits = explode( '!', $oldName, 2 ); |
458 | |
459 | if ( count( $bits ) != 2 ) { |
460 | wfDebug( "Old file name missing !: '$oldName' \n" ); |
461 | continue; |
462 | } |
463 | |
464 | list( $timestamp, $filename ) = $bits; |
465 | |
466 | if ( $this->oldName != $filename ) { |
467 | wfDebug( "Old file name doesn't match: '$oldName' \n" ); |
468 | continue; |
469 | } |
470 | /* This is the part that changed from LocalFileMoveBatch */ |
471 | #When file is moved within a namespace we do not want it |
472 | #looking to NS:Name format in FS |
473 | $strippedOldName = $this->file->getFileNameStripped( $oldName ); |
474 | /* End of changes */ |
475 | |
476 | $this->oldCount++; |
477 | |
478 | // Do we want to add those to oldCount? |
479 | if ( $row->oi_deleted & File::DELETED_FILE ) { |
480 | continue; |
481 | } |
482 | /* This is the part that changed from LocalFile */ |
483 | $this->olds[] = array( |
484 | "{$archiveBase}/{$this->oldHash}{$strippedOldName}", |
485 | "{$archiveBase}/{$this->newHash}{$timestamp}!{$newName}" |
486 | ); |
487 | /* End of changes */ |
488 | } |
489 | |
490 | return $archiveNames; |
491 | } |
492 | |
493 | function getFileNameStripped( $suffix ) { |
494 | return(NSLocalFile::getFileNameStripped($suffix)); |
495 | } |
496 | } |