64 private const MAX_US_PROPS_SIZE = 65535;
100 $this->user = $user ?? RequestContext::getMain()->getUser();
116 public function getFile( $key, $noAuth =
false ) {
117 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
119 wfMessage(
'uploadstash-bad-path-bad-format', $key )
123 if ( !$noAuth && !$this->user->isRegistered() ) {
129 if ( !isset( $this->fileMetadata[$key] ) ) {
136 if ( !isset( $this->fileMetadata[$key] ) ) {
138 wfMessage(
'uploadstash-file-not-found', $key )
147 isset( $this->fileMetadata[$key][
'us_props'] ) && strlen( $this->fileMetadata[$key][
'us_props'] )
149 $this->fileProps[$key] = unserialize( $this->fileMetadata[$key][
'us_props'] );
151 wfDebug( __METHOD__ .
" fetched props for $key from file" );
152 $path = $this->fileMetadata[$key][
'us_path'];
153 $this->fileProps[$key] = $this->repo->getFileProps(
$path );
157 if ( !$this->files[$key]->exists() ) {
158 wfDebug( __METHOD__ .
" tried to get file at $key, but it doesn't exist" );
165 if ( !$noAuth && $this->fileMetadata[$key][
'us_user'] != $this->user->getId() ) {
167 wfMessage(
'uploadstash-wrong-owner', $key )
171 return $this->files[$key];
183 return $this->fileMetadata[$key];
195 return $this->fileProps[$key];
212 if ( !is_file(
$path ) ) {
213 wfDebug( __METHOD__ .
" tried to stash file at '$path', but it doesn't exist" );
221 $mwProps =
new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
224 wfDebug( __METHOD__ .
" stashing file at '$path'" );
228 $extension = self::getExtensionForPath(
$path );
229 if ( !preg_match(
"/\\.\\Q$extension\\E$/",
$path ) ) {
230 $pathWithGoodExtension =
"$path.$extension";
232 $pathWithGoodExtension =
$path;
240 [ $usec, $sec ] = explode(
' ', microtime() );
241 $usec = substr( $usec, 2 );
242 $key = Wikimedia\base_convert( $sec . $usec, 10, 36 ) .
'.' .
243 Wikimedia\base_convert( (
string)mt_rand(), 10, 36 ) .
'.' .
244 $this->user->getId() .
'.' .
249 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
251 wfMessage(
'uploadstash-bad-path-bad-format', $key )
255 wfDebug( __METHOD__ .
" key for '$path': $key" );
258 $storeStatus = $this->repo->storeTemp( basename( $pathWithGoodExtension ),
$path );
260 if ( !$storeStatus->isOK() ) {
269 foreach ( $storeStatus->getMessages(
'error' ) as $msg ) {
272 foreach ( $storeStatus->getMessages(
'warning' ) as $msg ) {
278 $stashPath = $storeStatus->value;
281 if ( !$this->user->isRegistered() ) {
288 wfDebug( __METHOD__ .
" inserting $stashPath under $key" );
289 $dbw = $this->repo->getPrimaryDB();
291 $serializedFileProps = serialize(
$fileProps );
292 if ( strlen( $serializedFileProps ) > self::MAX_US_PROPS_SIZE ) {
297 $serializedFileProps = serialize(
$fileProps );
301 'us_user' => $this->user->getId(),
303 'us_orig_path' =>
$path,
304 'us_path' => $stashPath,
305 'us_props' => $dbw->encodeBlob( $serializedFileProps ),
313 'us_source_type' => $sourceType,
314 'us_timestamp' => $dbw->timestamp(),
315 'us_status' =>
'finished'
318 $dbw->newInsertQueryBuilder()
319 ->insertInto(
'uploadstash' )
321 ->caller( __METHOD__ )->execute();
325 $insertRow[
'us_id'] = $dbw->insertId();
327 $this->fileMetadata[$key] = $insertRow;
329 # create the UploadStashFile object for this file.
343 if ( !$this->user->isRegistered() ) {
349 wfDebug( __METHOD__ .
' clearing all rows for user ' . $this->user->getId() );
350 $dbw = $this->repo->getPrimaryDB();
351 $dbw->newDeleteQueryBuilder()
352 ->deleteFrom(
'uploadstash' )
353 ->where( [
'us_user' => $this->user->getId() ] )
354 ->caller( __METHOD__ )->execute();
358 $this->fileMetadata = [];
372 if ( !$this->user->isRegistered() ) {
378 $dbw = $this->repo->getPrimaryDB();
382 $row = $dbw->newSelectQueryBuilder()
383 ->select(
'us_user' )
384 ->from(
'uploadstash' )
385 ->where( [
'us_key' => $key ] )
386 ->caller( __METHOD__ )->fetchRow();
390 wfMessage(
'uploadstash-no-such-key', $key )
394 if ( $row->us_user != $this->user->getId() ) {
396 wfMessage(
'uploadstash-wrong-owner', $key )
410 wfDebug( __METHOD__ .
" clearing row $key" );
415 $dbw = $this->repo->getPrimaryDB();
417 $dbw->newDeleteQueryBuilder()
418 ->deleteFrom(
'uploadstash' )
419 ->where( [
'us_key' => $key ] )
420 ->caller( __METHOD__ )->execute();
425 $this->files[$key]->remove();
427 unset( $this->files[$key] );
428 unset( $this->fileMetadata[$key] );
440 if ( !$this->user->isRegistered() ) {
446 $res = $this->repo->getReplicaDB()->newSelectQueryBuilder()
448 ->from(
'uploadstash' )
449 ->where( [
'us_user' => $this->user->getId() ] )
450 ->caller( __METHOD__ )->fetchResultSet();
452 if ( $res->numRows() == 0 ) {
459 foreach ( $res as $row ) {
460 $keys[] = $row->us_key;
476 $prohibitedFileExtensions = MediaWikiServices::getInstance()
477 ->getMainConfig()->get( MainConfigNames::ProhibitedFileExtensions );
479 $n = strrpos(
$path,
'.' );
481 if ( $n !==
false ) {
482 $extension = $n ? substr(
$path, $n + 1 ) :
'';
485 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
486 $mimeType = $magic->guessMimeType(
$path );
487 $extension = $magic->getExtensionFromMimeTypeOrNull( $mimeType ) ??
'';
490 $extension = File::normalizeExtension( $extension );
491 if ( in_array( $extension, $prohibitedFileExtensions ) ) {
513 $dbr = $this->repo->getPrimaryDB();
515 $dbr = $this->repo->getReplicaDB();
518 $row = $dbr->newSelectQueryBuilder()
520 'us_user',
'us_key',
'us_orig_path',
'us_path',
'us_props',
521 'us_size',
'us_sha1',
'us_mime',
'us_media_type',
522 'us_image_width',
'us_image_height',
'us_image_bits',
523 'us_source_type',
'us_timestamp',
'us_status',
525 ->from(
'uploadstash' )
526 ->where( [
'us_key' => $key ] )
527 ->caller( __METHOD__ )->fetchRow();
529 if ( !is_object( $row ) ) {
534 $this->fileMetadata[$key] = (array)$row;
535 $this->fileMetadata[$key][
'us_props'] = $dbr->decodeBlob( $row->us_props );
550 $this->fileMetadata[$key][
'us_path'],
552 $this->fileMetadata[$key][
'us_sha1'],
553 $this->fileMetadata[$key][
'us_mime'] ??
false
555 if ( $file->getSize() === 0 ) {
560 $this->files[$key] = $file;
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
getFile()
Get the file for this page, if one exists.
MimeMagic helper wrapper.
Group all the pieces relevant to the context of a request into one instance.
A class containing constants representing the names of configuration variables.
UploadStash is intended to accomplish a few things:
static getExtensionForPath( $path)
Find or guess extension – ensuring that our extension matches our MIME type.
removeFile( $key)
Remove a particular file from the stash.
fetchFileMetadata( $key, $readFromDB=DB_REPLICA)
Helper function: do the actual database query to fetch file metadata.
getFileProps( $key)
Getter for fileProps.
clear()
Remove all files from the stash.
array $fileMetadata
cache of the file metadata that's stored in the database
array $fileProps
fileprops cache
listFiles()
List all files in the stash.
__construct(FileRepo $repo, ?UserIdentity $user=null)
Represents a temporary filestore, with metadata in the database.
getMetadata( $key)
Getter for file metadata.
removeFileNoAuth( $key)
Remove a file (see removeFile), but doesn't check ownership first.
initFile( $key)
Helper function: Initialize the UploadStashFile for a given file.
stashFile( $path, $sourceType=null, $fileProps=null)
Stash a file in a temp directory and record that we did this in the database, along with other metada...
getFile( $key, $noAuth=false)
Get a file and its metadata from the stash.
LocalRepo $repo
repository that this uses to store temp files public because we sometimes need to get a LocalFile wit...
array $files
array of initialized repo objects