28use InvalidArgumentException;
42use Wikimedia\ObjectFactory\ObjectFactory;
68 private $mimeAnalyzer;
74 private $tmpFileFactory;
77 private $objectFactory;
105 MimeAnalyzer $mimeAnalyzer,
108 ObjectFactory $objectFactory
110 $this->options = $options;
111 $this->srvCache = $srvCache;
112 $this->wanCache = $wanCache;
113 $this->mimeAnalyzer = $mimeAnalyzer;
114 $this->lmgFactory = $lmgFactory;
115 $this->tmpFileFactory = $tmpFileFactory;
116 $this->objectFactory = $objectFactory;
123 $repos = array_merge(
125 foreach ( $repos as $info ) {
126 $backendName = $info[
'backend'];
127 if ( is_object( $backendName ) || isset( $this->backends[$backendName] ) ) {
130 $repoName = $info[
'name'];
132 $directory = $info[
'directory'];
133 $deletedDir = $info[
'deletedDir'] ??
false;
134 $thumbDir = $info[
'thumbDir'] ??
"{$directory}/thumb";
135 $transcodedDir = $info[
'transcodedDir'] ??
"{$directory}/transcoded";
136 $lockManager = $info[
'lockManager'] ??
'fsLockManager';
139 'name' => $backendName,
140 'class' => FSFileBackend::class,
141 'lockManager' => $lockManager,
142 'containerPaths' => [
143 "{$repoName}-public" =>
"{$directory}",
144 "{$repoName}-thumb" => $thumbDir,
145 "{$repoName}-transcoded" => $transcodedDir,
146 "{$repoName}-deleted" => $deletedDir,
147 "{$repoName}-temp" =>
"{$directory}/temp"
149 'fileMode' => $info[
'fileMode'] ?? 0644,
164 protected function register( array $configs, $readOnlyReason = null ) {
165 foreach ( $configs as $config ) {
166 if ( !isset( $config[
'name'] ) ) {
167 throw new InvalidArgumentException(
"Cannot register a backend with no name." );
169 $name = $config[
'name'];
170 if ( isset( $this->backends[$name] ) ) {
171 throw new LogicException(
"Backend with name '$name' already registered." );
172 } elseif ( !isset( $config[
'class'] ) ) {
173 throw new InvalidArgumentException(
"Backend with name '$name' has no class." );
175 $class = $config[
'class'];
177 $config[
'domainId'] ??= $config[
'wikiId'] ?? $this->options->get(
'fallbackWikiId' );
178 $config[
'readOnly'] ??= $readOnlyReason;
180 unset( $config[
'class'] );
181 $this->backends[$name] = [
195 public function get( $name ) {
197 if ( !isset( $this->backends[$name][
'instance'] ) ) {
198 $config = $this->
config( $name );
200 $class = $config[
'class'];
201 if ( $class === FileBackendMultiWrite::class ) {
203 foreach ( $config[
'backends'] as $index => $beConfig ) {
204 if ( isset( $beConfig[
'template'] ) ) {
207 $config[
'backends'][$index] += $this->
config( $beConfig[
'template'] );
212 $this->backends[$name][
'instance'] =
new $class( $config );
215 return $this->backends[$name][
'instance'];
225 if ( !isset( $this->backends[$name] ) ) {
226 throw new InvalidArgumentException(
"No backend defined with the name '$name'." );
229 $config = $this->backends[$name][
'config'];
234 'mimeCallback' => [ $this,
'guessMimeInternal' ],
235 'obResetFunc' =>
'wfResetOutputBuffers',
236 'streamMimeFunc' => [ StreamFile::class,
'contentTypeFromPath' ],
237 'tmpFileFactory' => $this->tmpFileFactory,
238 'statusWrapper' => [ Status::class,
'wrap' ],
239 'wanCache' => $this->wanCache,
240 'srvCache' => $this->srvCache,
241 'logger' => LoggerFactory::getInstance(
'FileOperation' ),
242 'profiler' =>
static function ( $section ) {
250 'class' => $this->backends[$name][
'class'],
252 $this->lmgFactory->getLockManagerGroup( $config[
'domainId'] )
253 ->get( $config[
'lockManager'] ),
265 [ $backend, , ] = FileBackend::splitStoragePath( $storagePath );
266 if ( $backend !==
null && isset( $this->backends[$backend] ) ) {
267 return $this->
get( $backend );
282 $ext = FileBackend::extensionFromPath( $storagePath );
283 $type = $this->mimeAnalyzer->getMimeTypeFromExtensionOrNull( $ext );
285 if ( !$type && $fsPath ) {
286 $type = $this->mimeAnalyzer->guessMimeType( $fsPath,
false );
287 } elseif ( !$type && $content !==
null && $content !==
'' ) {
288 $tmpFile = $this->tmpFileFactory->newTempFSFile(
'mime_',
'' );
289 file_put_contents( $tmpFile->getPath(), $content );
290 $type = $this->mimeAnalyzer->guessMimeType( $tmpFile->getPath(),
false );
292 return $type ?:
'unknown/unknown';
296class_alias( FileBackendGroup::class,
'FileBackendGroup' );
Class for a file system (FS) based file backend.
Proxy backend that mirrors writes to several internal backends.
A class containing constants representing the names of configuration variables.
const FileBackends
Name constant for the FileBackends setting, for use with Config::get()
const LocalFileRepo
Name constant for the LocalFileRepo setting, for use with Config::get()
const ForeignFileRepos
Name constant for the ForeignFileRepos setting, for use with Config::get()
const DirectoryMode
Name constant for the DirectoryMode setting, for use with Config::get()
Profiler base class that defines the interface and some shared functionality.
Multi-datacenter aware caching interface.