61 private const MAX_US_PROPS_SIZE = 65535;
97 $this->user = $user ?? RequestContext::getMain()->getUser();
113 public function getFile( $key, $noAuth =
false ) {
114 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
116 wfMessage(
'uploadstash-bad-path-bad-format', $key )
120 if ( !$noAuth && !$this->user->isRegistered() ) {
126 if ( !isset( $this->fileMetadata[$key] ) ) {
133 if ( !isset( $this->fileMetadata[$key] ) ) {
135 wfMessage(
'uploadstash-file-not-found', $key )
144 isset( $this->fileMetadata[$key][
'us_props'] ) && strlen( $this->fileMetadata[$key][
'us_props'] )
146 $this->fileProps[$key] = unserialize( $this->fileMetadata[$key][
'us_props'] );
148 wfDebug( __METHOD__ .
" fetched props for $key from file" );
149 $path = $this->fileMetadata[$key][
'us_path'];
150 $this->fileProps[$key] = $this->repo->getFileProps(
$path );
154 if ( !$this->files[$key]->exists() ) {
155 wfDebug( __METHOD__ .
" tried to get file at $key, but it doesn't exist" );
162 if ( !$noAuth && $this->fileMetadata[$key][
'us_user'] != $this->user->getId() ) {
164 wfMessage(
'uploadstash-wrong-owner', $key )
168 return $this->files[$key];
180 return $this->fileMetadata[$key];
192 return $this->fileProps[$key];
209 if ( !is_file(
$path ) ) {
210 wfDebug( __METHOD__ .
" tried to stash file at '$path', but it doesn't exist" );
218 $mwProps =
new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
221 wfDebug( __METHOD__ .
" stashing file at '$path'" );
225 $extension = self::getExtensionForPath(
$path );
226 if ( !preg_match(
"/\\.\\Q$extension\\E$/",
$path ) ) {
227 $pathWithGoodExtension =
"$path.$extension";
229 $pathWithGoodExtension =
$path;
237 [ $usec, $sec ] = explode(
' ', microtime() );
238 $usec = substr( $usec, 2 );
239 $key = Wikimedia\base_convert( $sec . $usec, 10, 36 ) .
'.' .
240 Wikimedia\base_convert( (
string)mt_rand(), 10, 36 ) .
'.' .
241 $this->user->getId() .
'.' .
246 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
248 wfMessage(
'uploadstash-bad-path-bad-format', $key )
252 wfDebug( __METHOD__ .
" key for '$path': $key" );
255 $storeStatus = $this->repo->storeTemp( basename( $pathWithGoodExtension ),
$path );
257 if ( !$storeStatus->isOK() ) {
266 foreach ( $storeStatus->getMessages(
'error' ) as $msg ) {
269 foreach ( $storeStatus->getMessages(
'warning' ) as $msg ) {
275 $stashPath = $storeStatus->value;
278 if ( !$this->user->isRegistered() ) {
285 wfDebug( __METHOD__ .
" inserting $stashPath under $key" );
286 $dbw = $this->repo->getPrimaryDB();
288 $serializedFileProps = serialize(
$fileProps );
289 if ( strlen( $serializedFileProps ) > self::MAX_US_PROPS_SIZE ) {
294 $serializedFileProps = serialize(
$fileProps );
298 'us_user' => $this->user->getId(),
300 'us_orig_path' =>
$path,
301 'us_path' => $stashPath,
302 'us_props' => $dbw->encodeBlob( $serializedFileProps ),
310 'us_source_type' => $sourceType,
311 'us_timestamp' => $dbw->timestamp(),
312 'us_status' =>
'finished'
315 $dbw->newInsertQueryBuilder()
316 ->insertInto(
'uploadstash' )
318 ->caller( __METHOD__ )->execute();
322 $insertRow[
'us_id'] = $dbw->insertId();
324 $this->fileMetadata[$key] = $insertRow;
326 # create the UploadStashFile object for this file.
340 if ( !$this->user->isRegistered() ) {
346 wfDebug( __METHOD__ .
' clearing all rows for user ' . $this->user->getId() );
347 $dbw = $this->repo->getPrimaryDB();
348 $dbw->newDeleteQueryBuilder()
349 ->deleteFrom(
'uploadstash' )
350 ->where( [
'us_user' => $this->user->getId() ] )
351 ->caller( __METHOD__ )->execute();
355 $this->fileMetadata = [];
369 if ( !$this->user->isRegistered() ) {
375 $dbw = $this->repo->getPrimaryDB();
379 $row = $dbw->newSelectQueryBuilder()
380 ->select(
'us_user' )
381 ->from(
'uploadstash' )
382 ->where( [
'us_key' => $key ] )
383 ->caller( __METHOD__ )->fetchRow();
387 wfMessage(
'uploadstash-no-such-key', $key )
391 if ( $row->us_user != $this->user->getId() ) {
393 wfMessage(
'uploadstash-wrong-owner', $key )
407 wfDebug( __METHOD__ .
" clearing row $key" );
412 $dbw = $this->repo->getPrimaryDB();
414 $dbw->newDeleteQueryBuilder()
415 ->deleteFrom(
'uploadstash' )
416 ->where( [
'us_key' => $key ] )
417 ->caller( __METHOD__ )->execute();
422 $this->files[$key]->remove();
424 unset( $this->files[$key] );
425 unset( $this->fileMetadata[$key] );
437 if ( !$this->user->isRegistered() ) {
443 $res = $this->repo->getReplicaDB()->newSelectQueryBuilder()
445 ->from(
'uploadstash' )
446 ->where( [
'us_user' => $this->user->getId() ] )
447 ->caller( __METHOD__ )->fetchResultSet();
449 if ( $res->numRows() == 0 ) {
456 foreach ( $res as $row ) {
457 $keys[] = $row->us_key;
473 $prohibitedFileExtensions = MediaWikiServices::getInstance()
474 ->getMainConfig()->get( MainConfigNames::ProhibitedFileExtensions );
476 $n = strrpos(
$path,
'.' );
478 if ( $n !==
false ) {
479 $extension = $n ? substr(
$path, $n + 1 ) :
'';
482 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
483 $mimeType = $magic->guessMimeType(
$path );
484 $extension = $magic->getExtensionFromMimeTypeOrNull( $mimeType ) ??
'';
487 $extension = File::normalizeExtension( $extension );
488 if ( in_array( $extension, $prohibitedFileExtensions ) ) {
510 $dbr = $this->repo->getPrimaryDB();
512 $dbr = $this->repo->getReplicaDB();
515 $row = $dbr->newSelectQueryBuilder()
517 'us_user',
'us_key',
'us_orig_path',
'us_path',
'us_props',
518 'us_size',
'us_sha1',
'us_mime',
'us_media_type',
519 'us_image_width',
'us_image_height',
'us_image_bits',
520 'us_source_type',
'us_timestamp',
'us_status',
522 ->from(
'uploadstash' )
523 ->where( [
'us_key' => $key ] )
524 ->caller( __METHOD__ )->fetchRow();
526 if ( !is_object( $row ) ) {
531 $this->fileMetadata[$key] = (array)$row;
532 $this->fileMetadata[$key][
'us_props'] = $dbr->decodeBlob( $row->us_props );
547 $this->fileMetadata[$key][
'us_path'],
549 $this->fileMetadata[$key][
'us_sha1']
551 if ( $file->getSize() === 0 ) {
556 $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.
Base class for file repositories.
Local repository that stores files in the local filesystem and registers them in the wiki's own datab...
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