47 if ( self::$instance ==
null ) {
48 self::$instance =
new self();
49 self::$instance->initFromGlobals();
59 self::$instance =
null;
74 foreach ( $repos as $info ) {
75 $backendName = $info[
'backend'];
76 if ( is_object( $backendName ) || isset( $this->backends[$backendName] ) ) {
79 $repoName = $info[
'name'];
81 $directory = $info[
'directory'];
82 $deletedDir = $info[
'deletedDir'] ??
false;
83 $thumbDir = $info[
'thumbDir'] ??
"{$directory}/thumb";
84 $transcodedDir = $info[
'transcodedDir'] ??
"{$directory}/transcoded";
87 'name' => $backendName,
88 'class' => FSFileBackend::class,
89 'lockManager' =>
'fsLockManager',
91 "{$repoName}-public" =>
"{$directory}",
92 "{$repoName}-thumb" => $thumbDir,
93 "{$repoName}-transcoded" => $transcodedDir,
94 "{$repoName}-deleted" => $deletedDir,
95 "{$repoName}-temp" =>
"{$directory}/temp"
97 'fileMode' => $info[
'fileMode'] ?? 0644,
113 protected function register( array $configs, $readOnlyReason = null ) {
114 foreach ( $configs as $config ) {
115 if ( !isset( $config[
'name'] ) ) {
116 throw new InvalidArgumentException(
"Cannot register a backend with no name." );
118 $name = $config[
'name'];
119 if ( isset( $this->backends[$name] ) ) {
120 throw new LogicException(
"Backend with name '$name' already registered." );
121 } elseif ( !isset( $config[
'class'] ) ) {
122 throw new InvalidArgumentException(
"Backend with name '$name' has no class." );
124 $class = $config[
'class'];
126 if ( isset( $config[
'domainId'] ) ) {
127 $domainId = $config[
'domainId'];
128 } elseif ( isset( $config[
'wikiId'] ) ) {
129 $domainId = $config[
'wikiId'];
132 $ld = WikiMap::getCurrentWikiDbDomain();
133 $domainId = strlen( $ld->getTablePrefix() )
134 ?
"{$ld->getDatabase()}-{$ld->getTablePrefix()}"
135 : $ld->getDatabase();
139 $wikiId = WikiMap::getWikiIdFromDbDomain( $ld );
140 if ( $ld->getSchema() !==
null && $domainId !== $wikiId ) {
142 "\$wgFileBackend entry '$name' should have 'domainId' set.\n" .
143 "Legacy default 'domainId' is '$domainId' but wiki ID is '$wikiId'."
147 $config[
'domainId'] = $domainId;
148 $config[
'readOnly'] = $config[
'readOnly'] ?? $readOnlyReason;
150 unset( $config[
'class'] );
151 $this->backends[$name] = [
166 public function get( $name ) {
168 if ( !isset( $this->backends[$name][
'instance'] ) ) {
169 $config = $this->
config( $name );
171 $class = $config[
'class'];
172 if ( $class === FileBackendMultiWrite::class ) {
174 foreach ( $config[
'backends'] as $index => $beConfig ) {
175 if ( isset( $beConfig[
'template'] ) ) {
178 $config[
'backends'][$index] += $this->
config( $beConfig[
'template'] );
183 $this->backends[$name][
'instance'] =
new $class( $config );
186 return $this->backends[$name][
'instance'];
197 if ( !isset( $this->backends[$name] ) ) {
198 throw new InvalidArgumentException(
"No backend defined with the name '$name'." );
201 $config = $this->backends[$name][
'config'];
202 $services = MediaWikiServices::getInstance();
207 'mimeCallback' => [ $this,
'guessMimeInternal' ],
208 'obResetFunc' =>
'wfResetOutputBuffers',
209 'streamMimeFunc' => [ StreamFile::class,
'contentTypeFromPath' ],
210 'tmpFileFactory' => $services->getTempFSFileFactory(),
211 'statusWrapper' => [ Status::class,
'wrap' ],
212 'wanCache' => $services->getMainWANObjectCache(),
213 'srvCache' => ObjectCache::getLocalServerInstance(
'hash' ),
214 'logger' => LoggerFactory::getInstance(
'FileOperation' ),
215 'profiler' => function ( $section ) {
216 return Profiler::instance()->scopedProfileIn( $section );
223 'class' => $this->backends[$name][
'class'],
225 LockManagerGroup::singleton( $config[
'domainId'] )
226 ->get( $config[
'lockManager'] ),
227 'fileJournal' => isset( $config[
'fileJournal'] )
242 if ( $backend !==
null && isset( $this->backends[$backend] ) ) {
243 return $this->
get( $backend );
257 $magic = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
260 $type = $magic->guessTypesForExtension(
$ext );
262 if ( !
$type && $fsPath ) {
263 $type = $magic->guessMimeType( $fsPath,
false );
265 $tmpFile = MediaWikiServices::getInstance()->getTempFSFileFactory()
266 ->newTempFSFile(
'mime_',
'' );
267 file_put_contents( $tmpFile->getPath(),
$content );
268 $type = $magic->guessMimeType( $tmpFile->getPath(),
false );
270 return $type ?:
'unknown/unknown';
$wgFileBackends
File backend structure configuration.
$wgDirectoryMode
Default value for chmoding of new directories.
$wgLocalFileRepo
File repository structures.
$wgForeignFileRepos
Enable the use of files from one or more other wikis.
wfConfiguredReadOnlyReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
Class to handle file backend registration.
static destroySingleton()
Destroy the singleton instance.
config( $name)
Get the config array for a backend object with a given name.
guessMimeInternal( $storagePath, $content, $fsPath)
initFromGlobals()
Register file backends from the global variables.
static FileBackendGroup $instance
array $backends
(name => ('class' => string, 'config' => array, 'instance' => object))
backendFromPath( $storagePath)
Get an appropriate backend object from a storage path.
static splitStoragePath( $storagePath)
Split a storage path into a backend name, a container name, and a relative file path.
static extensionFromPath( $path, $case='lowercase')
Get the final extension from a storage or FS path.
static factory(array $config, $backend)
Create an appropriate FileJournal object from config.
if(!is_readable( $file)) $ext