MediaWiki  1.23.12
FileRepo.php
Go to the documentation of this file.
1 <?php
37 class FileRepo {
38  const DELETE_SOURCE = 1;
39  const OVERWRITE = 2;
40  const OVERWRITE_SAME = 4;
41  const SKIP_LOCKING = 8;
42 
43  const NAME_AND_TIME_ONLY = 1;
44 
47  public $fetchDescription;
48 
51 
53  protected $backend;
54 
56  protected $zones = array();
57 
59  protected $thumbScriptUrl;
60 
63  protected $transformVia404;
64 
68  protected $descBaseUrl;
69 
73  protected $scriptDirUrl;
74 
77  protected $scriptExtension;
78 
80  protected $articleUrl;
81 
87  protected $initialCapital;
88 
94  protected $pathDisclosureProtection = 'simple';
95 
97  protected $url;
98 
100  protected $thumbUrl;
101 
103  protected $hashLevels;
104 
106  protected $deletedHashLevels;
107 
112  protected $abbrvThreshold;
113 
115  protected $favicon;
116 
121  protected $fileFactory = array( 'UnregisteredLocalFile', 'newFromTitle' );
122  protected $oldFileFactory = false;
123  protected $fileFactoryKey = false;
124  protected $oldFileFactoryKey = false;
125 
130  public function __construct( array $info = null ) {
131  // Verify required settings presence
132  if (
133  $info === null
134  || !array_key_exists( 'name', $info )
135  || !array_key_exists( 'backend', $info )
136  ) {
137  throw new MWException( __CLASS__ .
138  " requires an array of options having both 'name' and 'backend' keys.\n" );
139  }
140 
141  // Required settings
142  $this->name = $info['name'];
143  if ( $info['backend'] instanceof FileBackend ) {
144  $this->backend = $info['backend']; // useful for testing
145  } else {
146  $this->backend = FileBackendGroup::singleton()->get( $info['backend'] );
147  }
148 
149  // Optional settings that can have no value
150  $optionalSettings = array(
151  'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription',
152  'thumbScriptUrl', 'pathDisclosureProtection', 'descriptionCacheExpiry',
153  'scriptExtension', 'favicon'
154  );
155  foreach ( $optionalSettings as $var ) {
156  if ( isset( $info[$var] ) ) {
157  $this->$var = $info[$var];
158  }
159  }
160 
161  // Optional settings that have a default
162  $this->initialCapital = isset( $info['initialCapital'] )
163  ? $info['initialCapital']
165  $this->url = isset( $info['url'] )
166  ? $info['url']
167  : false; // a subclass may set the URL (e.g. ForeignAPIRepo)
168  if ( isset( $info['thumbUrl'] ) ) {
169  $this->thumbUrl = $info['thumbUrl'];
170  } else {
171  $this->thumbUrl = $this->url ? "{$this->url}/thumb" : false;
172  }
173  $this->hashLevels = isset( $info['hashLevels'] )
174  ? $info['hashLevels']
175  : 2;
176  $this->deletedHashLevels = isset( $info['deletedHashLevels'] )
177  ? $info['deletedHashLevels']
179  $this->transformVia404 = !empty( $info['transformVia404'] );
180  $this->abbrvThreshold = isset( $info['abbrvThreshold'] )
181  ? $info['abbrvThreshold']
182  : 255;
183  $this->isPrivate = !empty( $info['isPrivate'] );
184  // Give defaults for the basic zones...
185  $this->zones = isset( $info['zones'] ) ? $info['zones'] : array();
186  foreach ( array( 'public', 'thumb', 'transcoded', 'temp', 'deleted' ) as $zone ) {
187  if ( !isset( $this->zones[$zone]['container'] ) ) {
188  $this->zones[$zone]['container'] = "{$this->name}-{$zone}";
189  }
190  if ( !isset( $this->zones[$zone]['directory'] ) ) {
191  $this->zones[$zone]['directory'] = '';
192  }
193  if ( !isset( $this->zones[$zone]['urlsByExt'] ) ) {
194  $this->zones[$zone]['urlsByExt'] = array();
195  }
196  }
197  }
198 
204  public function getBackend() {
205  return $this->backend;
206  }
207 
214  public function getReadOnlyReason() {
215  return $this->backend->getReadOnlyReason();
216  }
217 
225  protected function initZones( $doZones = array() ) {
226  $status = $this->newGood();
227  foreach ( (array)$doZones as $zone ) {
228  $root = $this->getZonePath( $zone );
229  if ( $root === null ) {
230  throw new MWException( "No '$zone' zone defined in the {$this->name} repo." );
231  }
232  }
233 
234  return $status;
235  }
236 
243  public static function isVirtualUrl( $url ) {
244  return substr( $url, 0, 9 ) == 'mwrepo://';
245  }
246 
255  public function getVirtualUrl( $suffix = false ) {
256  $path = 'mwrepo://' . $this->name;
257  if ( $suffix !== false ) {
258  $path .= '/' . rawurlencode( $suffix );
259  }
260 
261  return $path;
262  }
263 
271  public function getZoneUrl( $zone, $ext = null ) {
272  if ( in_array( $zone, array( 'public', 'temp', 'thumb', 'transcoded' ) ) ) {
273  // standard public zones
274  if ( $ext !== null && isset( $this->zones[$zone]['urlsByExt'][$ext] ) ) {
275  // custom URL for extension/zone
276  return $this->zones[$zone]['urlsByExt'][$ext];
277  } elseif ( isset( $this->zones[$zone]['url'] ) ) {
278  // custom URL for zone
279  return $this->zones[$zone]['url'];
280  }
281  }
282  switch ( $zone ) {
283  case 'public':
284  return $this->url;
285  case 'temp':
286  return "{$this->url}/temp";
287  case 'deleted':
288  return false; // no public URL
289  case 'thumb':
290  return $this->thumbUrl;
291  case 'transcoded':
292  return "{$this->url}/transcoded";
293  default:
294  return false;
295  }
296  }
297 
311  public function getZoneHandlerUrl( $zone ) {
312  if ( isset( $this->zones[$zone]['handlerUrl'] )
313  && in_array( $zone, array( 'public', 'temp', 'thumb', 'transcoded' ) )
314  ) {
315  return $this->zones[$zone]['handlerUrl'];
316  }
317 
318  return false;
319  }
320 
329  public function resolveVirtualUrl( $url ) {
330  if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
331  throw new MWException( __METHOD__ . ': unknown protocol' );
332  }
333  $bits = explode( '/', substr( $url, 9 ), 3 );
334  if ( count( $bits ) != 3 ) {
335  throw new MWException( __METHOD__ . ": invalid mwrepo URL: $url" );
336  }
337  list( $repo, $zone, $rel ) = $bits;
338  if ( $repo !== $this->name ) {
339  throw new MWException( __METHOD__ . ": fetching from a foreign repo is not supported" );
340  }
341  $base = $this->getZonePath( $zone );
342  if ( !$base ) {
343  throw new MWException( __METHOD__ . ": invalid zone: $zone" );
344  }
345 
346  return $base . '/' . rawurldecode( $rel );
347  }
348 
355  protected function getZoneLocation( $zone ) {
356  if ( !isset( $this->zones[$zone] ) ) {
357  return array( null, null ); // bogus
358  }
359 
360  return array( $this->zones[$zone]['container'], $this->zones[$zone]['directory'] );
361  }
362 
369  public function getZonePath( $zone ) {
370  list( $container, $base ) = $this->getZoneLocation( $zone );
371  if ( $container === null || $base === null ) {
372  return null;
373  }
374  $backendName = $this->backend->getName();
375  if ( $base != '' ) { // may not be set
376  $base = "/{$base}";
377  }
378 
379  return "mwstore://$backendName/{$container}{$base}";
380  }
381 
393  public function newFile( $title, $time = false ) {
395  if ( !$title ) {
396  return null;
397  }
398  if ( $time ) {
399  if ( $this->oldFileFactory ) {
400  return call_user_func( $this->oldFileFactory, $title, $this, $time );
401  } else {
402  return false;
403  }
404  } else {
405  return call_user_func( $this->fileFactory, $title, $this );
406  }
407  }
408 
425  public function findFile( $title, $options = array() ) {
427  if ( !$title ) {
428  return false;
429  }
430  $time = isset( $options['time'] ) ? $options['time'] : false;
431  # First try the current version of the file to see if it precedes the timestamp
432  $img = $this->newFile( $title );
433  if ( !$img ) {
434  return false;
435  }
436  if ( $img->exists() && ( !$time || $img->getTimestamp() == $time ) ) {
437  return $img;
438  }
439  # Now try an old version of the file
440  if ( $time !== false ) {
441  $img = $this->newFile( $title, $time );
442  if ( $img && $img->exists() ) {
443  if ( !$img->isDeleted( File::DELETED_FILE ) ) {
444  return $img; // always OK
445  } elseif ( !empty( $options['private'] ) &&
446  $img->userCan( File::DELETED_FILE,
447  $options['private'] instanceof User ? $options['private'] : null
448  )
449  ) {
450  return $img;
451  }
452  }
453  }
454 
455  # Now try redirects
456  if ( !empty( $options['ignoreRedirect'] ) ) {
457  return false;
458  }
459  $redir = $this->checkRedirect( $title );
460  if ( $redir && $title->getNamespace() == NS_FILE ) {
461  $img = $this->newFile( $redir );
462  if ( !$img ) {
463  return false;
464  }
465  if ( $img->exists() ) {
466  $img->redirectedFrom( $title->getDBkey() );
467 
468  return $img;
469  }
470  }
471 
472  return false;
473  }
474 
492  public function findFiles( array $items, $flags = 0 ) {
493  $result = array();
494  foreach ( $items as $item ) {
495  if ( is_array( $item ) ) {
496  $title = $item['title'];
497  $options = $item;
498  unset( $options['title'] );
499  } else {
500  $title = $item;
501  $options = array();
502  }
503  $file = $this->findFile( $title, $options );
504  if ( $file ) {
505  $searchName = File::normalizeTitle( $title )->getDBkey(); // must be valid
506  if ( $flags & self::NAME_AND_TIME_ONLY ) {
507  $result[$searchName] = array(
508  'title' => $file->getTitle()->getDBkey(),
509  'timestamp' => $file->getTimestamp()
510  );
511  } else {
512  $result[$searchName] = $file;
513  }
514  }
515  }
516 
517  return $result;
518  }
519 
529  public function findFileFromKey( $sha1, $options = array() ) {
530  $time = isset( $options['time'] ) ? $options['time'] : false;
531  # First try to find a matching current version of a file...
532  if ( $this->fileFactoryKey ) {
533  $img = call_user_func( $this->fileFactoryKey, $sha1, $this, $time );
534  } else {
535  return false; // find-by-sha1 not supported
536  }
537  if ( $img && $img->exists() ) {
538  return $img;
539  }
540  # Now try to find a matching old version of a file...
541  if ( $time !== false && $this->oldFileFactoryKey ) { // find-by-sha1 supported?
542  $img = call_user_func( $this->oldFileFactoryKey, $sha1, $this, $time );
543  if ( $img && $img->exists() ) {
544  if ( !$img->isDeleted( File::DELETED_FILE ) ) {
545  return $img; // always OK
546  } elseif ( !empty( $options['private'] ) &&
547  $img->userCan( File::DELETED_FILE,
548  $options['private'] instanceof User ? $options['private'] : null
549  )
550  ) {
551  return $img;
552  }
553  }
554  }
555 
556  return false;
557  }
558 
567  public function findBySha1( $hash ) {
568  return array();
569  }
570 
578  public function findBySha1s( array $hashes ) {
579  $result = array();
580  foreach ( $hashes as $hash ) {
581  $files = $this->findBySha1( $hash );
582  if ( count( $files ) ) {
583  $result[$hash] = $files;
584  }
585  }
586 
587  return $result;
588  }
589 
598  public function findFilesByPrefix( $prefix, $limit ) {
599  return array();
600  }
601 
608  public function getRootUrl() {
609  return $this->getZoneUrl( 'public' );
610  }
611 
617  public function getThumbScriptUrl() {
618  return $this->thumbScriptUrl;
619  }
620 
626  public function canTransformVia404() {
627  return $this->transformVia404;
628  }
629 
636  public function getNameFromTitle( Title $title ) {
638  if ( $this->initialCapital != MWNamespace::isCapitalized( NS_FILE ) ) {
639  $name = $title->getUserCaseDBKey();
640  if ( $this->initialCapital ) {
641  $name = $wgContLang->ucfirst( $name );
642  }
643  } else {
644  $name = $title->getDBkey();
645  }
646 
647  return $name;
648  }
649 
655  public function getRootDirectory() {
656  return $this->getZonePath( 'public' );
657  }
658 
666  public function getHashPath( $name ) {
667  return self::getHashPathForLevel( $name, $this->hashLevels );
668  }
669 
677  public function getTempHashPath( $suffix ) {
678  $parts = explode( '!', $suffix, 2 ); // format is <timestamp>!<name> or just <name>
679  $name = isset( $parts[1] ) ? $parts[1] : $suffix; // hash path is not based on timestamp
680  return self::getHashPathForLevel( $name, $this->hashLevels );
681  }
682 
688  protected static function getHashPathForLevel( $name, $levels ) {
689  if ( $levels == 0 ) {
690  return '';
691  } else {
692  $hash = md5( $name );
693  $path = '';
694  for ( $i = 1; $i <= $levels; $i++ ) {
695  $path .= substr( $hash, 0, $i ) . '/';
696  }
697 
698  return $path;
699  }
700  }
701 
707  public function getHashLevels() {
708  return $this->hashLevels;
709  }
710 
716  public function getName() {
717  return $this->name;
718  }
719 
727  public function makeUrl( $query = '', $entry = 'index' ) {
728  if ( isset( $this->scriptDirUrl ) ) {
729  $ext = isset( $this->scriptExtension ) ? $this->scriptExtension : '.php';
730 
731  return wfAppendQuery( "{$this->scriptDirUrl}/{$entry}{$ext}", $query );
732  }
733 
734  return false;
735  }
736 
749  public function getDescriptionUrl( $name ) {
750  $encName = wfUrlencode( $name );
751  if ( !is_null( $this->descBaseUrl ) ) {
752  # "http://example.com/wiki/File:"
753  return $this->descBaseUrl . $encName;
754  }
755  if ( !is_null( $this->articleUrl ) ) {
756  # "http://example.com/wiki/$1"
757  #
758  # We use "Image:" as the canonical namespace for
759  # compatibility across all MediaWiki versions.
760  return str_replace( '$1',
761  "Image:$encName", $this->articleUrl );
762  }
763  if ( !is_null( $this->scriptDirUrl ) ) {
764  # "http://example.com/w"
765  #
766  # We use "Image:" as the canonical namespace for
767  # compatibility across all MediaWiki versions,
768  # and just sort of hope index.php is right. ;)
769  return $this->makeUrl( "title=Image:$encName" );
770  }
771 
772  return false;
773  }
774 
785  public function getDescriptionRenderUrl( $name, $lang = null ) {
786  $query = 'action=render';
787  if ( !is_null( $lang ) ) {
788  $query .= '&uselang=' . $lang;
789  }
790  if ( isset( $this->scriptDirUrl ) ) {
791  return $this->makeUrl(
792  'title=' .
793  wfUrlencode( 'Image:' . $name ) .
794  "&$query" );
795  } else {
796  $descUrl = $this->getDescriptionUrl( $name );
797  if ( $descUrl ) {
798  return wfAppendQuery( $descUrl, $query );
799  } else {
800  return false;
801  }
802  }
803  }
804 
810  public function getDescriptionStylesheetUrl() {
811  if ( isset( $this->scriptDirUrl ) ) {
812  return $this->makeUrl( 'title=MediaWiki:Filepage.css&' .
814  }
815 
816  return false;
817  }
818 
833  public function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
834  $this->assertWritableRepo(); // fail out if read-only
835 
836  $status = $this->storeBatch( array( array( $srcPath, $dstZone, $dstRel ) ), $flags );
837  if ( $status->successCount == 0 ) {
838  $status->ok = false;
839  }
840 
841  return $status;
842  }
843 
857  public function storeBatch( array $triplets, $flags = 0 ) {
858  $this->assertWritableRepo(); // fail out if read-only
859 
860  $status = $this->newGood();
861  $backend = $this->backend; // convenience
862 
863  $operations = array();
864  $sourceFSFilesToDelete = array(); // cleanup for disk source files
865  // Validate each triplet and get the store operation...
866  foreach ( $triplets as $triplet ) {
867  list( $srcPath, $dstZone, $dstRel ) = $triplet;
868  wfDebug( __METHOD__
869  . "( \$src='$srcPath', \$dstZone='$dstZone', \$dstRel='$dstRel' )\n"
870  );
871 
872  // Resolve destination path
873  $root = $this->getZonePath( $dstZone );
874  if ( !$root ) {
875  throw new MWException( "Invalid zone: $dstZone" );
876  }
877  if ( !$this->validateFilename( $dstRel ) ) {
878  throw new MWException( 'Validation error in $dstRel' );
879  }
880  $dstPath = "$root/$dstRel";
881  $dstDir = dirname( $dstPath );
882  // Create destination directories for this triplet
883  if ( !$this->initDirectory( $dstDir )->isOK() ) {
884  return $this->newFatal( 'directorycreateerror', $dstDir );
885  }
886 
887  // Resolve source to a storage path if virtual
888  $srcPath = $this->resolveToStoragePath( $srcPath );
889 
890  // Get the appropriate file operation
891  if ( FileBackend::isStoragePath( $srcPath ) ) {
892  $opName = ( $flags & self::DELETE_SOURCE ) ? 'move' : 'copy';
893  } else {
894  $opName = 'store';
895  if ( $flags & self::DELETE_SOURCE ) {
896  $sourceFSFilesToDelete[] = $srcPath;
897  }
898  }
899  $operations[] = array(
900  'op' => $opName,
901  'src' => $srcPath,
902  'dst' => $dstPath,
903  'overwrite' => $flags & self::OVERWRITE,
904  'overwriteSame' => $flags & self::OVERWRITE_SAME,
905  );
906  }
907 
908  // Execute the store operation for each triplet
909  $opts = array( 'force' => true );
910  if ( $flags & self::SKIP_LOCKING ) {
911  $opts['nonLocking'] = true;
912  }
913  $status->merge( $backend->doOperations( $operations, $opts ) );
914  // Cleanup for disk source files...
915  foreach ( $sourceFSFilesToDelete as $file ) {
917  unlink( $file ); // FS cleanup
919  }
920 
921  return $status;
922  }
923 
934  public function cleanupBatch( array $files, $flags = 0 ) {
935  $this->assertWritableRepo(); // fail out if read-only
936 
937  $status = $this->newGood();
938 
939  $operations = array();
940  foreach ( $files as $path ) {
941  if ( is_array( $path ) ) {
942  // This is a pair, extract it
943  list( $zone, $rel ) = $path;
944  $path = $this->getZonePath( $zone ) . "/$rel";
945  } else {
946  // Resolve source to a storage path if virtual
947  $path = $this->resolveToStoragePath( $path );
948  }
949  $operations[] = array( 'op' => 'delete', 'src' => $path );
950  }
951  // Actually delete files from storage...
952  $opts = array( 'force' => true );
953  if ( $flags & self::SKIP_LOCKING ) {
954  $opts['nonLocking'] = true;
955  }
956  $status->merge( $this->backend->doOperations( $operations, $opts ) );
957 
958  return $status;
959  }
960 
974  final public function quickImport( $src, $dst, $options = null ) {
975  return $this->quickImportBatch( array( array( $src, $dst, $options ) ) );
976  }
977 
986  final public function quickPurge( $path ) {
987  return $this->quickPurgeBatch( array( $path ) );
988  }
989 
997  public function quickCleanDir( $dir ) {
998  $status = $this->newGood();
999  $status->merge( $this->backend->clean(
1000  array( 'dir' => $this->resolveToStoragePath( $dir ) ) ) );
1001 
1002  return $status;
1003  }
1004 
1017  public function quickImportBatch( array $triples ) {
1018  $status = $this->newGood();
1019  $operations = array();
1020  foreach ( $triples as $triple ) {
1021  list( $src, $dst ) = $triple;
1022  $src = $this->resolveToStoragePath( $src );
1023  $dst = $this->resolveToStoragePath( $dst );
1024 
1025  if ( !isset( $triple[2] ) ) {
1026  $headers = array();
1027  } elseif ( is_string( $triple[2] ) ) {
1028  // back-compat
1029  $headers = array( 'Content-Disposition' => $triple[2] );
1030  } elseif ( is_array( $triple[2] ) && isset( $triple[2]['headers'] ) ) {
1031  $headers = $triple[2]['headers'];
1032  }
1033  $operations[] = array(
1034  'op' => FileBackend::isStoragePath( $src ) ? 'copy' : 'store',
1035  'src' => $src,
1036  'dst' => $dst,
1037  'headers' => $headers
1038  );
1039  $status->merge( $this->initDirectory( dirname( $dst ) ) );
1040  }
1041  $status->merge( $this->backend->doQuickOperations( $operations ) );
1042 
1043  return $status;
1044  }
1045 
1054  public function quickPurgeBatch( array $paths ) {
1055  $status = $this->newGood();
1056  $operations = array();
1057  foreach ( $paths as $path ) {
1058  $operations[] = array(
1059  'op' => 'delete',
1060  'src' => $this->resolveToStoragePath( $path ),
1061  'ignoreMissingSource' => true
1062  );
1063  }
1064  $status->merge( $this->backend->doQuickOperations( $operations ) );
1066  return $status;
1067  }
1068 
1079  public function storeTemp( $originalName, $srcPath ) {
1080  $this->assertWritableRepo(); // fail out if read-only
1081 
1082  $date = MWTimestamp::getInstance()->format( 'YmdHis' );
1083  $hashPath = $this->getHashPath( $originalName );
1084  $dstUrlRel = $hashPath . $date . '!' . rawurlencode( $originalName );
1085  $virtualUrl = $this->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel;
1086 
1087  $result = $this->quickImport( $srcPath, $virtualUrl );
1088  $result->value = $virtualUrl;
1089 
1090  return $result;
1091  }
1092 
1099  public function freeTemp( $virtualUrl ) {
1100  $this->assertWritableRepo(); // fail out if read-only
1101 
1102  $temp = $this->getVirtualUrl( 'temp' );
1103  if ( substr( $virtualUrl, 0, strlen( $temp ) ) != $temp ) {
1104  wfDebug( __METHOD__ . ": Invalid temp virtual URL\n" );
1105 
1106  return false;
1107  }
1108 
1109  return $this->quickPurge( $virtualUrl )->isOK();
1110  }
1111 
1121  public function concatenate( array $srcPaths, $dstPath, $flags = 0 ) {
1122  $this->assertWritableRepo(); // fail out if read-only
1123 
1124  $status = $this->newGood();
1125 
1126  $sources = array();
1127  foreach ( $srcPaths as $srcPath ) {
1128  // Resolve source to a storage path if virtual
1129  $source = $this->resolveToStoragePath( $srcPath );
1130  $sources[] = $source; // chunk to merge
1131  }
1132 
1133  // Concatenate the chunks into one FS file
1134  $params = array( 'srcs' => $sources, 'dst' => $dstPath );
1135  $status->merge( $this->backend->concatenate( $params ) );
1136  if ( !$status->isOK() ) {
1137  return $status;
1138  }
1139 
1140  // Delete the sources if required
1141  if ( $flags & self::DELETE_SOURCE ) {
1142  $status->merge( $this->quickPurgeBatch( $srcPaths ) );
1143  }
1144 
1145  // Make sure status is OK, despite any quickPurgeBatch() fatals
1146  $status->setResult( true );
1147 
1148  return $status;
1149  }
1150 
1170  public function publish(
1171  $srcPath, $dstRel, $archiveRel, $flags = 0, array $options = array()
1172  ) {
1173  $this->assertWritableRepo(); // fail out if read-only
1174 
1175  $status = $this->publishBatch(
1176  array( array( $srcPath, $dstRel, $archiveRel, $options ) ), $flags );
1177  if ( $status->successCount == 0 ) {
1178  $status->ok = false;
1179  }
1180  if ( isset( $status->value[0] ) ) {
1181  $status->value = $status->value[0];
1182  } else {
1183  $status->value = false;
1184  }
1186  return $status;
1187  }
1188 
1199  public function publishBatch( array $ntuples, $flags = 0 ) {
1200  $this->assertWritableRepo(); // fail out if read-only
1201 
1202  $backend = $this->backend; // convenience
1203  // Try creating directories
1204  $status = $this->initZones( 'public' );
1205  if ( !$status->isOK() ) {
1206  return $status;
1207  }
1208 
1209  $status = $this->newGood( array() );
1210 
1211  $operations = array();
1212  $sourceFSFilesToDelete = array(); // cleanup for disk source files
1213  // Validate each triplet and get the store operation...
1214  foreach ( $ntuples as $ntuple ) {
1215  list( $srcPath, $dstRel, $archiveRel ) = $ntuple;
1216  $options = isset( $ntuple[3] ) ? $ntuple[3] : array();
1217  // Resolve source to a storage path if virtual
1218  $srcPath = $this->resolveToStoragePath( $srcPath );
1219  if ( !$this->validateFilename( $dstRel ) ) {
1220  throw new MWException( 'Validation error in $dstRel' );
1221  }
1222  if ( !$this->validateFilename( $archiveRel ) ) {
1223  throw new MWException( 'Validation error in $archiveRel' );
1224  }
1225 
1226  $publicRoot = $this->getZonePath( 'public' );
1227  $dstPath = "$publicRoot/$dstRel";
1228  $archivePath = "$publicRoot/$archiveRel";
1229 
1230  $dstDir = dirname( $dstPath );
1231  $archiveDir = dirname( $archivePath );
1232  // Abort immediately on directory creation errors since they're likely to be repetitive
1233  if ( !$this->initDirectory( $dstDir )->isOK() ) {
1234  return $this->newFatal( 'directorycreateerror', $dstDir );
1235  }
1236  if ( !$this->initDirectory( $archiveDir )->isOK() ) {
1237  return $this->newFatal( 'directorycreateerror', $archiveDir );
1238  }
1239 
1240  // Set any desired headers to be use in GET/HEAD responses
1241  $headers = isset( $options['headers'] ) ? $options['headers'] : array();
1242 
1243  // Archive destination file if it exists.
1244  // This will check if the archive file also exists and fail if does.
1245  // This is a sanity check to avoid data loss. On Windows and Linux,
1246  // copy() will overwrite, so the existence check is vulnerable to
1247  // race conditions unless an functioning LockManager is used.
1248  // LocalFile also uses SELECT FOR UPDATE for synchronization.
1249  $operations[] = array(
1250  'op' => 'copy',
1251  'src' => $dstPath,
1252  'dst' => $archivePath,
1253  'ignoreMissingSource' => true
1254  );
1255 
1256  // Copy (or move) the source file to the destination
1257  if ( FileBackend::isStoragePath( $srcPath ) ) {
1258  if ( $flags & self::DELETE_SOURCE ) {
1259  $operations[] = array(
1260  'op' => 'move',
1261  'src' => $srcPath,
1262  'dst' => $dstPath,
1263  'overwrite' => true, // replace current
1264  'headers' => $headers
1265  );
1266  } else {
1267  $operations[] = array(
1268  'op' => 'copy',
1269  'src' => $srcPath,
1270  'dst' => $dstPath,
1271  'overwrite' => true, // replace current
1272  'headers' => $headers
1273  );
1274  }
1275  } else { // FS source path
1276  $operations[] = array(
1277  'op' => 'store',
1278  'src' => $srcPath,
1279  'dst' => $dstPath,
1280  'overwrite' => true, // replace current
1281  'headers' => $headers
1282  );
1283  if ( $flags & self::DELETE_SOURCE ) {
1284  $sourceFSFilesToDelete[] = $srcPath;
1285  }
1286  }
1287  }
1288 
1289  // Execute the operations for each triplet
1290  $status->merge( $backend->doOperations( $operations ) );
1291  // Find out which files were archived...
1292  foreach ( $ntuples as $i => $ntuple ) {
1293  list( , , $archiveRel ) = $ntuple;
1294  $archivePath = $this->getZonePath( 'public' ) . "/$archiveRel";
1295  if ( $this->fileExists( $archivePath ) ) {
1296  $status->value[$i] = 'archived';
1297  } else {
1298  $status->value[$i] = 'new';
1299  }
1300  }
1301  // Cleanup for disk source files...
1302  foreach ( $sourceFSFilesToDelete as $file ) {
1304  unlink( $file ); // FS cleanup
1306  }
1307 
1308  return $status;
1309  }
1310 
1318  protected function initDirectory( $dir ) {
1319  $path = $this->resolveToStoragePath( $dir );
1320  list( , $container, ) = FileBackend::splitStoragePath( $path );
1321 
1322  $params = array( 'dir' => $path );
1323  if ( $this->isPrivate || $container === $this->zones['deleted']['container'] ) {
1324  # Take all available measures to prevent web accessibility of new deleted
1325  # directories, in case the user has not configured offline storage
1326  $params = array( 'noAccess' => true, 'noListing' => true ) + $params;
1327  }
1328 
1329  return $this->backend->prepare( $params );
1330  }
1331 
1338  public function cleanDir( $dir ) {
1339  $this->assertWritableRepo(); // fail out if read-only
1341  $status = $this->newGood();
1342  $status->merge( $this->backend->clean(
1343  array( 'dir' => $this->resolveToStoragePath( $dir ) ) ) );
1344 
1345  return $status;
1346  }
1347 
1354  public function fileExists( $file ) {
1355  $result = $this->fileExistsBatch( array( $file ) );
1356 
1357  return $result[0];
1358  }
1359 
1366  public function fileExistsBatch( array $files ) {
1367  $result = array();
1368  foreach ( $files as $key => $file ) {
1369  $file = $this->resolveToStoragePath( $file );
1370  $result[$key] = $this->backend->fileExists( array( 'src' => $file ) );
1371  }
1373  return $result;
1374  }
1375 
1386  public function delete( $srcRel, $archiveRel ) {
1387  $this->assertWritableRepo(); // fail out if read-only
1388 
1389  return $this->deleteBatch( array( array( $srcRel, $archiveRel ) ) );
1390  }
1391 
1409  public function deleteBatch( array $sourceDestPairs ) {
1410  $this->assertWritableRepo(); // fail out if read-only
1411 
1412  // Try creating directories
1413  $status = $this->initZones( array( 'public', 'deleted' ) );
1414  if ( !$status->isOK() ) {
1415  return $status;
1416  }
1417 
1418  $status = $this->newGood();
1419 
1420  $backend = $this->backend; // convenience
1421  $operations = array();
1422  // Validate filenames and create archive directories
1423  foreach ( $sourceDestPairs as $pair ) {
1424  list( $srcRel, $archiveRel ) = $pair;
1425  if ( !$this->validateFilename( $srcRel ) ) {
1426  throw new MWException( __METHOD__ . ':Validation error in $srcRel' );
1427  } elseif ( !$this->validateFilename( $archiveRel ) ) {
1428  throw new MWException( __METHOD__ . ':Validation error in $archiveRel' );
1429  }
1430 
1431  $publicRoot = $this->getZonePath( 'public' );
1432  $srcPath = "{$publicRoot}/$srcRel";
1433 
1434  $deletedRoot = $this->getZonePath( 'deleted' );
1435  $archivePath = "{$deletedRoot}/{$archiveRel}";
1436  $archiveDir = dirname( $archivePath ); // does not touch FS
1437 
1438  // Create destination directories
1439  if ( !$this->initDirectory( $archiveDir )->isOK() ) {
1440  return $this->newFatal( 'directorycreateerror', $archiveDir );
1441  }
1442 
1443  $operations[] = array(
1444  'op' => 'move',
1445  'src' => $srcPath,
1446  'dst' => $archivePath,
1447  // We may have 2+ identical files being deleted,
1448  // all of which will map to the same destination file
1449  'overwriteSame' => true // also see bug 31792
1450  );
1451  }
1452 
1453  // Move the files by execute the operations for each pair.
1454  // We're now committed to returning an OK result, which will
1455  // lead to the files being moved in the DB also.
1456  $opts = array( 'force' => true );
1457  $status->merge( $backend->doOperations( $operations, $opts ) );
1458 
1459  return $status;
1460  }
1461 
1467  public function cleanupDeletedBatch( array $storageKeys ) {
1468  $this->assertWritableRepo();
1469  }
1470 
1479  public function getDeletedHashPath( $key ) {
1480  if ( strlen( $key ) < 31 ) {
1481  throw new MWException( "Invalid storage key '$key'." );
1482  }
1483  $path = '';
1484  for ( $i = 0; $i < $this->deletedHashLevels; $i++ ) {
1485  $path .= $key[$i] . '/';
1486  }
1487 
1488  return $path;
1489  }
1490 
1499  protected function resolveToStoragePath( $path ) {
1500  if ( $this->isVirtualUrl( $path ) ) {
1501  return $this->resolveVirtualUrl( $path );
1502  }
1503 
1504  return $path;
1505  }
1506 
1514  public function getLocalCopy( $virtualUrl ) {
1515  $path = $this->resolveToStoragePath( $virtualUrl );
1516 
1517  return $this->backend->getLocalCopy( array( 'src' => $path ) );
1518  }
1519 
1528  public function getLocalReference( $virtualUrl ) {
1529  $path = $this->resolveToStoragePath( $virtualUrl );
1530 
1531  return $this->backend->getLocalReference( array( 'src' => $path ) );
1532  }
1533 
1541  public function getFileProps( $virtualUrl ) {
1542  $path = $this->resolveToStoragePath( $virtualUrl );
1543 
1544  return $this->backend->getFileProps( array( 'src' => $path ) );
1545  }
1546 
1553  public function getFileTimestamp( $virtualUrl ) {
1554  $path = $this->resolveToStoragePath( $virtualUrl );
1555 
1556  return $this->backend->getFileTimestamp( array( 'src' => $path ) );
1557  }
1558 
1565  public function getFileSize( $virtualUrl ) {
1566  $path = $this->resolveToStoragePath( $virtualUrl );
1567 
1568  return $this->backend->getFileSize( array( 'src' => $path ) );
1569  }
1570 
1577  public function getFileSha1( $virtualUrl ) {
1578  $path = $this->resolveToStoragePath( $virtualUrl );
1579 
1580  return $this->backend->getFileSha1Base36( array( 'src' => $path ) );
1581  }
1582 
1590  public function streamFile( $virtualUrl, $headers = array() ) {
1591  $path = $this->resolveToStoragePath( $virtualUrl );
1592  $params = array( 'src' => $path, 'headers' => $headers );
1593 
1594  return $this->backend->streamFile( $params )->isOK();
1595  }
1596 
1605  public function enumFiles( $callback ) {
1606  $this->enumFilesInStorage( $callback );
1607  }
1608 
1616  protected function enumFilesInStorage( $callback ) {
1617  $publicRoot = $this->getZonePath( 'public' );
1618  $numDirs = 1 << ( $this->hashLevels * 4 );
1619  // Use a priori assumptions about directory structure
1620  // to reduce the tree height of the scanning process.
1621  for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) {
1622  $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex );
1623  $path = $publicRoot;
1624  for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) {
1625  $path .= '/' . substr( $hexString, 0, $hexPos + 1 );
1626  }
1627  $iterator = $this->backend->getFileList( array( 'dir' => $path ) );
1628  foreach ( $iterator as $name ) {
1629  // Each item returned is a public file
1630  call_user_func( $callback, "{$path}/{$name}" );
1631  }
1632  }
1633  }
1634 
1641  public function validateFilename( $filename ) {
1642  if ( strval( $filename ) == '' ) {
1643  return false;
1644  }
1645 
1646  return FileBackend::isPathTraversalFree( $filename );
1647  }
1648 
1654  function getErrorCleanupFunction() {
1655  switch ( $this->pathDisclosureProtection ) {
1656  case 'none':
1657  case 'simple': // b/c
1658  $callback = array( $this, 'passThrough' );
1659  break;
1660  default: // 'paranoid'
1661  $callback = array( $this, 'paranoidClean' );
1662  }
1663  return $callback;
1664  }
1665 
1672  function paranoidClean( $param ) {
1673  return '[hidden]';
1674  }
1675 
1682  function passThrough( $param ) {
1683  return $param;
1684  }
1685 
1692  public function newFatal( $message /*, parameters...*/ ) {
1693  $params = func_get_args();
1694  array_unshift( $params, $this );
1695 
1696  return call_user_func_array( array( 'FileRepoStatus', 'newFatal' ), $params );
1697  }
1698 
1705  public function newGood( $value = null ) {
1706  return FileRepoStatus::newGood( $this, $value );
1707  }
1708 
1717  public function checkRedirect( Title $title ) {
1718  return false;
1719  }
1720 
1728  public function invalidateImageRedirect( Title $title ) {
1729  }
1730 
1736  public function getDisplayName() {
1737  // We don't name our own repo, return nothing
1738  if ( $this->isLocal() ) {
1739  return null;
1740  }
1741 
1742  // 'shared-repo-name-wikimediacommons' is used when $wgUseInstantCommons = true
1743  return wfMessageFallback( 'shared-repo-name-' . $this->name, 'shared-repo' )->text();
1744  }
1745 
1753  public function nameForThumb( $name ) {
1754  if ( strlen( $name ) > $this->abbrvThreshold ) {
1756  $name = ( $ext == '' ) ? 'thumbnail' : "thumbnail.$ext";
1757  }
1758 
1759  return $name;
1760  }
1761 
1767  public function isLocal() {
1768  return $this->getName() == 'local';
1769  }
1770 
1779  public function getSharedCacheKey( /*...*/ ) {
1780  return false;
1781  }
1782 
1790  public function getLocalCacheKey( /*...*/ ) {
1791  $args = func_get_args();
1792  array_unshift( $args, 'filerepo', $this->getName() );
1793 
1794  return call_user_func_array( 'wfMemcKey', $args );
1795  }
1796 
1805  public function getTempRepo() {
1806  return new TempFileRepo( array(
1807  'name' => "{$this->name}-temp",
1808  'backend' => $this->backend,
1809  'zones' => array(
1810  'public' => array(
1811  'container' => $this->zones['temp']['container'],
1812  'directory' => $this->zones['temp']['directory']
1813  ),
1814  'thumb' => array(
1815  'container' => $this->zones['thumb']['container'],
1816  'directory' => $this->zones['thumb']['directory'] == ''
1817  ? 'temp'
1818  : $this->zones['thumb']['directory'] . '/temp'
1819  ),
1820  'transcoded' => array(
1821  'container' => $this->zones['transcoded']['container'],
1822  'directory' => $this->zones['transcoded']['directory'] == ''
1823  ? 'temp'
1824  : $this->zones['transcoded']['directory'] . '/temp'
1825  )
1826  ),
1827  'url' => $this->getZoneUrl( 'temp' ),
1828  'thumbUrl' => $this->getZoneUrl( 'thumb' ) . '/temp',
1829  'transcodedUrl' => $this->getZoneUrl( 'transcoded' ) . '/temp',
1830  'hashLevels' => $this->hashLevels // performance
1831  ) );
1832  }
1833 
1840  public function getUploadStash( User $user = null ) {
1841  return new UploadStash( $this, $user );
1842  }
1843 
1851  protected function assertWritableRepo() {
1852  }
1853 
1860  public function getInfo() {
1861  $ret = array(
1862  'name' => $this->getName(),
1863  'displayname' => $this->getDisplayName(),
1864  'rootUrl' => $this->getZoneUrl( 'public' ),
1865  'local' => $this->isLocal(),
1866  );
1867 
1868  $optionalSettings = array(
1869  'url', 'thumbUrl', 'initialCapital', 'descBaseUrl', 'scriptDirUrl', 'articleUrl',
1870  'fetchDescription', 'descriptionCacheExpiry', 'scriptExtension', 'favicon'
1871  );
1872  foreach ( $optionalSettings as $k ) {
1873  if ( isset( $this->$k ) ) {
1874  $ret[$k] = $this->$k;
1875  }
1876  }
1877 
1878  return $ret;
1879  }
1880 }
1881 
1885 class TempFileRepo extends FileRepo {
1886  public function getTempRepo() {
1887  throw new MWException( "Cannot get a temp repo from a temp repo." );
1888  }
1889 }
FileBackend\splitStoragePath
static splitStoragePath( $storagePath)
Split a storage path into a backend name, a container name, and a relative file path.
Definition: FileBackend.php:1342
FileRepo\$zones
Array $zones
Map of zones to config *.
Definition: FileRepo.php:52
FileRepo\$oldFileFactory
$oldFileFactory
Definition: FileRepo.php:108
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
FileRepo\getReadOnlyReason
getReadOnlyReason()
Get an explanatory message if this repo is read-only.
Definition: FileRepo.php:200
FileRepo\$thumbUrl
$thumbUrl
Definition: FileRepo.php:90
FileRepo\passThrough
passThrough( $param)
Path disclosure protection function.
Definition: FileRepo.php:1668
FileRepo\findFile
findFile( $title, $options=array())
Find an instance of the named file created at the specified time Returns false if the file does not e...
Definition: FileRepo.php:411
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
FileRepo\findBySha1
findBySha1( $hash)
Get an array or iterator of file objects for files that have a given SHA-1 content hash.
Definition: FileRepo.php:553
$files
$files
Definition: importImages.php:67
FileRepo\getThumbScriptUrl
getThumbScriptUrl()
Get the URL of thumb.php.
Definition: FileRepo.php:603
FileRepo\newGood
newGood( $value=null)
Create a new good result.
Definition: FileRepo.php:1691
FileRepo\getDescriptionRenderUrl
getDescriptionRenderUrl( $name, $lang=null)
Get the URL of the content-only fragment of the description page.
Definition: FileRepo.php:771
FileBackend
Base class for all file backend classes (including multi-write backends).
Definition: FileBackend.php:85
FileRepo\$deletedHashLevels
int $deletedHashLevels
The number of directory levels for hash-based division of deleted files *.
Definition: FileRepo.php:94
FileRepo\enumFilesInStorage
enumFilesInStorage( $callback)
Call a callback function for every public file in the repository.
Definition: FileRepo.php:1602
FileRepo\$favicon
string $favicon
The URL of the repo's favicon, if any *.
Definition: FileRepo.php:101
FileRepo\OVERWRITE_SAME
const OVERWRITE_SAME
Definition: FileRepo.php:40
FileRepo\validateFilename
validateFilename( $filename)
Determine if a relative path is valid, i.e.
Definition: FileRepo.php:1627
FileRepo\getRootDirectory
getRootDirectory()
Get the public zone root storage directory of the repository.
Definition: FileRepo.php:641
FileRepo\OVERWRITE
const OVERWRITE
Definition: FileRepo.php:39
FileRepo\getVirtualUrl
getVirtualUrl( $suffix=false)
Get a URL referring to this repository, with the private mwrepo protocol.
Definition: FileRepo.php:241
FileRepo\makeUrl
makeUrl( $query='', $entry='index')
Make an url to this repo.
Definition: FileRepo.php:713
FileRepo\storeBatch
storeBatch(array $triplets, $flags=0)
Store a batch of files.
Definition: FileRepo.php:843
FileRepo\$pathDisclosureProtection
string $pathDisclosureProtection
May be 'paranoid' to remove all parameters from error messages, 'none' to leave the paths in unchange...
Definition: FileRepo.php:85
FileRepo\getTempRepo
getTempRepo()
Get an temporary FileRepo associated with this repo.
Definition: FileRepo.php:1791
FileRepo\getInfo
getInfo()
Return information about the repository.
Definition: FileRepo.php:1846
UploadStash
UploadStash is intended to accomplish a few things:
Definition: UploadStash.php:44
FileRepo\$descriptionCacheExpiry
int $descriptionCacheExpiry
Definition: FileRepo.php:48
FileRepo\getName
getName()
Get the name of this repository, as specified by $info['name]' to the constructor.
Definition: FileRepo.php:702
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1530
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2434
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:377
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
FileRepo\quickImportBatch
quickImportBatch(array $triples)
Import a batch of files from the local file system into the repo.
Definition: FileRepo.php:1003
FileBackend\extensionFromPath
static extensionFromPath( $path, $case='lowercase')
Get the final extension from a storage or FS path.
Definition: FileBackend.php:1401
FileRepo\$fileFactory
$fileFactory
Factory functions for creating new files Override these in the base class.
Definition: FileRepo.php:107
NS_FILE
const NS_FILE
Definition: Defines.php:85
FileRepo\getHashPathForLevel
static getHashPathForLevel( $name, $levels)
Definition: FileRepo.php:674
$params
$params
Definition: styleTest.css.php:40
$limit
if( $sleep) $limit
Definition: importImages.php:99
Skin\getDynamicStylesheetQuery
static getDynamicStylesheetQuery()
Get the query to generate a dynamic stylesheet.
Definition: Skin.php:428
FileRepo\getZoneUrl
getZoneUrl( $zone, $ext=null)
Get the URL corresponding to one of the four basic zones.
Definition: FileRepo.php:257
FileRepo\getZonePath
getZonePath( $zone)
Get the storage path corresponding to one of the zones.
Definition: FileRepo.php:355
FileRepo\getLocalReference
getLocalReference( $virtualUrl)
Get a local FS file with a given virtual URL/storage path.
Definition: FileRepo.php:1514
FileRepo\getZoneLocation
getZoneLocation( $zone)
The the storage container and base path of a zone.
Definition: FileRepo.php:341
FileRepo\resolveToStoragePath
resolveToStoragePath( $path)
If a path is a virtual URL, resolve it to a storage path.
Definition: FileRepo.php:1485
FileRepo\$backend
FileBackend $backend
Definition: FileRepo.php:50
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2118
wfMessageFallback
wfMessageFallback()
This function accepts multiple message keys and returns a message instance for the first message whic...
Definition: GlobalFunctions.php:1469
FileRepo\$initialCapital
bool $initialCapital
Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE], determines whether filenames impl...
Definition: FileRepo.php:79
FileRepo\initZones
initZones( $doZones=array())
Check if a single zone or list of zones is defined for usage.
Definition: FileRepo.php:211
File\normalizeTitle
static normalizeTitle( $title, $exception=false)
Given a string or Title object return either a valid Title object with namespace NS_FILE or null.
Definition: File.php:161
FileBackendGroup\singleton
static singleton()
Definition: FileBackendGroup.php:43
FileRepo\$scriptExtension
string $scriptExtension
Script extension of the MediaWiki installation, equivalent to $wgScriptExtension, e....
Definition: FileRepo.php:70
FileRepo\getDescriptionStylesheetUrl
getDescriptionStylesheetUrl()
Get the URL of the stylesheet to apply to description pages.
Definition: FileRepo.php:796
FileRepo\fileExistsBatch
fileExistsBatch(array $files)
Checks existence of an array of files.
Definition: FileRepo.php:1352
FileRepo
Base class for file repositories.
Definition: FileRepo.php:37
wfAppendQuery
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
Definition: GlobalFunctions.php:506
FileRepoStatus\newGood
static newGood( $repo=false, $value=null)
Definition: FileRepoStatus.php:49
FileRepo\getSharedCacheKey
getSharedCacheKey()
Get a key on the primary cache for this repository.
Definition: FileRepo.php:1765
FileRepo\freeTemp
freeTemp( $virtualUrl)
Remove a temporary file or mark it for garbage collection.
Definition: FileRepo.php:1085
FileRepo\findFiles
findFiles(array $items, $flags=0)
Find many files at once.
Definition: FileRepo.php:478
FileRepo\quickPurge
quickPurge( $path)
Purge a file from the repo.
Definition: FileRepo.php:972
FileRepo\newFile
newFile( $title, $time=false)
Create a new File object from the local repository.
Definition: FileRepo.php:379
MWException
MediaWiki exception.
Definition: MWException.php:26
FileRepo\enumFiles
enumFiles( $callback)
Call a callback function for every public regular file in the repository.
Definition: FileRepo.php:1591
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2464
FileRepo\checkRedirect
checkRedirect(Title $title)
Checks if there is a redirect named as $title.
Definition: FileRepo.php:1703
FileRepo\quickImport
quickImport( $src, $dst, $options=null)
Import a file from the local file system into the repo.
Definition: FileRepo.php:960
FileBackend\isStoragePath
static isStoragePath( $path)
Check if a given path is a "mwstore://" path.
Definition: FileBackend.php:1330
FileRepo\getUploadStash
getUploadStash(User $user=null)
Get an UploadStash associated with this repo.
Definition: FileRepo.php:1826
TempFileRepo\getTempRepo
getTempRepo()
Get an temporary FileRepo associated with this repo.
Definition: FileRepo.php:1872
FileRepo\$thumbScriptUrl
string $thumbScriptUrl
URL of thumb.php *.
Definition: FileRepo.php:54
FileRepo\findFilesByPrefix
findFilesByPrefix( $prefix, $limit)
Return an array of files where the name starts with $prefix.
Definition: FileRepo.php:584
FileRepo\$oldFileFactoryKey
$oldFileFactoryKey
Definition: FileRepo.php:110
FileRepo\paranoidClean
paranoidClean( $param)
Path disclosure protection function.
Definition: FileRepo.php:1658
FileRepo\getDescriptionUrl
getDescriptionUrl( $name)
Get the URL of an image description page.
Definition: FileRepo.php:735
FileRepo\store
store( $srcPath, $dstZone, $dstRel, $flags=0)
Store a file to a given destination.
Definition: FileRepo.php:819
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
FileRepo\getZoneHandlerUrl
getZoneHandlerUrl( $zone)
Get the thumb zone URL configured to be handled by scripts like thumb_handler.php.
Definition: FileRepo.php:297
MWTimestamp\getInstance
static getInstance( $ts=false)
Get a timestamp instance in GMT.
Definition: MWTimestamp.php:387
FileRepo\$descBaseUrl
$descBaseUrl
Definition: FileRepo.php:62
FileRepo\nameForThumb
nameForThumb( $name)
Get the portion of the file that contains the origin file name.
Definition: FileRepo.php:1739
FileRepo\invalidateImageRedirect
invalidateImageRedirect(Title $title)
Invalidates image redirect cache related to that image Doesn't do anything for repositories that don'...
Definition: FileRepo.php:1714
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
FileRepo\getLocalCopy
getLocalCopy( $virtualUrl)
Get a local FS copy of a file with a given virtual URL/storage path.
Definition: FileRepo.php:1500
TempFileRepo
FileRepo for temporary files created via FileRepo::getTempRepo()
Definition: FileRepo.php:1871
FileRepo\$fileFactoryKey
$fileFactoryKey
Definition: FileRepo.php:109
FileRepo\cleanupBatch
cleanupBatch(array $files, $flags=0)
Deletes a batch of files.
Definition: FileRepo.php:920
FileRepo\streamFile
streamFile( $virtualUrl, $headers=array())
Attempt to stream a file with the given virtual URL/storage path.
Definition: FileRepo.php:1576
FileBackend\doOperations
doOperations(array $ops, array $opts=array())
This is the main entry point into the backend for write operations.
Definition: FileBackend.php:367
FileRepo\fileExists
fileExists( $file)
Checks existence of a a file.
Definition: FileRepo.php:1340
FileRepo\getFileSha1
getFileSha1( $virtualUrl)
Get the sha1 (base 36) of a file with a given virtual URL/storage path.
Definition: FileRepo.php:1563
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
FileRepo\getNameFromTitle
getNameFromTitle(Title $title)
Get the name of a file from its title object.
Definition: FileRepo.php:622
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1530
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
FileRepo\getDisplayName
getDisplayName()
Get the human-readable name of the repo.
Definition: FileRepo.php:1722
$value
$value
Definition: styleTest.css.php:45
FileRepo\SKIP_LOCKING
const SKIP_LOCKING
Definition: FileRepo.php:41
FileRepo\$scriptDirUrl
$scriptDirUrl
Definition: FileRepo.php:67
FileRepo\storeTemp
storeTemp( $originalName, $srcPath)
Pick a random name in the temp zone and store a file to it.
Definition: FileRepo.php:1065
FileRepo\newFatal
newFatal( $message)
Create a new fatal error.
Definition: FileRepo.php:1678
FileRepo\publishBatch
publishBatch(array $ntuples, $flags=0)
Publish a batch of files.
Definition: FileRepo.php:1185
FileRepo\publish
publish( $srcPath, $dstRel, $archiveRel, $flags=0, array $options=array())
Copy or move a file either from a storage path, virtual URL, or file system path, into this repositor...
Definition: FileRepo.php:1156
FileRepo\getHashLevels
getHashLevels()
Get the number of hash directory levels.
Definition: FileRepo.php:693
FileRepo\initDirectory
initDirectory( $dir)
Creates a directory with the appropriate zone permissions.
Definition: FileRepo.php:1304
FileRepo\findFileFromKey
findFileFromKey( $sha1, $options=array())
Find an instance of the file with this key, created at the specified time Returns false if the file d...
Definition: FileRepo.php:515
FileRepo\getBackend
getBackend()
Get the file backend instance.
Definition: FileRepo.php:190
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
FileRepo\quickPurgeBatch
quickPurgeBatch(array $paths)
Purge a batch of files from the repo.
Definition: FileRepo.php:1040
FileRepo\getLocalCacheKey
getLocalCacheKey()
Get a key for this repo in the local cache domain.
Definition: FileRepo.php:1776
FileRepo\getFileSize
getFileSize( $virtualUrl)
Get the size of a file with a given virtual URL/storage path.
Definition: FileRepo.php:1551
FileRepo\isLocal
isLocal()
Returns true if this the local file repository.
Definition: FileRepo.php:1753
$hash
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks & $hash
Definition: hooks.txt:2702
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
FileRepo\getHashPath
getHashPath( $name)
Get a relative path including trailing slash, e.g.
Definition: FileRepo.php:652
$args
if( $line===false) $args
Definition: cdb.php:62
FileRepo\getErrorCleanupFunction
getErrorCleanupFunction()
Get a callback function to use for cleaning error message parameters.
Definition: FileRepo.php:1640
Title
Represents a title within MediaWiki.
Definition: Title.php:35
FileRepo\__construct
__construct(array $info=null)
Definition: FileRepo.php:116
FileRepo\findBySha1s
findBySha1s(array $hashes)
Get an array of arrays or iterators of file objects for files that have the given SHA-1 content hashe...
Definition: FileRepo.php:564
$dir
if(count( $args)==0) $dir
Definition: importImages.php:49
$ext
$ext
Definition: NoLocalSettings.php:34
FileRepo\getTempHashPath
getTempHashPath( $suffix)
Get a relative path including trailing slash, e.g.
Definition: FileRepo.php:663
$path
$path
Definition: NoLocalSettings.php:35
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
FileRepo\quickCleanDir
quickCleanDir( $dir)
Deletes a directory if empty.
Definition: FileRepo.php:983
FileRepo\isVirtualUrl
static isVirtualUrl( $url)
Determine if a string is an mwrepo:// URL.
Definition: FileRepo.php:229
MWNamespace\isCapitalized
static isCapitalized( $index)
Is the namespace first-letter capitalized?
Definition: Namespace.php:378
FileRepo\getFileTimestamp
getFileTimestamp( $virtualUrl)
Get the timestamp of a file with a given virtual URL/storage path.
Definition: FileRepo.php:1539
FileRepo\concatenate
concatenate(array $srcPaths, $dstPath, $flags=0)
Concatenate a list of temporary files into a target file location.
Definition: FileRepo.php:1107
FileRepo\deleteBatch
deleteBatch(array $sourceDestPairs)
Move a group of files to the deletion archive.
Definition: FileRepo.php:1395
FileRepo\resolveVirtualUrl
resolveVirtualUrl( $url)
Get the backend storage path corresponding to a virtual URL.
Definition: FileRepo.php:315
$source
if(PHP_SAPI !='cli') $source
Definition: mwdoc-filter.php:18
FileBackend\isPathTraversalFree
static isPathTraversalFree( $path)
Check if a relative path has no directory traversals.
Definition: FileBackend.php:1421
FileRepo\$url
bool $url
Public zone URL.
Definition: FileRepo.php:87
FileRepo\cleanDir
cleanDir( $dir)
Deletes a directory if empty.
Definition: FileRepo.php:1324
$hashes
$hashes
Definition: testCompression.php:62
FileRepo\DELETE_SOURCE
const DELETE_SOURCE
Definition: FileRepo.php:38
File\DELETED_FILE
const DELETED_FILE
Definition: File.php:52
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
FileRepo\getFileProps
getFileProps( $virtualUrl)
Get properties of a file with a given virtual URL/storage path.
Definition: FileRepo.php:1527
FileRepo\$abbrvThreshold
int $abbrvThreshold
File names over this size will use the short form of thumbnail names.
Definition: FileRepo.php:99
$query
return true to allow those checks to and false if checking is done use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1105
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:59
FileRepo\getRootUrl
getRootUrl()
Get the public root URL of the repository.
Definition: FileRepo.php:594
FileRepo\$transformVia404
bool $transformVia404
Whether to skip media file transformation on parse and rely on a 404 handler instead.
Definition: FileRepo.php:57
FileRepo\$hashLevels
int $hashLevels
The number of directory levels for hash-based division of files *.
Definition: FileRepo.php:92
FileRepo\getDeletedHashPath
getDeletedHashPath( $key)
Get a relative path for a deletion archive key, e.g.
Definition: FileRepo.php:1465
FileRepo\assertWritableRepo
assertWritableRepo()
Throw an exception if this repo is read-only by design.
Definition: FileRepo.php:1837
FileRepo\NAME_AND_TIME_ONLY
const NAME_AND_TIME_ONLY
Definition: FileRepo.php:43
FileRepo\cleanupDeletedBatch
cleanupDeletedBatch(array $storageKeys)
Delete files in the deleted directory if they are not referenced in the filearchive table.
Definition: FileRepo.php:1453
FileRepo\canTransformVia404
canTransformVia404()
Returns true if the repository can transform files via a 404 handler.
Definition: FileRepo.php:612
FileRepo\$fetchDescription
bool $fetchDescription
Whether to fetch commons image description pages and display them on the local wiki *.
Definition: FileRepo.php:46
FileRepo\$articleUrl
$articleUrl
Definition: FileRepo.php:73
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes two arrays as input, and returns a CGI-style string, e.g.
Definition: GlobalFunctions.php:414