77 parent::__construct( $info );
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' );
144 wfDebug( __METHOD__ .
": skipped because storage uses sha1 paths" );
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' ] : []
206 return (
bool)$dbw->selectField(
'oldimage',
'1',
209 'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(),
".$ext" ),
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 )
272 [
'pcTTL' => WANObjectCache::TTL_PROC_LONG ]
276 if ( $redirDbKey !==
' ' && strval( $redirDbKey ) !==
'' ) {
288 foreach ( $items as $item ) {
289 if ( is_array( $item ) ) {
292 $searchSet[
$title->getDBkey()] = $item;
297 $searchSet[
$title->getDBkey()] = [];
302 $fileMatchesSearch =
static function (
File $file, array $search ) {
309 $performer = ( !empty( $search[
'private'] ) && $search[
'private'] instanceof
Authority )
316 ( empty( $search[
'time'] ) && !
$file->isOld() ) ||
317 ( !empty( $search[
'time'] ) && $search[
'time'] ===
$file->getTimestamp() )
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 ) ) {
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 ) ) {
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'] ) ) {
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;
427 $fileQuery[
'tables'],
428 $fileQuery[
'fields'],
429 [
'img_sha1' => $hash ],
431 [
'ORDER BY' =>
'img_name' ],
436 foreach (
$res as $row ) {
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 ) ];
493 $fileQuery[
'tables'],
494 $fileQuery[
'fields'],
495 'img_name ' .
$dbr->buildLike( $prefix,
$dbr->anyString() ),
503 foreach (
$res as $row ) {
542 return static function ( $index ) {
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" );
634 return parent::$function( ...
$args );
686 if ( !$this->blobStore ) {
687 $this->blobStore = MediaWikiServices::getInstance()->getBlobStoreFactory()
688 ->newBlobStore( $this->dbDomain );
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...
static normalizeTitle( $title, $exception=false)
Given a string or Title object return either a valid Title object with namespace NS_FILE or null.
static normalizeExtension( $extension)
Normalize a file extension to the common form, making it lowercase and checking some synonyms,...
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new localfile object.
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.
static newFromArchiveName( $title, $repo, $archiveName)
static getQueryInfo(array $options=[])
Return the tables, fields, and join conditions to be selected to create a new oldlocalfile object.
static getMain()
Get the RequestContext object associated with the main request.
static newGood( $value=null)
Factory function for good results.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
static getCurrentWikiDbDomain()
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