42 $request = $this->
getMain()->getRequest();
44 $this->mParams[
'async'] = ( $this->mParams[
'async'] &&
45 $this->
getConfig()->get(
'EnableAsyncUploads' ) );
47 $this->mParams[
'file'] = $request->getFileName(
'file' );
48 $this->mParams[
'chunk'] = $request->getFileName(
'chunk' );
51 if ( !$this->mParams[
'filekey'] && $this->mParams[
'sessionkey'] ) {
52 $this->mParams[
'filekey'] = $this->mParams[
'sessionkey'];
59 } elseif ( !isset( $this->mUpload ) ) {
60 $this->
dieDebug( __METHOD__,
'No upload module set' );
71 $status = $this->mUpload->fetchFile();
72 if ( !$status->isGood() ) {
77 if ( $this->mParams[
'chunk'] ) {
79 if ( $this->mParams[
'filesize'] > $maxSize ) {
82 if ( !$this->mUpload->getTitle() ) {
85 } elseif ( $this->mParams[
'async'] && $this->mParams[
'filekey'] ) {
88 wfDebug( __METHOD__ .
" about to verify\n" );
95 if ( !$this->mParams[
'stash'] ) {
96 $permErrors = $this->mUpload->verifyTitlePermissions( $user );
97 if ( $permErrors !==
true ) {
113 if ( $result[
'result'] ===
'Success' ) {
114 $imageinfo = $this->mUpload->getImageInfo( $this->
getResult() );
119 $this->mUpload->cleanupTempFile();
128 if ( $warnings && !$this->mParams[
'ignorewarnings'] ) {
131 } elseif ( $this->mParams[
'chunk'] ) {
134 } elseif ( $this->mParams[
'stash'] ) {
157 $result[
'result'] =
'Success';
158 if ( $warnings && count( $warnings ) > 0 ) {
159 $result[
'warnings'] = $warnings;
175 $result[
'result'] =
'Warning';
176 $result[
'warnings'] = $warnings;
192 if ( $warnings && count( $warnings ) > 0 ) {
193 $result[
'warnings'] = $warnings;
196 $request = $this->
getMain()->getRequest();
197 $chunkPath = $request->getFileTempname(
'chunk' );
198 $chunkSize = $request->getUpload(
'chunk' )->getSize();
199 $totalSoFar = $this->mParams[
'offset'] + $chunkSize;
200 $minChunkSize = $this->
getConfig()->get(
'MinUploadChunkSize' );
203 if ( $totalSoFar > $this->mParams[
'filesize'] ) {
208 if ( $totalSoFar != $this->mParams[
'filesize'] && $chunkSize < $minChunkSize ) {
212 if ( $this->mParams[
'offset'] == 0 ) {
215 $filekey = $this->mParams[
'filekey'];
221 $this->
dieWithError(
'apierror-stashfailed-nosession',
'stashfailed' );
222 } elseif ( $progress[
'result'] !==
'Continue' || $progress[
'stage'] !==
'uploading' ) {
223 $this->
dieWithError(
'apierror-stashfailed-complete',
'stashfailed' );
226 $status = $this->mUpload->addChunk(
227 $chunkPath, $chunkSize, $this->mParams[
'offset'] );
228 if ( !$status->isGood() ) {
230 'offset' => $this->mUpload->getOffset(),
238 if ( $totalSoFar == $this->mParams[
'filesize'] ) {
239 if ( $this->mParams[
'async'] ) {
243 [
'result' =>
'Poll',
249 'filename' => $this->mParams[
'filename'],
250 'filekey' => $filekey,
254 $result[
'result'] =
'Poll';
255 $result[
'stage'] =
'queued';
257 $status = $this->mUpload->concatenateChunks();
258 if ( !$status->isGood() ) {
262 [
'result' =>
'Failure',
'stage' =>
'assembling',
'status' => $status ]
270 $result[
'warnings'] = $warnings;
276 $this->mUpload->stash->removeFile( $filekey );
277 $filekey = $this->mUpload->getStashFile()->getFileKey();
279 $result[
'result'] =
'Success';
286 'result' =>
'Continue',
287 'stage' =>
'uploading',
288 'offset' => $totalSoFar,
292 $result[
'result'] =
'Continue';
293 $result[
'offset'] = $totalSoFar;
296 $result[
'filekey'] = $filekey;
314 $isPartial = (bool)$this->mParams[
'chunk'];
316 $status = $this->mUpload->tryStashFile( $this->
getUser(), $isPartial );
318 if ( $status->isGood() && !$status->getValue() ) {
320 $status->fatal(
new ApiMessage(
'apierror-stashinvalidfile',
'stashfailed' ) );
323 $debugMessage =
'Stashing temporary file failed: ' . get_class( $e ) .
' ' . $e->getMessage();
324 wfDebug( __METHOD__ .
' ' . $debugMessage .
"\n" );
326 $e, [
'wrap' =>
new ApiMessage(
'apierror-stashexception',
'stashfailed' ) ]
330 if ( $status->isGood() ) {
331 $stashFile = $status->getValue();
332 $data[
'filekey'] = $stashFile->getFileKey();
334 $data[
'sessionkey'] = $data[
'filekey'];
335 return $data[
'filekey'];
338 if ( $status->getMessage()->getKey() ===
'uploadstash-exception' ) {
341 list( $exceptionType, $message ) = $status->getMessage()->getParams();
342 $debugMessage =
'Stashing temporary file failed: ' . $exceptionType .
' ' . $message;
343 wfDebug( __METHOD__ .
' ' . $debugMessage .
"\n" );
347 if ( $failureMode !==
'optional' ) {
368 $data[
'invalidparameter'] = $parameter;
372 foreach ( $errors as $error ) {
374 $msg->setApiData( $msg->getApiData() + $data );
391 foreach ( $status->getErrors() as $error ) {
393 if ( $moreExtraData ) {
394 $msg->setApiData( $msg->getApiData() + $moreExtraData );
410 $request = $this->
getMain()->getRequest();
413 if ( !$this->mParams[
'chunk'] ) {
415 'filekey',
'file',
'url' );
419 if ( $this->mParams[
'filekey'] && $this->mParams[
'checkstatus'] ) {
422 $this->
dieWithError(
'apierror-upload-missingresult',
'missingresult' );
423 } elseif ( !$progress[
'status']->isGood() ) {
426 if ( isset( $progress[
'status']->value[
'verification'] ) ) {
429 if ( isset( $progress[
'status']->value[
'warnings'] ) ) {
432 $progress[
'warnings'] = $warnings;
435 unset( $progress[
'status'] );
437 if ( isset( $progress[
'imageinfo'] ) ) {
438 $imageinfo = $progress[
'imageinfo'];
439 unset( $progress[
'imageinfo'] );
453 if ( is_null( $this->mParams[
'filename'] ) ) {
454 $this->
dieWithError( [
'apierror-missingparam',
'filename' ] );
457 if ( $this->mParams[
'chunk'] ) {
460 if ( isset( $this->mParams[
'filekey'] ) ) {
461 if ( $this->mParams[
'offset'] === 0 ) {
462 $this->
dieWithError(
'apierror-upload-filekeynotallowed',
'filekeynotallowed' );
466 $this->mUpload->continueChunks(
467 $this->mParams[
'filename'],
468 $this->mParams[
'filekey'],
469 $request->getUpload(
'chunk' )
472 if ( $this->mParams[
'offset'] !== 0 ) {
473 $this->
dieWithError(
'apierror-upload-filekeyneeded',
'filekeyneeded' );
477 $this->mUpload->initialize(
478 $this->mParams[
'filename'],
479 $request->getUpload(
'chunk' )
482 } elseif ( isset( $this->mParams[
'filekey'] ) ) {
491 $this->mUpload->initialize(
492 $this->mParams[
'filekey'], $this->mParams[
'filename'], !$this->mParams[
'async']
494 } elseif ( isset( $this->mParams[
'file'] ) ) {
498 if ( $this->mParams[
'async'] ) {
499 $this->
dieWithError(
'apierror-cannot-async-upload-file' );
503 $this->mUpload->initialize(
504 $this->mParams[
'filename'],
505 $request->getUpload(
'file' )
507 } elseif ( isset( $this->mParams[
'url'] ) ) {
522 $this->mUpload->
initialize( $this->mParams[
'filename'],
523 $this->mParams[
'url'] );
536 $permission = $this->mUpload->isAllowed( $user );
538 if ( $permission !==
true ) {
539 if ( !$user->isLoggedIn() ) {
540 $this->
dieWithError( [
'apierror-mustbeloggedin', $this->
msg(
'action-upload' ) ] );
547 if ( $user->isBlockedFromUpload() ) {
552 if ( $user->isBlockedGlobally() ) {
561 $verification = $this->mUpload->verifyUpload();
574 switch ( $verification[
'status'] ) {
582 'illegal-filename', null, [
'filename' => $verification[
'filtered'] ]
606 'filetype' => $verification[
'finalExt'],
607 'allowed' => array_values( array_unique( $this->
getConfig()->
get(
'FileExtensions' ) ) )
609 $extensions = array_unique( $this->
getConfig()->
get(
'FileExtensions' ) );
611 'filetype-banned-type',
614 count( $extensions ),
619 if ( isset( $verification[
'blacklistedExt'] ) ) {
621 $msg[4] = count( $verification[
'blacklistedExt'] );
622 $extradata[
'blacklisted'] = array_values( $verification[
'blacklistedExt'] );
625 $msg[1] = $verification[
'finalExt'];
629 $this->
dieWithError( $msg,
'filetype-banned', $extradata );
635 $details = array_merge( [ $msg->getKey() ], $msg->getParams() );
637 $details = $verification[
'details'];
640 $msg->setApiData( $msg->getApiData() + [
'details' => $details ] );
646 $msg = $verification[
'error'] ===
'' ?
'hookaborted' : $verification[
'error'];
647 $this->
dieWithError( $msg,
'hookaborted', [
'details' => $verification[
'error'] ] );
650 $this->
dieWithError(
'apierror-unknownerror-nocode',
'unknown-error',
651 [
'details' => [
'code' => $verification[
'status'] ] ] );
674 if ( isset( $warnings[
'duplicate'] ) ) {
676 foreach ( $warnings[
'duplicate'] as $dupe ) {
677 $dupes[] = $dupe[
'fileName'];
680 $warnings[
'duplicate'] = $dupes;
683 if ( isset( $warnings[
'exists'] ) ) {
684 $warning = $warnings[
'exists'];
685 unset( $warnings[
'exists'] );
686 $localFile = $warning[
'normalizedFile'] ?? $warning[
'file'];
687 $warnings[$warning[
'warning']] = $localFile[
'fileName'];
690 if ( isset( $warnings[
'no-change'] ) ) {
691 $file = $warnings[
'no-change'];
692 unset( $warnings[
'no-change'] );
694 $warnings[
'nochange'] = [
699 if ( isset( $warnings[
'duplicate-version'] ) ) {
701 foreach ( $warnings[
'duplicate-version'] as $dupe ) {
703 'timestamp' =>
wfTimestamp( TS_ISO_8601, $dupe[
'timestamp'] )
706 unset( $warnings[
'duplicate-version'] );
709 $warnings[
'duplicateversions'] = $dupes;
723 switch ( get_class( $e ) ) {
724 case UploadStashFileNotFoundException::class:
725 $wrap =
'apierror-stashedfilenotfound';
727 case UploadStashBadPathException::class:
728 $wrap =
'apierror-stashpathinvalid';
730 case UploadStashFileException::class:
731 $wrap =
'apierror-stashfilestorage';
733 case UploadStashZeroLengthFileException::class:
734 $wrap =
'apierror-stashzerolength';
736 case UploadStashNotLoggedInException::class:
738 [
'apierror-mustbeloggedin', $this->
msg(
'action-upload' ) ],
'stashnotloggedin' 740 case UploadStashWrongOwnerException::class:
741 $wrap =
'apierror-stashwrongowner';
743 case UploadStashNoSuchKeyException::class:
744 $wrap =
'apierror-stashnosuchfilekey';
747 $wrap = [
'uploadstash-exception', get_class( $e ) ];
764 if ( is_null( $this->mParams[
'text'] ) ) {
765 $this->mParams[
'text'] = $this->mParams[
'comment'];
769 $file = $this->mUpload->getLocalFile();
777 $this->mParams[
'watchlist'],
$file->getTitle(),
'watchdefault' 780 if ( !$watch && $this->mParams[
'watchlist'] ==
'preferences' && !
$file->exists() ) {
788 if ( $this->mParams[
'watch'] ) {
792 if ( $this->mParams[
'tags'] ) {
794 if ( !$status->isOK() ) {
801 if ( $this->mParams[
'async'] ) {
803 if ( $progress && $progress[
'result'] ===
'Poll' ) {
804 $this->
dieWithError(
'apierror-upload-inprogress',
'publishfailed' );
808 $this->mParams[
'filekey'],
809 [
'result' =>
'Poll',
'stage' =>
'queued',
'status' =>
Status::newGood() ]
814 'filename' => $this->mParams[
'filename'],
815 'filekey' => $this->mParams[
'filekey'],
816 'comment' => $this->mParams[
'comment'],
817 'tags' => $this->mParams[
'tags'],
818 'text' => $this->mParams[
'text'],
823 $result[
'result'] =
'Poll';
824 $result[
'stage'] =
'queued';
827 $status = $this->mUpload->performUpload( $this->mParams[
'comment'],
828 $this->mParams[
'text'], $watch, $this->
getUser(), $this->mParams[
'tags'] );
830 if ( !$status->isGood() ) {
833 $result[
'result'] =
'Success';
836 $result[
'filename'] =
$file->getName();
837 if ( $warnings && count( $warnings ) > 0 ) {
838 $result[
'warnings'] = $warnings;
879 'ignorewarnings' =>
false,
904 'checkstatus' =>
false,
916 'action=upload&filename=Wiki.png' .
917 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC' 918 =>
'apihelp-upload-example-url',
919 'action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC' 920 =>
'apihelp-upload-example-filekey',
925 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
static newFatal( $message,... $parameters)
Factory function for fatal errors.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below...
getErrorFormatter()
Get the error formatter.
handleStashException( $e)
Handles a stash exception, giving a useful error to the user.
getResult()
Get the result object.
Implements uploading from previously stored file.
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
getMain()
Get the main module.
dieBlocked(AbstractBlock $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
static getSessionStatus(User $user, $statusKey)
Get the current status of a chunked upload (used for polling)
const PARAM_MAX
(integer) Max value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
getContextResult()
Get an upload result based on upload context.
transformWarnings( $warnings)
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user...
verifyUpload()
Performs file verification, dies on error.
static getMaxUploadSize( $forType=null)
Get the MediaWiki maximum uploaded file size for given type of upload, based on $wgMaxUploadSize.
static isAllowedHost( $url)
Checks whether the URL is for an allowed host The domains in the whitelist can include wildcard chara...
requireOnlyOneParameter( $params,... $required)
Die if none or more than one of a certain set of parameters is set and not false. ...
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Implements uploading from a HTTP resource.
initialize( $name, $url)
Entry point for API upload.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
performUpload( $warnings)
Perform the actual upload.
static isEnabled()
Checks if the upload from URL feature is enabled.
Implements regular file uploads.
getWatchlistValue( $watchlist, $titleObj, $userOption=null)
Return true if we're to watch the page, false if not, null if no change.
static isAllowedUrl( $url)
Checks whether the URL is not allowed.
Upload a file from the upload stash into the local file repo.
getChunkResult( $warnings)
Get the result of a chunk upload.
static newGood( $value=null)
Factory function for good results.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
dieStatusWithCode( $status, $overrideCode, $moreExtraData=null)
Like dieStatus(), but always uses $overrideCode for the error code, unless the code comes from IApiMe...
getApiWarnings()
Check warnings.
checkPermissions( $user)
Checks that the user has permissions to perform this upload.
Assemble the segments of a chunked upload.
getContext()
Get the base IContextSource object.
Implements uploading from chunks.
Extension of Message implementing IApiMessage.
static makeWarningsSerializable( $warnings)
Convert the warnings array returned by checkWarnings() to something that can be serialized.
getModuleName()
Get the name of the module being executed by this instance.
const MIN_LENGTH_PARTNAME
static isEnabled()
Returns true if uploads are enabled.
static isThrottled( $user)
Returns true if the user has surpassed the upload rate limit, false otherwise.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
exportSession()
Export the resolved user IP, HTTP headers, user ID, and session ID.
selectUploadModule()
Select an upload module and set it to mUpload.
performStash( $failureMode, &$data=null)
Stash the file and add the file key, or error information if it fails, to the data.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
dieRecoverableError( $errors, $parameter=null)
Throw an error that the user can recover from by providing a better value for $parameter.
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
const WINDOWS_NONASCII_FILENAME
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
This abstract class implements many basic API functions, and is the base of all API classes...
static singleton( $domain=false)
getStashResult( $warnings)
Get Stash Result, throws an exception if the file could not be stashed.
const PARAM_DEPRECATED
(boolean) Is the parameter deprecated (will show a warning)?
getWarningsResult( $warnings)
Get Warnings Result.
static setSessionStatus(User $user, $statusKey, $value)
Set the current status of a chunked upload (used for polling)
checkVerification(array $verification)
Performs file verification, dies on error.
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
UploadBase UploadFromChunks $mUpload
static listParam(array $list, $type='text')
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.