50use Psr\Log\LoggerInterface;
55use Wikimedia\Timestamp\TimestampFormat as TS;
72 private LoggerInterface $log;
83 parent::__construct( $mainModule, $moduleName );
88 $this->watchlistMaxDuration =
90 $this->watchlistManager = $watchlistManager;
91 $this->watchedItemStore = $watchedItemStore;
92 $this->userOptionsLookup = $userOptionsLookup;
93 $this->log = LoggerFactory::getInstance(
'upload' );
98 if ( !UploadBase::isEnabled() ) {
108 $this->mParams[
'async'] = $this->mParams[
'async'] &&
113 if ( !$this->mParams[
'filekey'] && $this->mParams[
'sessionkey'] ) {
114 $this->mParams[
'filekey'] = $this->mParams[
'sessionkey'];
120 if ( $this->mParams[
'stash'] && $this->mParams[
'text'] !==
null ) {
121 $this->
addWarning(
'apiwarn-upload-textwithstash' );
126 if ( $this->mParams[
'stash'] && $this->mParams[
'autotext'] ) {
127 $this->
addWarning(
'apiwarn-upload-autotextwithstash' );
130 if ( !$this->mParams[
'checkstatus'] ) {
139 } elseif ( !$this->mUpload ) {
153 if ( $this->mParams[
'async'] && $this->mParams[
'url'] ) {
154 $status = $this->mUpload->canFetchFile();
156 $status = $this->mUpload->fetchFile();
159 if ( !$status->isGood() ) {
160 $this->log->info(
"Unable to fetch file {filename} for {user} because {status}",
162 'user' => $this->
getUser()->getName(),
163 'status' => (
string)$status,
164 'filename' => $this->mParams[
'filename'] ??
'-',
176 if ( !$this->mParams[
'stash'] ) {
177 $status = $this->mUpload->authorizeUpload( $user );
178 if ( !$status->isGood() ) {
179 $this->dieRecoverableError( $status->getMessages(),
'filename' );
185 $result = $this->getContextResult();
194 if ( $result[
'result'] ===
'Success' ) {
200 $this->mUpload->cleanupTempFile();
213 $services->getJobQueueGroup(),
214 $services->getWatchlistManager(),
215 $services->getWatchedItemStore(),
216 $services->getUserOptionsLookup(),
217 $services->getRepoGroup(),
234 $stashFile = $upload->getStashFile();
236 $info = $this->getUploadImageInfoInternal( $stashFile,
true );
239 $info = $this->getUploadImageInfoInternal( $localFile,
false );
245 private function getUploadImageInfoInternal( File $file,
bool $stashedImageInfos ): array {
246 $result = $this->getResult();
272 if ( $stashedImageInfos ) {
274 $info = ApiQueryStashImageInfo::getInfo(
276 array_fill_keys( $imParam,
true ),
289 $info = ApiQueryImageInfo::getInfo(
291 array_fill_keys( $imParam,
true ),
303 private function getContextResult() {
304 $warnings = $this->getApiWarnings();
305 if ( $warnings && !$this->mParams[
'ignorewarnings'] ) {
307 return $this->getWarningsResult( $warnings );
308 } elseif ( $this->mParams[
'chunk'] ) {
310 return $this->getChunkResult( $warnings );
311 } elseif ( $this->mParams[
'stash'] ) {
313 return $this->getStashResult( $warnings );
318 return $this->performUpload( $warnings );
326 private function getStashResult( $warnings ) {
327 $result = [
'result' =>
'Success' ];
328 if ( $warnings && count( $warnings ) > 0 ) {
329 $result[
'warnings'] = $warnings;
333 $this->performStash(
'critical', $result );
343 private function getWarningsResult( $warnings ) {
345 'result' =>
'Warning',
346 'warnings' => $warnings,
351 $this->performStash(
'optional', $result );
363 $configured = $config->
get( MainConfigNames::MinUploadChunkSize );
368 ini_get(
'post_max_size' ),
377 UploadBase::getMaxUploadSize(
'file' ),
378 UploadBase::getMaxPhpUploadSize(),
388 private function getChunkResult( $warnings ) {
391 if ( $warnings && count( $warnings ) > 0 ) {
392 $result[
'warnings'] = $warnings;
395 $chunkUpload = $this->getMain()->getUpload(
'chunk' );
396 $chunkPath = $chunkUpload->getTempName();
397 $chunkSize = $chunkUpload->getSize();
398 $totalSoFar = $this->mParams[
'offset'] + $chunkSize;
399 $minChunkSize = self::getMinUploadChunkSize( $this->getConfig() );
402 if ( $totalSoFar > $this->mParams[
'filesize'] ) {
403 $this->dieWithError(
'apierror-invalid-chunk' );
407 if ( $totalSoFar != $this->mParams[
'filesize'] && $chunkSize < $minChunkSize ) {
408 $this->dieWithError( [
'apierror-chunk-too-small', Message::numParam( $minChunkSize ) ] );
411 if ( $this->mParams[
'offset'] == 0 ) {
412 $this->log->debug(
"Started first chunk of chunked upload of {filename} for {user}",
415 'filename' => $this->mParams[
'filename'] ??
'-',
416 'filesize' => $this->mParams[
'filesize'],
417 'chunkSize' => $chunkSize
420 $filekey = $this->performStash(
'critical' );
422 $filekey = $this->mParams[
'filekey'];
425 $progress = UploadBase::getSessionStatus( $this->
getUser(), $filekey );
428 $this->log->info(
"Stash failed due to no session for {user}",
431 'filename' => $this->mParams[
'filename'] ??
'-',
432 'filekey' => $this->mParams[
'filekey'] ??
'-',
433 'filesize' => $this->mParams[
'filesize'],
434 'chunkSize' => $chunkSize
437 $this->dieWithError(
'apierror-stashfailed-nosession',
'stashfailed' );
438 } elseif ( $progress[
'result'] !==
'Continue' || $progress[
'stage'] !==
'uploading' ) {
439 $this->dieWithError(
'apierror-stashfailed-complete',
'stashfailed' );
442 $status = $this->mUpload->addChunk(
443 $chunkPath, $chunkSize, $this->mParams[
'offset'] );
444 if ( !$status->isGood() ) {
446 'offset' => $this->mUpload->getOffset(),
448 $this->log->info(
"Chunked upload stash failure {status} for {user}",
450 'status' => (
string)$status,
452 'filename' => $this->mParams[
'filename'] ??
'-',
453 'filekey' => $this->mParams[
'filekey'] ??
'-',
454 'filesize' => $this->mParams[
'filesize'],
455 'chunkSize' => $chunkSize,
456 'offset' => $this->mUpload->getOffset()
459 $this->dieStatusWithCode( $status,
'stashfailed', $extradata );
461 $this->log->debug(
"Got chunk for {filename} with offset {offset} for {user}",
464 'filename' => $this->mParams[
'filename'] ??
'-',
465 'filekey' => $this->mParams[
'filekey'] ??
'-',
466 'filesize' => $this->mParams[
'filesize'],
467 'chunkSize' => $chunkSize,
468 'offset' => $this->mUpload->getOffset()
475 if ( $totalSoFar == $this->mParams[
'filesize'] ) {
476 if ( $this->mParams[
'async'] ) {
477 UploadBase::setSessionStatus(
480 [
'result' =>
'Poll',
481 'stage' =>
'queued',
'status' => Status::newGood() ]
487 $this->jobQueueGroup->lazyPush(
new AssembleUploadChunksJob( [
488 'filename' => $this->mParams[
'filename'],
489 'filekey' => $filekey,
490 'filesize' => $this->mParams[
'filesize'],
491 'session' => $this->
getContext()->exportSession()
493 $this->log->info(
"Received final chunk of {filename} for {user}, queuing assemble job",
496 'filename' => $this->mParams[
'filename'] ??
'-',
497 'filekey' => $this->mParams[
'filekey'] ??
'-',
498 'filesize' => $this->mParams[
'filesize'],
499 'chunkSize' => $chunkSize,
502 $result[
'result'] =
'Poll';
503 $result[
'stage'] =
'queued';
505 $this->log->info(
"Received final chunk of {filename} for {user}, assembling immediately",
508 'filename' => $this->mParams[
'filename'] ??
'-',
509 'filekey' => $this->mParams[
'filekey'] ??
'-',
510 'filesize' => $this->mParams[
'filesize'],
511 'chunkSize' => $chunkSize,
515 $status = $this->mUpload->concatenateChunks();
516 if ( !$status->isGood() ) {
517 UploadBase::setSessionStatus(
520 [
'result' =>
'Failure',
'stage' =>
'assembling',
'status' => $status ]
522 $this->log->info(
"Non jobqueue assembly of {filename} failed because {status}",
525 'filename' => $this->mParams[
'filename'] ??
'-',
526 'filekey' => $this->mParams[
'filekey'] ??
'-',
527 'filesize' => $this->mParams[
'filesize'],
528 'chunkSize' => $chunkSize,
529 'status' => (
string)$status
532 $this->dieStatusWithCode( $status,
'stashfailed' );
536 $warnings = $this->getApiWarnings();
538 $result[
'warnings'] = $warnings;
543 UploadBase::setSessionStatus( $this->
getUser(), $filekey,
false );
544 $this->mUpload->stash->removeFile( $filekey );
545 $filekey = $this->mUpload->getStashFile()->getFileKey();
547 $result[
'result'] =
'Success';
550 UploadBase::setSessionStatus(
554 'result' =>
'Continue',
555 'stage' =>
'uploading',
556 'offset' => $totalSoFar,
557 'status' => Status::newGood(),
560 $result[
'result'] =
'Continue';
561 $result[
'offset'] = $totalSoFar;
564 $result[
'filekey'] = $filekey;
581 private function performStash( $failureMode, &$data = [] ) {
582 if ( $failureMode ===
'optional' && $this->mUpload->skipStashFileAttempt() ) {
586 $isPartial = (bool)$this->mParams[
'chunk'];
588 $status = $this->mUpload->tryStashFile( $this->
getUser(), $isPartial );
590 if ( $status->isGood() && !$status->getValue() ) {
592 $status->fatal(
new ApiMessage(
'apierror-stashinvalidfile',
'stashfailed' ) );
594 }
catch ( Exception $e ) {
595 $debugMessage =
'Stashing temporary file failed: ' . get_class( $e ) .
' ' . $e->getMessage();
596 $this->log->info( $debugMessage,
599 'filename' => $this->mParams[
'filename'] ??
'-',
600 'filekey' => $this->mParams[
'filekey'] ??
'-'
604 $status = Status::newFatal( $this->getErrorFormatter()->getMessageFromException(
605 $e, [
'wrap' =>
new ApiMessage(
'apierror-stashexception',
'stashfailed' ) ]
609 if ( $status->isGood() ) {
610 $stashFile = $status->getValue();
611 $data[
'filekey'] = $stashFile->getFileKey();
613 $data[
'sessionkey'] = $data[
'filekey'];
614 return $data[
'filekey'];
617 if ( $status->getMessage()->getKey() ===
'uploadstash-exception' ) {
620 [ $exceptionType, $message ] = $status->getMessage()->getParams();
621 $debugMessage =
'Stashing temporary file failed: ' . $exceptionType .
' ' . $message;
622 $this->log->info( $debugMessage,
625 'filename' => $this->mParams[
'filename'] ??
'-',
626 'filekey' => $this->mParams[
'filekey'] ??
'-'
631 $this->log->info(
"Stash upload failure {status}",
633 'status' => (
string)$status,
635 'filename' => $this->mParams[
'filename'] ??
'-',
636 'filekey' => $this->mParams[
'filekey'] ??
'-'
640 if ( $failureMode !==
'optional' ) {
641 $this->dieStatus( $status );
643 $data[
'stasherrors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
657 private function dieRecoverableError( $errors, $parameter =
null ): never {
659 $this->performStash(
'optional', $data );
662 $data[
'invalidparameter'] = $parameter;
666 foreach ( $errors as $error ) {
667 $msg = ApiMessage::create( $error );
668 $msg->setApiData( $msg->getApiData() + $data );
671 $this->dieStatus( $sv );
686 foreach ( $status->getMessages() as $error ) {
687 $msg = ApiMessage::create( $error, $overrideCode );
688 if ( $moreExtraData ) {
689 $msg->setApiData( $msg->getApiData() + $moreExtraData );
693 $this->dieStatus( $sv );
705 if ( !$this->mParams[
'chunk'] ) {
706 $this->requireOnlyOneParameter( $this->mParams,
707 'filekey',
'file',
'url' );
711 if ( $this->mParams[
'checkstatus'] &&
712 ( $this->mParams[
'filekey'] || ( $this->mParams[
'url'] && $this->mParams[
'filename'] ) )
714 $statusKey = $this->mParams[
'filekey'] ?: UploadFromUrl::getCacheKey( $this->mParams );
715 $progress = UploadBase::getSessionStatus( $this->
getUser(), $statusKey );
717 $this->log->info(
"Cannot check upload status due to missing upload session for {user}",
719 'user' => $this->
getUser()->getName(),
720 'url' => $this->mParams[
'url'] ??
'-',
721 'filename' => $this->mParams[
'filename'] ??
'-',
722 'filekey' => $this->mParams[
'filekey'] ??
'-'
725 $this->dieWithError(
'apierror-upload-missingresult',
'missingresult' );
726 } elseif ( !$progress[
'status']->isGood() ) {
727 $this->dieStatusWithCode( $progress[
'status'],
'stashfailed' );
729 if ( isset( $progress[
'status']->value[
'verification'] ) ) {
730 $this->checkVerification( $progress[
'status']->value[
'verification'] );
732 if ( isset( $progress[
'status']->value[
'warnings'] ) ) {
733 $warnings = $this->transformWarnings( $progress[
'status']->value[
'warnings'] );
735 $progress[
'warnings'] = $warnings;
739 unset( $progress[
'status'] );
741 if ( $progress[
'result'] ===
'Success' ) {
742 if ( isset( $progress[
'filekey'] ) ) {
744 $file = $this->localRepo->getUploadStash()->getFile( $progress[
'filekey'] );
746 $imageinfo = $this->getUploadImageInfoInternal( $file,
true );
748 } elseif ( isset( $progress[
'filename'] ) && isset( $progress[
'timestamp'] ) ) {
750 $file = $this->localRepo->findFile(
751 $progress[
'filename'],
752 [
'time' => $progress[
'timestamp'],
'latest' =>
true ]
755 $imageinfo = $this->getUploadImageInfoInternal( $file,
false );
757 } elseif ( isset( $progress[
'imageinfo'] ) ) {
759 $imageinfo = $progress[
'imageinfo'];
761 unset( $progress[
'imageinfo'] );
764 $this->getResult()->addValue(
null, $this->getModuleName(), $progress );
768 $this->getResult()->addValue( $this->getModuleName(),
'imageinfo', $imageinfo );
775 if ( $this->mParams[
'filename'] ===
null ) {
776 $this->dieWithError( [
'apierror-missingparam',
'filename' ] );
779 if ( $this->mParams[
'chunk'] ) {
782 if ( isset( $this->mParams[
'filekey'] ) ) {
783 if ( $this->mParams[
'offset'] === 0 ) {
784 $this->dieWithError(
'apierror-upload-filekeynotallowed',
'filekeynotallowed' );
788 $this->mUpload->continueChunks(
789 $this->mParams[
'filename'],
790 $this->mParams[
'filekey'],
791 $this->getMain()->getUpload(
'chunk' )
794 if ( $this->mParams[
'offset'] !== 0 ) {
795 $this->dieWithError(
'apierror-upload-filekeyneeded',
'filekeyneeded' );
799 $this->mUpload->initialize(
800 $this->mParams[
'filename'],
801 $this->getMain()->getUpload(
'chunk' )
804 } elseif ( isset( $this->mParams[
'filekey'] ) ) {
806 if ( !UploadFromStash::isValidKey( $this->mParams[
'filekey'] ) ) {
807 $this->dieWithError(
'apierror-invalid-file-key' );
813 $this->mUpload->initialize(
814 $this->mParams[
'filekey'], $this->mParams[
'filename'], !$this->mParams[
'async']
816 } elseif ( isset( $this->mParams[
'file'] ) ) {
820 if ( $this->mParams[
'async'] ) {
821 $this->dieWithError(
'apierror-cannot-async-upload-file' );
825 $this->mUpload->initialize(
826 $this->mParams[
'filename'],
827 $this->getMain()->getUpload(
'file' )
829 } elseif ( isset( $this->mParams[
'url'] ) ) {
831 if ( !UploadFromUrl::isEnabled() ) {
832 $this->dieWithError(
'copyuploaddisabled' );
835 if ( !UploadFromUrl::isAllowedHost( $this->mParams[
'url'] ) ) {
836 $this->dieWithError(
'apierror-copyuploadbaddomain' );
839 if ( !UploadFromUrl::isAllowedUrl( $this->mParams[
'url'] ) ) {
840 $this->dieWithError(
'apierror-copyuploadbadurl' );
846 $this->mUpload->
initialize( $this->mParams[
'filename'],
847 $this->mParams[
'url'], !$this->mParams[
'async'] );
860 $permission = $this->mUpload->isAllowed( $user );
862 if ( $permission !==
true ) {
863 if ( !$user->isNamed() ) {
864 $this->dieWithError( [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ] );
867 $this->dieStatus( User::newFatalPermissionDeniedStatus( $permission ) );
871 if ( $user->isBlockedFromUpload() ) {
873 $this->dieBlocked( $user->getBlock() );
881 if ( $this->mParams[
'chunk'] ) {
882 $maxSize = UploadBase::getMaxUploadSize(
'file' );
883 if ( $this->mParams[
'filesize'] > $maxSize ) {
884 $this->dieWithError(
'file-too-large' );
886 if ( !$this->mUpload->getTitle() ) {
887 $this->dieWithError(
'illegal-filename' );
891 $verification = $this->mUpload->validateName();
892 if ( $verification ===
true ) {
895 } elseif ( $this->mParams[
'async'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
899 $verification = $this->mUpload->validateName();
900 if ( $verification ===
true ) {
904 wfDebug( __METHOD__ .
" about to verify" );
906 $verification = $this->mUpload->verifyUpload();
908 if ( $verification[
'status'] === UploadBase::OK ) {
911 $this->log->info(
"File verification of {filename} failed for {user} because {result}",
913 'user' => $this->
getUser()->getName(),
914 'resultCode' => $verification[
'status'],
915 'result' => $this->mUpload->getVerificationErrorCode( $verification[
'status'] ),
916 'filename' => $this->mParams[
'filename'] ??
'-',
917 'details' => $verification[
'details'] ??
''
923 $this->checkVerification( $verification );
932 $status = $this->mUpload->convertVerifyErrorToStatus( $verification );
933 if ( $status->isRecoverableError() ) {
934 $this->dieRecoverableError( [ $status->asApiMessage() ], $status->getInvalidParameter() );
937 $this->dieWithError( $status->asApiMessage() );
949 $warnings = UploadBase::makeWarningsSerializable(
950 $this->mUpload->checkWarnings( $this->getUser() )
953 return $this->transformWarnings( $warnings );
959 ApiResult::setIndexedTagName( $warnings,
'warning' );
961 if ( isset( $warnings[
'duplicate'] ) ) {
962 $dupes = array_column( $warnings[
'duplicate'],
'fileName' );
963 ApiResult::setIndexedTagName( $dupes,
'duplicate' );
964 $warnings[
'duplicate'] = $dupes;
967 if ( isset( $warnings[
'exists'] ) ) {
968 $warning = $warnings[
'exists'];
969 unset( $warnings[
'exists'] );
970 $localFile = $warning[
'normalizedFile'] ?? $warning[
'file'];
971 $warnings[$warning[
'warning']] = $localFile[
'fileName'];
974 if ( isset( $warnings[
'no-change'] ) ) {
975 $file = $warnings[
'no-change'];
976 unset( $warnings[
'no-change'] );
978 $warnings[
'nochange'] = [
979 'timestamp' =>
wfTimestamp( TS::ISO_8601, $file[
'timestamp'] )
983 if ( isset( $warnings[
'duplicate-version'] ) ) {
985 foreach ( $warnings[
'duplicate-version'] as $dupe ) {
987 'timestamp' =>
wfTimestamp( TS::ISO_8601, $dupe[
'timestamp'] )
990 unset( $warnings[
'duplicate-version'] );
992 ApiResult::setIndexedTagName( $dupes,
'ver' );
993 $warnings[
'duplicateversions'] = $dupes;
1007 $this->log->info(
"Upload stashing of {filename} failed for {user} because {error}",
1009 'user' => $this->
getUser()->getName(),
1010 'error' => get_class( $e ),
1011 'filename' => $this->mParams[
'filename'] ??
'-',
1012 'filekey' => $this->mParams[
'filekey'] ??
'-'
1016 switch ( get_class( $e ) ) {
1017 case UploadStashFileNotFoundException::class:
1018 $wrap =
'apierror-stashedfilenotfound';
1020 case UploadStashBadPathException::class:
1021 $wrap =
'apierror-stashpathinvalid';
1023 case UploadStashFileException::class:
1024 $wrap =
'apierror-stashfilestorage';
1026 case UploadStashZeroLengthFileException::class:
1027 $wrap =
'apierror-stashzerolength';
1029 case UploadStashNotLoggedInException::class:
1030 return StatusValue::newFatal( ApiMessage::create(
1031 [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ],
'stashnotloggedin'
1033 case UploadStashWrongOwnerException::class:
1034 $wrap =
'apierror-stashwrongowner';
1036 case UploadStashNoSuchKeyException::class:
1037 $wrap =
'apierror-stashnosuchfilekey';
1040 $wrap = [
'uploadstash-exception', get_class( $e ) ];
1043 return StatusValue::newFatal(
1044 $this->getErrorFormatter()->getMessageFromException( $e, [
'wrap' => $wrap ] )
1056 if ( $this->mParams[
'autotext'] ) {
1061 $this->mParams[
'text'] = SpecialUpload::getInitialPageText(
1062 $this->mParams[
'comment'],
1063 $this->mParams[
'license'],
1064 $this->mParams[
'copystatus'],
1065 $this->mParams[
'source'],
1070 $this->mParams[
'text'] ??= $this->mParams[
'comment'];
1074 $file = $this->mUpload->getLocalFile();
1076 $title = $file->getTitle();
1084 $this->mParams[
'watchlist'], $title, $user,
'watchdefault'
1087 if ( !$watch && $this->mParams[
'watchlist'] ==
'preferences' && !$file->exists() ) {
1096 if ( $this->mParams[
'watch'] ) {
1100 if ( $this->mParams[
'tags'] ) {
1101 $status = ChangeTags::canAddTagsAccompanyingChange( $this->mParams[
'tags'], $this->
getAuthority() );
1102 if ( !$status->isOK() ) {
1103 $this->dieStatus( $status );
1109 if ( $this->mParams[
'async'] ) {
1111 if ( $this->mParams[
'filekey'] ) {
1114 'filename' => $this->mParams[
'filename'],
1115 'filekey' => $this->mParams[
'filekey'],
1116 'comment' => $this->mParams[
'comment'],
1117 'tags' => $this->mParams[
'tags'] ?? [],
1118 'text' => $this->mParams[
'text'],
1120 'watchlistexpiry' => $watchlistExpiry,
1121 'session' => $this->
getContext()->exportSession(),
1122 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1125 } elseif ( $this->mParams[
'url'] ) {
1128 'filename' => $this->mParams[
'filename'],
1129 'url' => $this->mParams[
'url'],
1130 'comment' => $this->mParams[
'comment'],
1131 'tags' => $this->mParams[
'tags'] ?? [],
1132 'text' => $this->mParams[
'text'],
1134 'watchlistexpiry' => $watchlistExpiry,
1135 'session' => $this->
getContext()->exportSession(),
1136 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1140 $this->dieWithError(
'apierror-no-async-support',
'publishfailed' );
1146 $cacheKey =
$job->getCacheKey();
1149 $progress = UploadBase::getSessionStatus( $this->
getUser(), $cacheKey );
1150 if ( $progress && $progress[
'result'] ===
'Poll' ) {
1151 $this->dieWithError(
'apierror-upload-inprogress',
'publishfailed' );
1153 UploadBase::setSessionStatus(
1156 [
'result' =>
'Poll',
'stage' =>
'queued',
'status' => Status::newGood() ]
1159 $this->jobQueueGroup->push(
$job );
1160 $this->log->info(
"Sending publish job of {filename} for {user}",
1162 'user' => $this->
getUser()->getName(),
1163 'filename' => $this->mParams[
'filename'] ??
'-'
1166 $result[
'result'] =
'Poll';
1167 $result[
'stage'] =
'queued';
1169 $status = $this->mUpload->performUpload(
1170 $this->mParams[
'comment'],
1171 $this->mParams[
'text'],
1174 $this->mParams[
'tags'] ?? [],
1178 if ( !$status->isGood() ) {
1179 $this->log->info(
"Non-async API upload publish failed for {user} because {status}",
1181 'user' => $this->
getUser()->getName(),
1182 'filename' => $this->mParams[
'filename'] ??
'-',
1183 'filekey' => $this->mParams[
'filekey'] ??
'-',
1184 'status' => (
string)$status
1187 $this->dieRecoverableError( $status->getMessages() );
1189 $result[
'result'] =
'Success';
1192 $result[
'filename'] = $file->getName();
1193 if ( $warnings && count( $warnings ) > 0 ) {
1194 $result[
'warnings'] = $warnings;
1214 ParamValidator::PARAM_TYPE =>
'string',
1217 ParamValidator::PARAM_DEFAULT =>
''
1220 ParamValidator::PARAM_TYPE =>
'tags',
1221 ParamValidator::PARAM_ISMULTI =>
true,
1224 ParamValidator::PARAM_TYPE =>
'text',
1227 ParamValidator::PARAM_DEFAULT =>
false,
1228 ParamValidator::PARAM_DEPRECATED =>
true,
1241 'ignorewarnings' =>
false,
1243 ParamValidator::PARAM_TYPE =>
'upload',
1248 ParamValidator::PARAM_DEPRECATED =>
true,
1253 ParamValidator::PARAM_TYPE =>
'integer',
1254 IntegerDef::PARAM_MIN => 0,
1255 IntegerDef::PARAM_MAX => UploadBase::getMaxUploadSize(
'file' ),
1258 ParamValidator::PARAM_TYPE =>
'integer',
1259 IntegerDef::PARAM_MIN => 0,
1262 ParamValidator::PARAM_TYPE =>
'upload',
1266 'checkstatus' =>
false,
1269 ParamValidator::PARAM_TYPE =>
'boolean',
1270 ParamValidator::PARAM_DEFAULT =>
false,
1273 ParamValidator::PARAM_TYPE =>
'string',
1274 ParamValidator::PARAM_DEFAULT =>
''
1278 if ( $this->getConfig()->
get( MainConfigNames::UseCopyrightUpload ) ) {
1281 ParamValidator::PARAM_TYPE =>
'string',
1282 ParamValidator::PARAM_DEFAULT =>
''
1285 ParamValidator::PARAM_TYPE =>
'string',
1286 ParamValidator::PARAM_DEFAULT =>
''
1302 'action=upload&filename=Wiki.png' .
1303 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC'
1304 =>
'apihelp-upload-example-url',
1305 'action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC'
1306 =>
'apihelp-upload-example-filekey',
1312 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
1317class_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