49use Psr\Log\LoggerInterface;
54use Wikimedia\Timestamp\TimestampFormat as TS;
72 private LoggerInterface $log;
83 parent::__construct( $mainModule, $moduleName );
84 $this->jobQueueGroup = $jobQueueGroup;
89 $this->watchlistMaxDuration =
91 $this->watchlistManager = $watchlistManager;
92 $this->watchedItemStore = $watchedItemStore;
93 $this->userOptionsLookup = $userOptionsLookup;
94 $this->log = LoggerFactory::getInstance(
'upload' );
99 if ( !UploadBase::isEnabled() ) {
109 $this->mParams[
'async'] = $this->mParams[
'async'] &&
114 if ( !$this->mParams[
'filekey'] && $this->mParams[
'sessionkey'] ) {
115 $this->mParams[
'filekey'] = $this->mParams[
'sessionkey'];
118 if ( !$this->mParams[
'checkstatus'] ) {
127 } elseif ( !$this->mUpload ) {
141 if ( $this->mParams[
'async'] && $this->mParams[
'url'] ) {
142 $status = $this->mUpload->canFetchFile();
144 $status = $this->mUpload->fetchFile();
147 if ( !$status->isGood() ) {
148 $this->log->info(
"Unable to fetch file {filename} for {user} because {status}",
150 'user' => $this->
getUser()->getName(),
151 'status' => (
string)$status,
152 'filename' => $this->mParams[
'filename'] ??
'-',
164 if ( !$this->mParams[
'stash'] ) {
165 $status = $this->mUpload->authorizeUpload( $user );
166 if ( !$status->isGood() ) {
167 $this->dieRecoverableError( $status->getMessages(),
'filename' );
173 $result = $this->getContextResult();
183 if ( $result[
'result'] ===
'Success' ) {
189 $this->mUpload->cleanupTempFile();
202 $services->getJobQueueGroup(),
203 $services->getWatchlistManager(),
204 $services->getWatchedItemStore(),
205 $services->getUserOptionsLookup(),
206 $services->getRepoGroup(),
223 $stashFile = $upload->getStashFile();
225 $info = $this->getUploadImageInfoInternal( $stashFile,
true );
228 $info = $this->getUploadImageInfoInternal( $localFile,
false );
234 private function getUploadImageInfoInternal( File $file,
bool $stashedImageInfos ): array {
235 $result = $this->getResult();
238 if ( $stashedImageInfos ) {
239 $imParam = ApiQueryStashImageInfo::getPropertyNames();
240 $info = ApiQueryStashImageInfo::getInfo(
242 array_fill_keys( $imParam,
true ),
246 $imParam = ApiQueryImageInfo::getPropertyNames( [
'uploadwarning' ] );
247 $info = ApiQueryImageInfo::getInfo(
249 array_fill_keys( $imParam,
true ),
261 private function getContextResult() {
262 $warnings = $this->getApiWarnings();
263 if ( $warnings && !$this->mParams[
'ignorewarnings'] ) {
265 return $this->getWarningsResult( $warnings );
266 } elseif ( $this->mParams[
'chunk'] ) {
268 return $this->getChunkResult( $warnings );
269 } elseif ( $this->mParams[
'stash'] ) {
271 return $this->getStashResult( $warnings );
276 return $this->performUpload( $warnings );
284 private function getStashResult( $warnings ) {
285 $result = [
'result' =>
'Success' ];
286 if ( $warnings && count( $warnings ) > 0 ) {
287 $result[
'warnings'] = $warnings;
291 $this->performStash(
'critical', $result );
301 private function getWarningsResult( $warnings ) {
303 'result' =>
'Warning',
304 'warnings' => $warnings,
309 $this->performStash(
'optional', $result );
321 $configured = $config->
get( MainConfigNames::MinUploadChunkSize );
326 ini_get(
'post_max_size' ),
335 UploadBase::getMaxUploadSize(
'file' ),
336 UploadBase::getMaxPhpUploadSize(),
346 private function getChunkResult( $warnings ) {
349 if ( $warnings && count( $warnings ) > 0 ) {
350 $result[
'warnings'] = $warnings;
353 $chunkUpload = $this->getMain()->getUpload(
'chunk' );
354 $chunkPath = $chunkUpload->getTempName();
355 $chunkSize = $chunkUpload->getSize();
356 $totalSoFar = $this->mParams[
'offset'] + $chunkSize;
357 $minChunkSize = self::getMinUploadChunkSize( $this->getConfig() );
360 if ( $totalSoFar > $this->mParams[
'filesize'] ) {
361 $this->dieWithError(
'apierror-invalid-chunk' );
365 if ( $totalSoFar != $this->mParams[
'filesize'] && $chunkSize < $minChunkSize ) {
366 $this->dieWithError( [
'apierror-chunk-too-small', Message::numParam( $minChunkSize ) ] );
369 if ( $this->mParams[
'offset'] == 0 ) {
370 $this->log->debug(
"Started first chunk of chunked upload of {filename} for {user}",
373 'filename' => $this->mParams[
'filename'] ??
'-',
374 'filesize' => $this->mParams[
'filesize'],
375 'chunkSize' => $chunkSize
378 $filekey = $this->performStash(
'critical' );
380 $filekey = $this->mParams[
'filekey'];
383 $progress = UploadBase::getSessionStatus( $this->
getUser(), $filekey );
386 $this->log->info(
"Stash failed due to no session for {user}",
389 'filename' => $this->mParams[
'filename'] ??
'-',
390 'filekey' => $this->mParams[
'filekey'] ??
'-',
391 'filesize' => $this->mParams[
'filesize'],
392 'chunkSize' => $chunkSize
395 $this->dieWithError(
'apierror-stashfailed-nosession',
'stashfailed' );
396 } elseif ( $progress[
'result'] !==
'Continue' || $progress[
'stage'] !==
'uploading' ) {
397 $this->dieWithError(
'apierror-stashfailed-complete',
'stashfailed' );
400 $status = $this->mUpload->addChunk(
401 $chunkPath, $chunkSize, $this->mParams[
'offset'] );
402 if ( !$status->isGood() ) {
404 'offset' => $this->mUpload->getOffset(),
406 $this->log->info(
"Chunked upload stash failure {status} for {user}",
408 'status' => (
string)$status,
410 'filename' => $this->mParams[
'filename'] ??
'-',
411 'filekey' => $this->mParams[
'filekey'] ??
'-',
412 'filesize' => $this->mParams[
'filesize'],
413 'chunkSize' => $chunkSize,
414 'offset' => $this->mUpload->getOffset()
417 $this->dieStatusWithCode( $status,
'stashfailed', $extradata );
419 $this->log->debug(
"Got chunk for {filename} with offset {offset} for {user}",
422 'filename' => $this->mParams[
'filename'] ??
'-',
423 'filekey' => $this->mParams[
'filekey'] ??
'-',
424 'filesize' => $this->mParams[
'filesize'],
425 'chunkSize' => $chunkSize,
426 'offset' => $this->mUpload->getOffset()
433 if ( $totalSoFar == $this->mParams[
'filesize'] ) {
434 if ( $this->mParams[
'async'] ) {
435 UploadBase::setSessionStatus(
438 [
'result' =>
'Poll',
439 'stage' =>
'queued',
'status' => Status::newGood() ]
445 $this->jobQueueGroup->lazyPush(
new AssembleUploadChunksJob( [
446 'filename' => $this->mParams[
'filename'],
447 'filekey' => $filekey,
448 'filesize' => $this->mParams[
'filesize'],
449 'session' => $this->
getContext()->exportSession()
451 $this->log->info(
"Received final chunk of {filename} for {user}, queuing assemble job",
454 'filename' => $this->mParams[
'filename'] ??
'-',
455 'filekey' => $this->mParams[
'filekey'] ??
'-',
456 'filesize' => $this->mParams[
'filesize'],
457 'chunkSize' => $chunkSize,
460 $result[
'result'] =
'Poll';
461 $result[
'stage'] =
'queued';
463 $this->log->info(
"Received final chunk of {filename} for {user}, assembling immediately",
466 'filename' => $this->mParams[
'filename'] ??
'-',
467 'filekey' => $this->mParams[
'filekey'] ??
'-',
468 'filesize' => $this->mParams[
'filesize'],
469 'chunkSize' => $chunkSize,
473 $status = $this->mUpload->concatenateChunks();
474 if ( !$status->isGood() ) {
475 UploadBase::setSessionStatus(
478 [
'result' =>
'Failure',
'stage' =>
'assembling',
'status' => $status ]
480 $this->log->info(
"Non jobqueue assembly of {filename} failed because {status}",
483 'filename' => $this->mParams[
'filename'] ??
'-',
484 'filekey' => $this->mParams[
'filekey'] ??
'-',
485 'filesize' => $this->mParams[
'filesize'],
486 'chunkSize' => $chunkSize,
487 'status' => (
string)$status
490 $this->dieStatusWithCode( $status,
'stashfailed' );
494 $warnings = $this->getApiWarnings();
496 $result[
'warnings'] = $warnings;
501 UploadBase::setSessionStatus( $this->
getUser(), $filekey,
false );
502 $this->mUpload->stash->removeFile( $filekey );
503 $filekey = $this->mUpload->getStashFile()->getFileKey();
505 $result[
'result'] =
'Success';
508 UploadBase::setSessionStatus(
512 'result' =>
'Continue',
513 'stage' =>
'uploading',
514 'offset' => $totalSoFar,
515 'status' => Status::newGood(),
518 $result[
'result'] =
'Continue';
519 $result[
'offset'] = $totalSoFar;
522 $result[
'filekey'] = $filekey;
539 private function performStash( $failureMode, &$data = [] ) {
540 if ( $failureMode ===
'optional' && $this->mUpload->skipStashFileAttempt() ) {
544 $isPartial = (bool)$this->mParams[
'chunk'];
546 $status = $this->mUpload->tryStashFile( $this->
getUser(), $isPartial );
548 if ( $status->isGood() && !$status->getValue() ) {
550 $status->fatal(
new ApiMessage(
'apierror-stashinvalidfile',
'stashfailed' ) );
552 }
catch ( Exception $e ) {
553 $debugMessage =
'Stashing temporary file failed: ' . get_class( $e ) .
' ' . $e->getMessage();
554 $this->log->info( $debugMessage,
557 'filename' => $this->mParams[
'filename'] ??
'-',
558 'filekey' => $this->mParams[
'filekey'] ??
'-'
562 $status = Status::newFatal( $this->getErrorFormatter()->getMessageFromException(
563 $e, [
'wrap' =>
new ApiMessage(
'apierror-stashexception',
'stashfailed' ) ]
567 if ( $status->isGood() ) {
568 $stashFile = $status->getValue();
569 $data[
'filekey'] = $stashFile->getFileKey();
571 $data[
'sessionkey'] = $data[
'filekey'];
572 return $data[
'filekey'];
575 if ( $status->getMessage()->getKey() ===
'uploadstash-exception' ) {
578 [ $exceptionType, $message ] = $status->getMessage()->getParams();
579 $debugMessage =
'Stashing temporary file failed: ' . $exceptionType .
' ' . $message;
580 $this->log->info( $debugMessage,
583 'filename' => $this->mParams[
'filename'] ??
'-',
584 'filekey' => $this->mParams[
'filekey'] ??
'-'
589 $this->log->info(
"Stash upload failure {status}",
591 'status' => (
string)$status,
593 'filename' => $this->mParams[
'filename'] ??
'-',
594 'filekey' => $this->mParams[
'filekey'] ??
'-'
598 if ( $failureMode !==
'optional' ) {
599 $this->dieStatus( $status );
601 $data[
'stasherrors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
615 private function dieRecoverableError( $errors, $parameter =
null ): never {
617 $this->performStash(
'optional', $data );
620 $data[
'invalidparameter'] = $parameter;
624 foreach ( $errors as $error ) {
625 $msg = ApiMessage::create( $error );
626 $msg->setApiData( $msg->getApiData() + $data );
629 $this->dieStatus( $sv );
644 foreach ( $status->getMessages() as $error ) {
645 $msg = ApiMessage::create( $error, $overrideCode );
646 if ( $moreExtraData ) {
647 $msg->setApiData( $msg->getApiData() + $moreExtraData );
651 $this->dieStatus( $sv );
663 if ( !$this->mParams[
'chunk'] ) {
664 $this->requireOnlyOneParameter( $this->mParams,
665 'filekey',
'file',
'url' );
669 if ( $this->mParams[
'checkstatus'] &&
670 ( $this->mParams[
'filekey'] || ( $this->mParams[
'url'] && $this->mParams[
'filename'] ) )
672 $statusKey = $this->mParams[
'filekey'] ?: UploadFromUrl::getCacheKey( $this->mParams );
673 $progress = UploadBase::getSessionStatus( $this->
getUser(), $statusKey );
675 $this->log->info(
"Cannot check upload status due to missing upload session for {user}",
677 'user' => $this->
getUser()->getName(),
678 'url' => $this->mParams[
'url'] ??
'-',
679 'filename' => $this->mParams[
'filename'] ??
'-',
680 'filekey' => $this->mParams[
'filekey'] ??
'-'
683 $this->dieWithError(
'apierror-upload-missingresult',
'missingresult' );
684 } elseif ( !$progress[
'status']->isGood() ) {
685 $this->dieStatusWithCode( $progress[
'status'],
'stashfailed' );
687 if ( isset( $progress[
'status']->value[
'verification'] ) ) {
688 $this->checkVerification( $progress[
'status']->value[
'verification'] );
690 if ( isset( $progress[
'status']->value[
'warnings'] ) ) {
691 $warnings = $this->transformWarnings( $progress[
'status']->value[
'warnings'] );
693 $progress[
'warnings'] = $warnings;
697 unset( $progress[
'status'] );
699 if ( $progress[
'result'] ===
'Success' ) {
700 if ( isset( $progress[
'filekey'] ) ) {
702 $file = $this->localRepo->getUploadStash()->getFile( $progress[
'filekey'] );
704 $imageinfo = $this->getUploadImageInfoInternal( $file,
true );
706 } elseif ( isset( $progress[
'filename'] ) && isset( $progress[
'timestamp'] ) ) {
708 $file = $this->localRepo->findFile(
709 $progress[
'filename'],
710 [
'time' => $progress[
'timestamp'],
'latest' =>
true ]
713 $imageinfo = $this->getUploadImageInfoInternal( $file,
false );
715 } elseif ( isset( $progress[
'imageinfo'] ) ) {
717 $imageinfo = $progress[
'imageinfo'];
719 unset( $progress[
'imageinfo'] );
722 $this->getResult()->addValue(
null, $this->getModuleName(), $progress );
726 $this->getResult()->addValue( $this->getModuleName(),
'imageinfo', $imageinfo );
733 if ( $this->mParams[
'filename'] ===
null ) {
734 $this->dieWithError( [
'apierror-missingparam',
'filename' ] );
737 if ( $this->mParams[
'chunk'] ) {
740 if ( isset( $this->mParams[
'filekey'] ) ) {
741 if ( $this->mParams[
'offset'] === 0 ) {
742 $this->dieWithError(
'apierror-upload-filekeynotallowed',
'filekeynotallowed' );
746 $this->mUpload->continueChunks(
747 $this->mParams[
'filename'],
748 $this->mParams[
'filekey'],
749 $this->getMain()->getUpload(
'chunk' )
752 if ( $this->mParams[
'offset'] !== 0 ) {
753 $this->dieWithError(
'apierror-upload-filekeyneeded',
'filekeyneeded' );
757 $this->mUpload->initialize(
758 $this->mParams[
'filename'],
759 $this->getMain()->getUpload(
'chunk' )
762 } elseif ( isset( $this->mParams[
'filekey'] ) ) {
764 if ( !UploadFromStash::isValidKey( $this->mParams[
'filekey'] ) ) {
765 $this->dieWithError(
'apierror-invalid-file-key' );
771 $this->mUpload->initialize(
772 $this->mParams[
'filekey'], $this->mParams[
'filename'], !$this->mParams[
'async']
774 } elseif ( isset( $this->mParams[
'file'] ) ) {
778 if ( $this->mParams[
'async'] ) {
779 $this->dieWithError(
'apierror-cannot-async-upload-file' );
783 $this->mUpload->initialize(
784 $this->mParams[
'filename'],
785 $this->getMain()->getUpload(
'file' )
787 } elseif ( isset( $this->mParams[
'url'] ) ) {
789 if ( !UploadFromUrl::isEnabled() ) {
790 $this->dieWithError(
'copyuploaddisabled' );
793 if ( !UploadFromUrl::isAllowedHost( $this->mParams[
'url'] ) ) {
794 $this->dieWithError(
'apierror-copyuploadbaddomain' );
797 if ( !UploadFromUrl::isAllowedUrl( $this->mParams[
'url'] ) ) {
798 $this->dieWithError(
'apierror-copyuploadbadurl' );
804 $this->mUpload->
initialize( $this->mParams[
'filename'],
805 $this->mParams[
'url'], !$this->mParams[
'async'] );
818 $permission = $this->mUpload->isAllowed( $user );
820 if ( $permission !==
true ) {
821 if ( !$user->isNamed() ) {
822 $this->dieWithError( [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ] );
825 $this->dieStatus( User::newFatalPermissionDeniedStatus( $permission ) );
829 if ( $user->isBlockedFromUpload() ) {
831 $this->dieBlocked( $user->getBlock() );
839 if ( $this->mParams[
'chunk'] ) {
840 $maxSize = UploadBase::getMaxUploadSize(
'file' );
841 if ( $this->mParams[
'filesize'] > $maxSize ) {
842 $this->dieWithError(
'file-too-large' );
844 if ( !$this->mUpload->getTitle() ) {
845 $this->dieWithError(
'illegal-filename' );
849 $verification = $this->mUpload->validateName();
850 if ( $verification ===
true ) {
853 } elseif ( $this->mParams[
'async'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
857 $verification = $this->mUpload->validateName();
858 if ( $verification ===
true ) {
862 wfDebug( __METHOD__ .
" about to verify" );
864 $verification = $this->mUpload->verifyUpload();
866 if ( $verification[
'status'] === UploadBase::OK ) {
869 $this->log->info(
"File verification of {filename} failed for {user} because {result}",
871 'user' => $this->
getUser()->getName(),
872 'resultCode' => $verification[
'status'],
873 'result' => $this->mUpload->getVerificationErrorCode( $verification[
'status'] ),
874 'filename' => $this->mParams[
'filename'] ??
'-',
875 'details' => $verification[
'details'] ??
''
881 $this->checkVerification( $verification );
890 $status = $this->mUpload->convertVerifyErrorToStatus( $verification );
891 if ( $status->isRecoverableError() ) {
892 $this->dieRecoverableError( [ $status->asApiMessage() ], $status->getInvalidParameter() );
895 $this->dieWithError( $status->asApiMessage() );
907 $warnings = UploadBase::makeWarningsSerializable(
908 $this->mUpload->checkWarnings( $this->getUser() )
911 return $this->transformWarnings( $warnings );
917 ApiResult::setIndexedTagName( $warnings,
'warning' );
919 if ( isset( $warnings[
'duplicate'] ) ) {
920 $dupes = array_column( $warnings[
'duplicate'],
'fileName' );
921 ApiResult::setIndexedTagName( $dupes,
'duplicate' );
922 $warnings[
'duplicate'] = $dupes;
925 if ( isset( $warnings[
'exists'] ) ) {
926 $warning = $warnings[
'exists'];
927 unset( $warnings[
'exists'] );
928 $localFile = $warning[
'normalizedFile'] ?? $warning[
'file'];
929 $warnings[$warning[
'warning']] = $localFile[
'fileName'];
932 if ( isset( $warnings[
'no-change'] ) ) {
933 $file = $warnings[
'no-change'];
934 unset( $warnings[
'no-change'] );
936 $warnings[
'nochange'] = [
937 'timestamp' =>
wfTimestamp( TS::ISO_8601, $file[
'timestamp'] )
941 if ( isset( $warnings[
'duplicate-version'] ) ) {
943 foreach ( $warnings[
'duplicate-version'] as $dupe ) {
945 'timestamp' =>
wfTimestamp( TS::ISO_8601, $dupe[
'timestamp'] )
948 unset( $warnings[
'duplicate-version'] );
950 ApiResult::setIndexedTagName( $dupes,
'ver' );
951 $warnings[
'duplicateversions'] = $dupes;
965 $this->log->info(
"Upload stashing of {filename} failed for {user} because {error}",
967 'user' => $this->
getUser()->getName(),
968 'error' => get_class( $e ),
969 'filename' => $this->mParams[
'filename'] ??
'-',
970 'filekey' => $this->mParams[
'filekey'] ??
'-'
974 switch ( get_class( $e ) ) {
975 case UploadStashFileNotFoundException::class:
976 $wrap =
'apierror-stashedfilenotfound';
978 case UploadStashBadPathException::class:
979 $wrap =
'apierror-stashpathinvalid';
981 case UploadStashFileException::class:
982 $wrap =
'apierror-stashfilestorage';
984 case UploadStashZeroLengthFileException::class:
985 $wrap =
'apierror-stashzerolength';
987 case UploadStashNotLoggedInException::class:
988 return StatusValue::newFatal( ApiMessage::create(
989 [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ],
'stashnotloggedin'
991 case UploadStashWrongOwnerException::class:
992 $wrap =
'apierror-stashwrongowner';
994 case UploadStashNoSuchKeyException::class:
995 $wrap =
'apierror-stashnosuchfilekey';
998 $wrap = [
'uploadstash-exception', get_class( $e ) ];
1001 return StatusValue::newFatal(
1002 $this->getErrorFormatter()->getMessageFromException( $e, [
'wrap' => $wrap ] )
1015 $this->mParams[
'text'] ??= $this->mParams[
'comment'];
1018 $file = $this->mUpload->getLocalFile();
1020 $title = $file->getTitle();
1028 $this->mParams[
'watchlist'], $title, $user,
'watchdefault'
1031 if ( !$watch && $this->mParams[
'watchlist'] ==
'preferences' && !$file->exists() ) {
1040 if ( $this->mParams[
'watch'] ) {
1044 if ( $this->mParams[
'tags'] ) {
1045 $status = ChangeTags::canAddTagsAccompanyingChange( $this->mParams[
'tags'], $this->
getAuthority() );
1046 if ( !$status->isOK() ) {
1047 $this->dieStatus( $status );
1053 if ( $this->mParams[
'async'] ) {
1055 if ( $this->mParams[
'filekey'] ) {
1058 'filename' => $this->mParams[
'filename'],
1059 'filekey' => $this->mParams[
'filekey'],
1060 'comment' => $this->mParams[
'comment'],
1061 'tags' => $this->mParams[
'tags'] ?? [],
1062 'text' => $this->mParams[
'text'],
1064 'watchlistexpiry' => $watchlistExpiry,
1065 'session' => $this->
getContext()->exportSession(),
1066 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1069 } elseif ( $this->mParams[
'url'] ) {
1072 'filename' => $this->mParams[
'filename'],
1073 'url' => $this->mParams[
'url'],
1074 'comment' => $this->mParams[
'comment'],
1075 'tags' => $this->mParams[
'tags'] ?? [],
1076 'text' => $this->mParams[
'text'],
1078 'watchlistexpiry' => $watchlistExpiry,
1079 'session' => $this->
getContext()->exportSession(),
1080 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1084 $this->dieWithError(
'apierror-no-async-support',
'publishfailed' );
1090 $cacheKey =
$job->getCacheKey();
1093 $progress = UploadBase::getSessionStatus( $this->
getUser(), $cacheKey );
1094 if ( $progress && $progress[
'result'] ===
'Poll' ) {
1095 $this->dieWithError(
'apierror-upload-inprogress',
'publishfailed' );
1097 UploadBase::setSessionStatus(
1100 [
'result' =>
'Poll',
'stage' =>
'queued',
'status' => Status::newGood() ]
1103 $this->jobQueueGroup->push(
$job );
1104 $this->log->info(
"Sending publish job of {filename} for {user}",
1106 'user' => $this->
getUser()->getName(),
1107 'filename' => $this->mParams[
'filename'] ??
'-'
1110 $result[
'result'] =
'Poll';
1111 $result[
'stage'] =
'queued';
1113 $status = $this->mUpload->performUpload(
1114 $this->mParams[
'comment'],
1115 $this->mParams[
'text'],
1118 $this->mParams[
'tags'] ?? [],
1122 if ( !$status->isGood() ) {
1123 $this->log->info(
"Non-async API upload publish failed for {user} because {status}",
1125 'user' => $this->
getUser()->getName(),
1126 'filename' => $this->mParams[
'filename'] ??
'-',
1127 'filekey' => $this->mParams[
'filekey'] ??
'-',
1128 'status' => (
string)$status
1131 $this->dieRecoverableError( $status->getMessages() );
1133 $result[
'result'] =
'Success';
1136 $result[
'filename'] = $file->getName();
1137 if ( $warnings && count( $warnings ) > 0 ) {
1138 $result[
'warnings'] = $warnings;
1158 ParamValidator::PARAM_TYPE =>
'string',
1161 ParamValidator::PARAM_DEFAULT =>
''
1164 ParamValidator::PARAM_TYPE =>
'tags',
1165 ParamValidator::PARAM_ISMULTI =>
true,
1168 ParamValidator::PARAM_TYPE =>
'text',
1171 ParamValidator::PARAM_DEFAULT =>
false,
1172 ParamValidator::PARAM_DEPRECATED =>
true,
1185 'ignorewarnings' =>
false,
1187 ParamValidator::PARAM_TYPE =>
'upload',
1192 ParamValidator::PARAM_DEPRECATED =>
true,
1197 ParamValidator::PARAM_TYPE =>
'integer',
1198 IntegerDef::PARAM_MIN => 0,
1199 IntegerDef::PARAM_MAX => UploadBase::getMaxUploadSize(
'file' ),
1202 ParamValidator::PARAM_TYPE =>
'integer',
1203 IntegerDef::PARAM_MIN => 0,
1206 ParamValidator::PARAM_TYPE =>
'upload',
1210 'checkstatus' =>
false,
1224 'action=upload&filename=Wiki.png' .
1225 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC'
1226 =>
'apihelp-upload-example-url',
1227 'action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC'
1228 =>
'apihelp-upload-example-filekey',
1234 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
1239class_alias( ApiUpload::class,
'ApiUpload' );
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfShorthandToInteger(?string $string='', int $default=-1)
Converts shorthand byte notation to integer form.
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined('MW_SETUP_CALLBACK'))
This is the main API class, used for both external and internal processing.
A class containing constants representing the names of configuration variables.
const EnableAsyncUploads
Name constant for the EnableAsyncUploads setting, for use with Config::get()
const WatchlistExpiry
Name constant for the WatchlistExpiry setting, for use with Config::get()
const EnableAsyncUploadsByURL
Name constant for the EnableAsyncUploadsByURL setting, for use with Config::get()
const WatchlistExpiryMaxDuration
Name constant for the WatchlistExpiryMaxDuration setting, for use with Config::get()
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static newGood( $value=null)
Factory function for good results.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
if(count( $args)< 1) $job