46use Psr\Log\LoggerInterface;
80 private LoggerInterface $log;
89 parent::__construct( $mainModule, $moduleName );
90 $this->jobQueueGroup = $jobQueueGroup;
94 $this->watchlistMaxDuration =
96 $this->watchlistManager = $watchlistManager;
97 $this->userOptionsLookup = $userOptionsLookup;
98 $this->log = LoggerFactory::getInstance(
'upload' );
103 if ( !UploadBase::isEnabled() ) {
112 $this->mParams[
'async'] = ( $this->mParams[
'async'] &&
116 if ( !$this->mParams[
'filekey'] && $this->mParams[
'sessionkey'] ) {
117 $this->mParams[
'filekey'] = $this->mParams[
'sessionkey'];
120 if ( !$this->mParams[
'checkstatus'] ) {
128 } elseif ( !$this->mUpload ) {
129 $this->
dieDebug( __METHOD__,
'No upload module set' );
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();
182 if ( $result[
'result'] ===
'Success' ) {
188 $this->mUpload->cleanupTempFile();
197 $services->getJobQueueGroup(),
198 $services->getWatchlistManager(),
199 $services->getUserOptionsLookup()
220 $result = $this->getResult();
229 array_fill_keys( $imParam,
true ),
237 array_fill_keys( $imParam,
true ),
249 private function getContextResult() {
250 $warnings = $this->getApiWarnings();
251 if ( $warnings && !$this->mParams[
'ignorewarnings'] ) {
253 return $this->getWarningsResult( $warnings );
254 } elseif ( $this->mParams[
'chunk'] ) {
256 return $this->getChunkResult( $warnings );
257 } elseif ( $this->mParams[
'stash'] ) {
259 return $this->getStashResult( $warnings );
264 return $this->performUpload( $warnings );
272 private function getStashResult( $warnings ) {
274 $result[
'result'] =
'Success';
275 if ( $warnings && count( $warnings ) > 0 ) {
276 $result[
'warnings'] = $warnings;
280 $this->performStash(
'critical', $result );
290 private function getWarningsResult( $warnings ) {
292 $result[
'result'] =
'Warning';
293 $result[
'warnings'] = $warnings;
296 $this->performStash(
'optional', $result );
308 $configured = $config->
get( MainConfigNames::MinUploadChunkSize );
313 ini_get(
'post_max_size' ),
322 UploadBase::getMaxUploadSize(
'file' ),
323 UploadBase::getMaxPhpUploadSize(),
333 private function getChunkResult( $warnings ) {
336 if ( $warnings && count( $warnings ) > 0 ) {
337 $result[
'warnings'] = $warnings;
340 $chunkUpload = $this->getMain()->getUpload(
'chunk' );
341 $chunkPath = $chunkUpload->getTempName();
342 $chunkSize = $chunkUpload->getSize();
343 $totalSoFar = $this->mParams[
'offset'] + $chunkSize;
344 $minChunkSize = self::getMinUploadChunkSize( $this->getConfig() );
347 if ( $totalSoFar > $this->mParams[
'filesize'] ) {
348 $this->dieWithError(
'apierror-invalid-chunk' );
352 if ( $totalSoFar != $this->mParams[
'filesize'] && $chunkSize < $minChunkSize ) {
353 $this->dieWithError( [
'apierror-chunk-too-small', Message::numParam( $minChunkSize ) ] );
356 if ( $this->mParams[
'offset'] == 0 ) {
357 $this->log->debug(
"Started first chunk of chunked upload of {filename} for {user}",
360 'filename' => $this->mParams[
'filename'] ??
'-',
361 'filesize' => $this->mParams[
'filesize'],
362 'chunkSize' => $chunkSize
365 $filekey = $this->performStash(
'critical' );
367 $filekey = $this->mParams[
'filekey'];
373 $this->log->info(
"Stash failed due to no session for {user}",
376 'filename' => $this->mParams[
'filename'] ??
'-',
377 'filekey' => $this->mParams[
'filekey'] ??
'-',
378 'filesize' => $this->mParams[
'filesize'],
379 'chunkSize' => $chunkSize
382 $this->dieWithError(
'apierror-stashfailed-nosession',
'stashfailed' );
383 } elseif ( $progress[
'result'] !==
'Continue' || $progress[
'stage'] !==
'uploading' ) {
384 $this->dieWithError(
'apierror-stashfailed-complete',
'stashfailed' );
387 $status = $this->mUpload->addChunk(
388 $chunkPath, $chunkSize, $this->mParams[
'offset'] );
389 if ( !$status->isGood() ) {
391 'offset' => $this->mUpload->getOffset(),
393 $this->log->info(
"Chunked upload stash failure {status} for {user}",
395 'status' => (
string)$status,
397 'filename' => $this->mParams[
'filename'] ??
'-',
398 'filekey' => $this->mParams[
'filekey'] ??
'-',
399 'filesize' => $this->mParams[
'filesize'],
400 'chunkSize' => $chunkSize,
401 'offset' => $this->mUpload->getOffset()
404 $this->dieStatusWithCode( $status,
'stashfailed', $extradata );
406 $this->log->debug(
"Got chunk for {filename} with offset {offset} for {user}",
409 'filename' => $this->mParams[
'filename'] ??
'-',
410 'filekey' => $this->mParams[
'filekey'] ??
'-',
411 'filesize' => $this->mParams[
'filesize'],
412 'chunkSize' => $chunkSize,
413 'offset' => $this->mUpload->getOffset()
420 if ( $totalSoFar == $this->mParams[
'filesize'] ) {
421 if ( $this->mParams[
'async'] ) {
425 [
'result' =>
'Poll',
426 'stage' =>
'queued',
'status' => Status::newGood() ]
432 $this->jobQueueGroup->lazyPush(
new AssembleUploadChunksJob( [
433 'filename' => $this->mParams[
'filename'],
434 'filekey' => $filekey,
435 'filesize' => $this->mParams[
'filesize'],
436 'session' => $this->
getContext()->exportSession()
438 $this->log->info(
"Received final chunk of {filename} for {user}, queuing assemble job",
441 'filename' => $this->mParams[
'filename'] ??
'-',
442 'filekey' => $this->mParams[
'filekey'] ??
'-',
443 'filesize' => $this->mParams[
'filesize'],
444 'chunkSize' => $chunkSize,
447 $result[
'result'] =
'Poll';
448 $result[
'stage'] =
'queued';
450 $this->log->info(
"Received final chunk of {filename} for {user}, assembling immediately",
453 'filename' => $this->mParams[
'filename'] ??
'-',
454 'filekey' => $this->mParams[
'filekey'] ??
'-',
455 'filesize' => $this->mParams[
'filesize'],
456 'chunkSize' => $chunkSize,
460 $status = $this->mUpload->concatenateChunks();
461 if ( !$status->isGood() ) {
465 [
'result' =>
'Failure',
'stage' =>
'assembling',
'status' => $status ]
467 $this->log->info(
"Non jobqueue assembly of {filename} failed because {status}",
470 'filename' => $this->mParams[
'filename'] ??
'-',
471 'filekey' => $this->mParams[
'filekey'] ??
'-',
472 'filesize' => $this->mParams[
'filesize'],
473 'chunkSize' => $chunkSize,
474 'status' => (
string)$status
477 $this->dieStatusWithCode( $status,
'stashfailed' );
481 $warnings = $this->getApiWarnings();
483 $result[
'warnings'] = $warnings;
489 $this->mUpload->stash->removeFile( $filekey );
490 $filekey = $this->mUpload->getStashFile()->getFileKey();
492 $result[
'result'] =
'Success';
499 'result' =>
'Continue',
500 'stage' =>
'uploading',
501 'offset' => $totalSoFar,
502 'status' => Status::newGood(),
505 $result[
'result'] =
'Continue';
506 $result[
'offset'] = $totalSoFar;
509 $result[
'filekey'] = $filekey;
526 private function performStash( $failureMode, &$data =
null ) {
527 $isPartial = (bool)$this->mParams[
'chunk'];
529 $status = $this->mUpload->tryStashFile( $this->
getUser(), $isPartial );
531 if ( $status->isGood() && !$status->getValue() ) {
533 $status->fatal(
new ApiMessage(
'apierror-stashinvalidfile',
'stashfailed' ) );
535 }
catch ( Exception $e ) {
536 $debugMessage =
'Stashing temporary file failed: ' . get_class( $e ) .
' ' . $e->getMessage();
537 $this->log->info( $debugMessage,
540 'filename' => $this->mParams[
'filename'] ??
'-',
541 'filekey' => $this->mParams[
'filekey'] ??
'-'
545 $status = Status::newFatal( $this->getErrorFormatter()->getMessageFromException(
546 $e, [
'wrap' =>
new ApiMessage(
'apierror-stashexception',
'stashfailed' ) ]
550 if ( $status->isGood() ) {
551 $stashFile = $status->getValue();
552 $data[
'filekey'] = $stashFile->getFileKey();
554 $data[
'sessionkey'] = $data[
'filekey'];
555 return $data[
'filekey'];
558 if ( $status->getMessage()->getKey() ===
'uploadstash-exception' ) {
561 [ $exceptionType, $message ] = $status->getMessage()->getParams();
562 $debugMessage =
'Stashing temporary file failed: ' . $exceptionType .
' ' . $message;
563 $this->log->info( $debugMessage,
566 'filename' => $this->mParams[
'filename'] ??
'-',
567 'filekey' => $this->mParams[
'filekey'] ??
'-'
572 $this->log->info(
"Stash upload failure {status}",
574 'status' => (
string)$status,
576 'filename' => $this->mParams[
'filename'] ??
'-',
577 'filekey' => $this->mParams[
'filekey'] ??
'-'
581 if ( $failureMode !==
'optional' ) {
582 $this->dieStatus( $status );
584 $data[
'stasherrors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
598 private function dieRecoverableError( $errors, $parameter =
null ) {
599 $this->performStash(
'optional', $data );
602 $data[
'invalidparameter'] = $parameter;
606 foreach ( $errors as $error ) {
607 $msg = ApiMessage::create( $error );
608 $msg->setApiData( $msg->getApiData() + $data );
611 $this->dieStatus( $sv );
625 $sv = StatusValue::newGood();
626 foreach ( $status->getMessages() as $error ) {
627 $msg = ApiMessage::create( $error, $overrideCode );
628 if ( $moreExtraData ) {
629 $msg->setApiData( $msg->getApiData() + $moreExtraData );
633 $this->dieStatus( $sv );
645 if ( !$this->mParams[
'chunk'] ) {
646 $this->requireOnlyOneParameter( $this->mParams,
647 'filekey',
'file',
'url' );
651 if ( $this->mParams[
'checkstatus'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
652 $statusKey = $this->mParams[
'filekey'] ?: UploadFromUrl::getCacheKey( $this->mParams );
653 $progress = UploadBase::getSessionStatus( $this->
getUser(), $statusKey );
655 $this->log->info(
"Cannot check upload status due to missing upload session for {user}",
657 'user' => $this->
getUser()->getName(),
658 'filename' => $this->mParams[
'filename'] ??
'-',
659 'filekey' => $this->mParams[
'filekey'] ??
'-'
662 $this->dieWithError(
'apierror-upload-missingresult',
'missingresult' );
663 } elseif ( !$progress[
'status']->isGood() ) {
664 $this->dieStatusWithCode( $progress[
'status'],
'stashfailed' );
666 if ( isset( $progress[
'status']->value[
'verification'] ) ) {
667 $this->checkVerification( $progress[
'status']->value[
'verification'] );
669 if ( isset( $progress[
'status']->value[
'warnings'] ) ) {
670 $warnings = $this->transformWarnings( $progress[
'status']->value[
'warnings'] );
672 $progress[
'warnings'] = $warnings;
675 unset( $progress[
'status'] );
677 if ( isset( $progress[
'imageinfo'] ) ) {
678 $imageinfo = $progress[
'imageinfo'];
679 unset( $progress[
'imageinfo'] );
682 $this->getResult()->addValue(
null, $this->getModuleName(), $progress );
686 $this->getResult()->addValue( $this->getModuleName(),
'imageinfo', $imageinfo );
693 if ( $this->mParams[
'filename'] ===
null ) {
694 $this->dieWithError( [
'apierror-missingparam',
'filename' ] );
697 if ( $this->mParams[
'chunk'] ) {
700 if ( isset( $this->mParams[
'filekey'] ) ) {
701 if ( $this->mParams[
'offset'] === 0 ) {
702 $this->dieWithError(
'apierror-upload-filekeynotallowed',
'filekeynotallowed' );
706 $this->mUpload->continueChunks(
707 $this->mParams[
'filename'],
708 $this->mParams[
'filekey'],
709 $this->getMain()->getUpload(
'chunk' )
712 if ( $this->mParams[
'offset'] !== 0 ) {
713 $this->dieWithError(
'apierror-upload-filekeyneeded',
'filekeyneeded' );
717 $this->mUpload->initialize(
718 $this->mParams[
'filename'],
719 $this->getMain()->getUpload(
'chunk' )
722 } elseif ( isset( $this->mParams[
'filekey'] ) ) {
724 if ( !UploadFromStash::isValidKey( $this->mParams[
'filekey'] ) ) {
725 $this->dieWithError(
'apierror-invalid-file-key' );
731 $this->mUpload->initialize(
732 $this->mParams[
'filekey'], $this->mParams[
'filename'], !$this->mParams[
'async']
734 } elseif ( isset( $this->mParams[
'file'] ) ) {
738 if ( $this->mParams[
'async'] ) {
739 $this->dieWithError(
'apierror-cannot-async-upload-file' );
743 $this->mUpload->initialize(
744 $this->mParams[
'filename'],
745 $this->getMain()->getUpload(
'file' )
747 } elseif ( isset( $this->mParams[
'url'] ) ) {
749 if ( !UploadFromUrl::isEnabled() ) {
750 $this->dieWithError(
'copyuploaddisabled' );
753 if ( !UploadFromUrl::isAllowedHost( $this->mParams[
'url'] ) ) {
754 $this->dieWithError(
'apierror-copyuploadbaddomain' );
757 if ( !UploadFromUrl::isAllowedUrl( $this->mParams[
'url'] ) ) {
758 $this->dieWithError(
'apierror-copyuploadbadurl' );
762 $this->mUpload->
initialize( $this->mParams[
'filename'],
763 $this->mParams[
'url'] );
776 $permission = $this->mUpload->isAllowed( $user );
778 if ( $permission !==
true ) {
779 if ( !$user->isNamed() ) {
780 $this->dieWithError( [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ] );
783 $this->dieStatus( User::newFatalPermissionDeniedStatus( $permission ) );
787 if ( $user->isBlockedFromUpload() ) {
789 $this->dieBlocked( $user->getBlock() );
797 if ( $this->mParams[
'chunk'] ) {
798 $maxSize = UploadBase::getMaxUploadSize();
799 if ( $this->mParams[
'filesize'] > $maxSize ) {
800 $this->dieWithError(
'file-too-large' );
802 if ( !$this->mUpload->getTitle() ) {
803 $this->dieWithError(
'illegal-filename' );
807 $verification = $this->mUpload->validateName();
808 if ( $verification ===
true ) {
811 } elseif ( $this->mParams[
'async'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
815 $verification = $this->mUpload->validateName();
816 if ( $verification ===
true ) {
820 wfDebug( __METHOD__ .
" about to verify" );
822 $verification = $this->mUpload->verifyUpload();
824 if ( $verification[
'status'] === UploadBase::OK ) {
827 $this->log->info(
"File verification of {filename} failed for {user} because {result}",
829 'user' => $this->
getUser()->getName(),
830 'resultCode' => $verification[
'status'],
831 'result' => $this->mUpload->getVerificationErrorCode( $verification[
'status'] ),
832 'filename' => $this->mParams[
'filename'] ??
'-',
833 'details' => $verification[
'details'] ??
''
839 $this->checkVerification( $verification );
848 $status = $this->mUpload->convertVerifyErrorToStatus( $verification );
849 if ( $status->isRecoverableError() ) {
850 $this->dieRecoverableError( [ $status->asApiMessage() ], $status->getInvalidParameter() );
853 $this->dieWithError( $status->asApiMessage() );
865 $warnings = UploadBase::makeWarningsSerializable(
866 $this->mUpload->checkWarnings( $this->getUser() )
869 return $this->transformWarnings( $warnings );
875 ApiResult::setIndexedTagName( $warnings,
'warning' );
877 if ( isset( $warnings[
'duplicate'] ) ) {
878 $dupes = array_column( $warnings[
'duplicate'],
'fileName' );
879 ApiResult::setIndexedTagName( $dupes,
'duplicate' );
880 $warnings[
'duplicate'] = $dupes;
883 if ( isset( $warnings[
'exists'] ) ) {
884 $warning = $warnings[
'exists'];
885 unset( $warnings[
'exists'] );
886 $localFile = $warning[
'normalizedFile'] ?? $warning[
'file'];
887 $warnings[$warning[
'warning']] = $localFile[
'fileName'];
890 if ( isset( $warnings[
'no-change'] ) ) {
891 $file = $warnings[
'no-change'];
892 unset( $warnings[
'no-change'] );
894 $warnings[
'nochange'] = [
895 'timestamp' =>
wfTimestamp( TS_ISO_8601, $file[
'timestamp'] )
899 if ( isset( $warnings[
'duplicate-version'] ) ) {
901 foreach ( $warnings[
'duplicate-version'] as $dupe ) {
903 'timestamp' =>
wfTimestamp( TS_ISO_8601, $dupe[
'timestamp'] )
906 unset( $warnings[
'duplicate-version'] );
908 ApiResult::setIndexedTagName( $dupes,
'ver' );
909 $warnings[
'duplicateversions'] = $dupes;
912 if ( $this->mParams[
'async'] && $this->mParams[
'url'] ) {
913 unset( $warnings[
'empty-file'] );
927 $this->log->info(
"Upload stashing of {filename} failed for {user} because {error}",
929 'user' => $this->
getUser()->getName(),
930 'error' => get_class( $e ),
931 'filename' => $this->mParams[
'filename'] ??
'-',
932 'filekey' => $this->mParams[
'filekey'] ??
'-'
936 switch ( get_class( $e ) ) {
937 case UploadStashFileNotFoundException::class:
938 $wrap =
'apierror-stashedfilenotfound';
940 case UploadStashBadPathException::class:
941 $wrap =
'apierror-stashpathinvalid';
943 case UploadStashFileException::class:
944 $wrap =
'apierror-stashfilestorage';
946 case UploadStashZeroLengthFileException::class:
947 $wrap =
'apierror-stashzerolength';
949 case UploadStashNotLoggedInException::class:
950 return StatusValue::newFatal( ApiMessage::create(
951 [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ],
'stashnotloggedin'
953 case UploadStashWrongOwnerException::class:
954 $wrap =
'apierror-stashwrongowner';
956 case UploadStashNoSuchKeyException::class:
957 $wrap =
'apierror-stashnosuchfilekey';
960 $wrap = [
'uploadstash-exception', get_class( $e ) ];
963 return StatusValue::newFatal(
964 $this->getErrorFormatter()->getMessageFromException( $e, [
'wrap' => $wrap ] )
977 $this->mParams[
'text'] ??= $this->mParams[
'comment'];
980 $file = $this->mUpload->getLocalFile();
982 $title = $file->getTitle();
990 $this->mParams[
'watchlist'], $title, $user,
'watchdefault'
993 if ( !$watch && $this->mParams[
'watchlist'] ==
'preferences' && !$file->exists() ) {
1002 if ( $this->mParams[
'watch'] ) {
1006 if ( $this->mParams[
'tags'] ) {
1007 $status = ChangeTags::canAddTagsAccompanyingChange( $this->mParams[
'tags'], $this->
getAuthority() );
1008 if ( !$status->isOK() ) {
1009 $this->dieStatus( $status );
1015 if ( $this->mParams[
'async'] ) {
1017 if ( $this->mParams[
'filekey'] ) {
1020 'filename' => $this->mParams[
'filename'],
1021 'filekey' => $this->mParams[
'filekey'],
1022 'comment' => $this->mParams[
'comment'],
1023 'tags' => $this->mParams[
'tags'] ?? [],
1024 'text' => $this->mParams[
'text'],
1026 'watchlistexpiry' => $watchlistExpiry,
1027 'session' => $this->
getContext()->exportSession(),
1028 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1031 } elseif ( $this->mParams[
'url'] ) {
1034 'filename' => $this->mParams[
'filename'],
1035 'url' => $this->mParams[
'url'],
1036 'comment' => $this->mParams[
'comment'],
1037 'tags' => $this->mParams[
'tags'] ?? [],
1038 'text' => $this->mParams[
'text'],
1040 'watchlistexpiry' => $watchlistExpiry,
1041 'session' => $this->
getContext()->exportSession(),
1042 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1046 $this->dieWithError(
'apierror-no-async-support',
'publishfailed' );
1052 $cacheKey =
$job->getCacheKey();
1055 $progress = UploadBase::getSessionStatus( $this->
getUser(), $cacheKey );
1056 if ( $progress && $progress[
'result'] ===
'Poll' ) {
1057 $this->dieWithError(
'apierror-upload-inprogress',
'publishfailed' );
1059 UploadBase::setSessionStatus(
1062 [
'result' =>
'Poll',
'stage' =>
'queued',
'status' => Status::newGood() ]
1065 $this->jobQueueGroup->push(
$job );
1066 $this->log->info(
"Sending publish job of {filename} for {user}",
1068 'user' => $this->
getUser()->getName(),
1069 'filename' => $this->mParams[
'filename'] ??
'-'
1072 $result[
'result'] =
'Poll';
1073 $result[
'stage'] =
'queued';
1076 $status = $this->mUpload->performUpload(
1077 $this->mParams[
'comment'],
1078 $this->mParams[
'text'],
1081 $this->mParams[
'tags'] ?? [],
1085 if ( !$status->isGood() ) {
1086 $this->log->info(
"Non-async API upload publish failed for {user} because {status}",
1088 'user' => $this->
getUser()->getName(),
1089 'filename' => $this->mParams[
'filename'] ??
'-',
1090 'filekey' => $this->mParams[
'filekey'] ??
'-',
1091 'status' => (
string)$status
1094 $this->dieRecoverableError( $status->getMessages() );
1096 $result[
'result'] =
'Success';
1099 $result[
'filename'] = $file->getName();
1100 if ( $warnings && count( $warnings ) > 0 ) {
1101 $result[
'warnings'] = $warnings;
1118 ParamValidator::PARAM_TYPE =>
'string',
1121 ParamValidator::PARAM_DEFAULT =>
''
1124 ParamValidator::PARAM_TYPE =>
'tags',
1125 ParamValidator::PARAM_ISMULTI =>
true,
1128 ParamValidator::PARAM_TYPE =>
'text',
1131 ParamValidator::PARAM_DEFAULT =>
false,
1132 ParamValidator::PARAM_DEPRECATED =>
true,
1145 'ignorewarnings' =>
false,
1147 ParamValidator::PARAM_TYPE =>
'upload',
1152 ParamValidator::PARAM_DEPRECATED =>
true,
1157 ParamValidator::PARAM_TYPE =>
'integer',
1158 IntegerDef::PARAM_MIN => 0,
1159 IntegerDef::PARAM_MAX => UploadBase::getMaxUploadSize(),
1162 ParamValidator::PARAM_TYPE =>
'integer',
1163 IntegerDef::PARAM_MIN => 0,
1166 ParamValidator::PARAM_TYPE =>
'upload',
1170 'checkstatus' =>
false,
1182 'action=upload&filename=Wiki.png' .
1183 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC'
1184 =>
'apihelp-upload-example-url',
1185 'action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC'
1186 =>
'apihelp-upload-example-filekey',
1191 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
1196class_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.
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 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.
UploadBase and subclasses are the backend of MediaWiki's file uploads.
static setSessionStatus(UserIdentity $user, $statusKey, $value)
Set the current status of a chunked upload (used for polling).
getLocalFile()
Return the local file and initializes if necessary.
static getSessionStatus(UserIdentity $user, $statusKey)
Get the current status of a chunked upload (used for polling).
Implements uploading from chunks.
Implements regular file uploads.
Implements uploading from previously stored file.
Implements uploading from a HTTP resource.
initialize( $name, $url)
Entry point for API upload.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
if(count( $args)< 1) $job