77 parent::__construct( $info );
79 $this->dbDomain = WikiMap::getCurrentWikiDbDomain();
80 $this->hasAccessibleSharedCache =
true;
82 $this->
hasSha1Storage = ( $info[
'storageLayout'] ?? null ) ===
'sha1';
86 'backend' => $this->backend,
87 'repoName' => $this->name,
96 'splitMetadataThreshold',
97 'updateCompatibleMetadata',
98 'reserializeMetadata',
101 if ( isset( $info[$option] ) ) {
102 $this->$option = $info[$option];
113 if ( isset( $row->img_name ) ) {
114 return call_user_func( $this->fileFromRowFactory, $row, $this );
115 } elseif ( isset( $row->oi_name ) ) {
116 return call_user_func( $this->oldFileFromRowFactory, $row, $this );
118 throw new MWException( __METHOD__ .
': invalid row' );
129 return OldLocalFile::newFromArchiveName(
$title, $this, $archiveName );
144 wfDebug( __METHOD__ .
": skipped because storage uses sha1 paths" );
145 return Status::newGood();
152 $storageKeys = array_unique( $storageKeys );
153 foreach ( $storageKeys as $key ) {
155 $path =
"$root/$hashPath$key";
156 $dbw->startAtomic( __METHOD__ );
161 if ( !$deleted && !$hidden ) {
162 wfDebug( __METHOD__ .
": deleting $key" );
163 $op = [
'op' =>
'delete',
'src' =>
$path ];
165 $status->error(
'undelete-cleanup-error',
$path );
166 $status->failCount++;
169 wfDebug( __METHOD__ .
": $key still in use" );
170 $status->successCount++;
172 $dbw->endAtomic( __METHOD__ );
187 return (
bool)$dbw->selectField(
'filearchive',
'1',
188 [
'fa_storage_group' =>
'deleted',
'fa_storage_key' => $key ],
190 $lock ===
'lock' ? [
'FOR UPDATE' ] : []
202 $sha1 = self::getHashFromKey( $key );
203 $ext = File::normalizeExtension( substr( $key, strcspn( $key,
'.' ) + 1 ) );
206 return (
bool)$dbw->selectField(
'oldimage',
'1',
209 'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(),
".$ext" ),
210 $dbw->bitAnd(
'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE,
213 $lock ===
'lock' ? [
'FOR UPDATE' ] : []
224 $sha1 = strtok( $key,
'.' );
225 if ( is_string( $sha1 ) && strlen( $sha1 ) === 32 && $sha1[0] ===
'0' ) {
226 $sha1 = substr( $sha1, 1 );
241 if ( $memcKey ===
false ) {
248 $method = __METHOD__;
249 $redirDbKey = $this->wanCache->getWithSetCallback(
252 function ( $oldValue, &$ttl, array &$setOpts ) use ( $method,
$title ) {
255 $setOpts += Database::getCacheSetOptions(
$dbr );
257 $row =
$dbr->selectRow(
258 [
'page',
'redirect' ],
259 [
'rd_namespace',
'rd_title' ],
261 'page_namespace' =>
$title->getNamespace(),
262 'page_title' =>
$title->getDBkey(),
268 return ( $row && $row->rd_namespace ==
NS_FILE )
269 ? Title::makeTitle( $row->rd_namespace, $row->rd_title )->getDBkey()
272 [
'pcTTL' => WANObjectCache::TTL_PROC_LONG ]
276 if ( $redirDbKey !==
' ' && strval( $redirDbKey ) !==
'' ) {
278 return Title::newFromText( $redirDbKey,
NS_FILE );
288 foreach ( $items as $item ) {
289 if ( is_array( $item ) ) {
290 $title = File::normalizeTitle( $item[
'title'] );
292 $searchSet[
$title->getDBkey()] = $item;
295 $title = File::normalizeTitle( $item );
297 $searchSet[
$title->getDBkey()] = [];
302 $fileMatchesSearch =
static function (
File $file, array $search ) {
308 $contextPerformer = RequestContext::getMain()->getAuthority();
309 $performer = ( !empty( $search[
'private'] ) && $search[
'private'] instanceof
Authority )
316 ( empty( $search[
'time'] ) && !
$file->isOld() ) ||
317 ( !empty( $search[
'time'] ) && $search[
'time'] ===
$file->getTimestamp() )
319 ( !empty( $search[
'private'] ) || !
$file->isDeleted( File::DELETED_FILE ) ) &&
320 $file->userCan( File::DELETED_FILE, $performer )
325 use ( $fileMatchesSearch, $flags )
327 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
329 foreach (
$res as $row ) {
333 $dbKeysLook = [ strtr(
$file->getName(),
' ',
'_' ) ];
334 if ( !empty( $info[
'initialCapital'] ) ) {
336 $dbKeysLook[] = $contLang->lcfirst(
$file->getName() );
338 foreach ( $dbKeysLook as $dbKey ) {
339 if ( isset( $searchSet[$dbKey] )
340 && $fileMatchesSearch(
$file, $searchSet[$dbKey] )
343 ? [
'title' => $dbKey,
'timestamp' =>
$file->getTimestamp() ]
345 unset( $searchSet[$dbKey] );
355 foreach ( array_keys( $searchSet ) as $dbKey ) {
359 if ( count( $imgNames ) ) {
360 $fileQuery = LocalFile::getQueryInfo();
361 $res =
$dbr->select( $fileQuery[
'tables'], $fileQuery[
'fields'], [
'img_name' => $imgNames ],
362 __METHOD__, [], $fileQuery[
'joins'] );
363 $applyMatchingFiles(
$res, $searchSet, $finalFiles );
368 foreach ( $searchSet as $dbKey => $search ) {
369 if ( isset( $search[
'time'] ) ) {
370 $oiConds[] =
$dbr->makeList(
373 'oi_timestamp' =>
$dbr->timestamp( $search[
'time'] )
380 if ( count( $oiConds ) ) {
381 $fileQuery = OldLocalFile::getQueryInfo();
382 $res =
$dbr->select( $fileQuery[
'tables'], $fileQuery[
'fields'],
384 __METHOD__, [], $fileQuery[
'joins'] );
385 $applyMatchingFiles(
$res, $searchSet, $finalFiles );
389 foreach ( $searchSet as $dbKey => $search ) {
390 if ( !empty( $search[
'ignoreRedirect'] ) ) {
394 $title = File::normalizeTitle( $dbKey );
397 if ( $redir && $redir->getNamespace() ===
NS_FILE ) {
399 if (
$file && $fileMatchesSearch(
$file, $search ) ) {
402 $finalFiles[$dbKey] = [
403 'title' =>
$file->getTitle()->getDBkey(),
404 'timestamp' =>
$file->getTimestamp()
407 $finalFiles[$dbKey] =
$file;
425 $fileQuery = LocalFile::getQueryInfo();
427 $fileQuery[
'tables'],
428 $fileQuery[
'fields'],
429 [
'img_sha1' => $hash ],
431 [
'ORDER BY' =>
'img_name' ],
436 foreach (
$res as $row ) {
459 $fileQuery = LocalFile::getQueryInfo();
461 $fileQuery[
'tables'],
462 $fileQuery[
'fields'],
465 [
'ORDER BY' =>
'img_name' ],
470 foreach (
$res as $row ) {
487 $selectOptions = [
'ORDER BY' =>
'img_name',
'LIMIT' => intval( $limit ) ];
491 $fileQuery = LocalFile::getQueryInfo();
493 $fileQuery[
'tables'],
494 $fileQuery[
'fields'],
495 'img_name ' .
$dbr->buildLike( $prefix,
$dbr->anyString() ),
503 foreach (
$res as $row ) {
542 return static function ( $index ) {
554 return $this->hasAccessibleSharedCache;
560 ? $this->wanCache->makeGlobalKey(
561 'filerepo-' . $kClassSuffix,
578 function () use ( $key ) {
579 $this->wanCache->delete( $key );
586 public function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
612 public function delete( $srcRel, $archiveRel ) {
631 wfDebug( __METHOD__ .
": skipped because storage uses sha1 paths" );
632 return Status::newGood();
634 return parent::$function( ...
$args );
648 return $this->useJsonMetadata;
668 return $this->splitMetadataThreshold;
672 return $this->updateCompatibleMetadata;
676 return $this->reserializeMetadata;
686 if ( !$this->blobStore ) {
687 $this->blobStore = MediaWikiServices::getInstance()->getBlobStoreFactory()
688 ->newBlobStore( $this->dbDomain );
690 return $this->blobStore;
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Proxy backend that manages file layout rewriting for FileRepo.
doOperation(array $op, array $opts=[])
Same as doOperations() except it takes a single operation.
Base class for file repositories.
assertWritableRepo()
Throw an exception if this repo is read-only by design.
newGood( $value=null)
Create a new good result.
getLocalCacheKey( $kClassSuffix,... $components)
Get a site-local, repository-qualified, WAN cache key.
hasSha1Storage()
Returns whether or not storage is SHA-1 based.
getZonePath( $zone)
Get the storage path corresponding to one of the zones.
getDeletedHashPath( $key)
Get a relative path for a deletion archive key, e.g.
getNameFromTitle( $title)
Get the name of a file from its title.
newFile( $title, $time=false)
Create a new File object from the local repository.
getInfo()
Return information about the repository.
Implements some public methods and some protected utility functions which are required by multiple ch...
Local repository that stores files in the local filesystem and registers them in the wiki's own datab...
skipWriteOperationIfSha1( $function, array $args)
Skips the write operation if storage is sha1-based, executes it normally otherwise.
int null $splitMetadataThreshold
getDBFactory()
Get a callback to get a DB handle given an index (DB_REPLICA/DB_PRIMARY)
getSharedCacheKey( $kClassSuffix,... $components)
Get a global, repository-qualified, WAN cache key.
isMetadataUpdateEnabled()
isSplitMetadataEnabled()
Returns true if files should split up large metadata, storing parts of it in the BlobStore.
deletedFileHasKey( $key, $lock=null)
Check if a deleted (filearchive) file has this sha1 key.
callable $oldFileFactoryKey
isJsonMetadataEnabled()
Returns true if files should store metadata in JSON format.
cleanupBatch(array $files, $flags=0)
Deletes a batch of files.
publishBatch(array $ntuples, $flags=0)
Publish a batch of files.
findFiles(array $items, $flags=0)
Find many files at once.
findFilesByPrefix( $prefix, $limit)
Return an array of files where the name starts with $prefix.
findBySha1s(array $hashes)
Get an array of arrays or iterators of file objects for files that have the given SHA-1 content hashe...
getBlobStore()
Get a BlobStore for storing and retrieving large metadata, or null if that can't be done.
callable $oldFileFromRowFactory
string $dbDomain
DB domain of the repo wiki.
invalidateImageRedirect( $title)
Invalidates image redirect cache related to that image.
cleanupDeletedBatch(array $storageKeys)
Delete files in the deleted directory if they are not referenced in the filearchive table.
bool $updateCompatibleMetadata
getPrimaryDB()
Get a connection to the primary DB.
checkRedirect( $title)
Checks if there is a redirect named as $title.
hasAcessibleSharedCache()
Check whether the repo has a shared cache, accessible from the current site context.
bool $hasAccessibleSharedCache
Whether shared cache keys are exposed/accessible.
getReplicaDB()
Get a connection to the replica DB.
store( $srcPath, $dstZone, $dstRel, $flags=0)
Store a file to a given destination.
publish( $src, $dstRel, $archiveRel, $flags=0, array $options=[])
Copy or move a file either from a storage path, virtual URL, or file system path, into this repositor...
getMasterDB()
Get a connection to the primary DB.
storeBatch(array $triplets, $flags=0)
Store a batch of files.
getSplitMetadataThreshold()
Get the threshold above which metadata items should be split into separate storage,...
callable $fileFromRowFactory
__construct(array $info=null)
deleteBatch(array $sourceDestPairs)
Move a group of files to the deletion archive.
hiddenFileHasKey( $key, $lock=null)
Check if a hidden (revision delete) file has this sha1 key.
static getHashFromKey( $key)
Gets the SHA1 hash from a storage key.
newFromArchiveName( $title, $archiveName)
bool $reserializeMetadata
isMetadataReserializeEnabled()
findBySha1( $hash)
Get an array or iterator of file objects for files that have a given SHA-1 content hash.
Interface for objects (potentially) representing an editable wiki page.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!is_readable( $file)) $ext