33use Psr\Log\LoggerInterface;
67 private LoggerInterface $log;
77 parent::__construct( $mainModule, $moduleName );
78 $this->jobQueueGroup = $jobQueueGroup;
82 $this->watchlistMaxDuration =
84 $this->watchlistManager = $watchlistManager;
85 $this->watchedItemStore = $watchedItemStore;
86 $this->userOptionsLookup = $userOptionsLookup;
87 $this->log = LoggerFactory::getInstance(
'upload' );
92 if ( !UploadBase::isEnabled() ) {
101 $this->mParams[
'async'] = ( $this->mParams[
'async'] &&
105 if ( !$this->mParams[
'filekey'] && $this->mParams[
'sessionkey'] ) {
106 $this->mParams[
'filekey'] = $this->mParams[
'sessionkey'];
109 if ( !$this->mParams[
'checkstatus'] ) {
117 } elseif ( !$this->mUpload ) {
118 $this->
dieDebug( __METHOD__,
'No upload module set' );
130 if ( $this->mParams[
'async'] && $this->mParams[
'url'] ) {
131 $status = $this->mUpload->canFetchFile();
133 $status = $this->mUpload->fetchFile();
136 if ( !$status->isGood() ) {
137 $this->log->info(
"Unable to fetch file {filename} for {user} because {status}",
139 'user' => $this->
getUser()->getName(),
140 'status' => (
string)$status,
141 'filename' => $this->mParams[
'filename'] ??
'-',
153 if ( !$this->mParams[
'stash'] ) {
154 $status = $this->mUpload->authorizeUpload( $user );
155 if ( !$status->isGood() ) {
156 $this->dieRecoverableError( $status->getMessages(),
'filename' );
162 $result = $this->getContextResult();
171 if ( $result[
'result'] ===
'Success' ) {
177 $this->mUpload->cleanupTempFile();
186 $services->getJobQueueGroup(),
187 $services->getWatchlistManager(),
188 $services->getWatchedItemStore(),
189 $services->getUserOptionsLookup()
210 $result = $this->getResult();
219 array_fill_keys( $imParam,
true ),
227 array_fill_keys( $imParam,
true ),
239 private function getContextResult() {
240 $warnings = $this->getApiWarnings();
241 if ( $warnings && !$this->mParams[
'ignorewarnings'] ) {
243 return $this->getWarningsResult( $warnings );
244 } elseif ( $this->mParams[
'chunk'] ) {
246 return $this->getChunkResult( $warnings );
247 } elseif ( $this->mParams[
'stash'] ) {
249 return $this->getStashResult( $warnings );
254 return $this->performUpload( $warnings );
262 private function getStashResult( $warnings ) {
264 $result[
'result'] =
'Success';
265 if ( $warnings && count( $warnings ) > 0 ) {
266 $result[
'warnings'] = $warnings;
270 $this->performStash(
'critical', $result );
280 private function getWarningsResult( $warnings ) {
282 $result[
'result'] =
'Warning';
283 $result[
'warnings'] = $warnings;
286 $this->performStash(
'optional', $result );
298 $configured = $config->
get( MainConfigNames::MinUploadChunkSize );
303 ini_get(
'post_max_size' ),
312 UploadBase::getMaxUploadSize(
'file' ),
313 UploadBase::getMaxPhpUploadSize(),
323 private function getChunkResult( $warnings ) {
326 if ( $warnings && count( $warnings ) > 0 ) {
327 $result[
'warnings'] = $warnings;
330 $chunkUpload = $this->getMain()->getUpload(
'chunk' );
331 $chunkPath = $chunkUpload->getTempName();
332 $chunkSize = $chunkUpload->getSize();
333 $totalSoFar = $this->mParams[
'offset'] + $chunkSize;
334 $minChunkSize = self::getMinUploadChunkSize( $this->getConfig() );
337 if ( $totalSoFar > $this->mParams[
'filesize'] ) {
338 $this->dieWithError(
'apierror-invalid-chunk' );
342 if ( $totalSoFar != $this->mParams[
'filesize'] && $chunkSize < $minChunkSize ) {
343 $this->dieWithError( [
'apierror-chunk-too-small', Message::numParam( $minChunkSize ) ] );
346 if ( $this->mParams[
'offset'] == 0 ) {
347 $this->log->debug(
"Started first chunk of chunked upload of {filename} for {user}",
350 'filename' => $this->mParams[
'filename'] ??
'-',
351 'filesize' => $this->mParams[
'filesize'],
352 'chunkSize' => $chunkSize
355 $filekey = $this->performStash(
'critical' );
357 $filekey = $this->mParams[
'filekey'];
363 $this->log->info(
"Stash failed due to no session for {user}",
366 'filename' => $this->mParams[
'filename'] ??
'-',
367 'filekey' => $this->mParams[
'filekey'] ??
'-',
368 'filesize' => $this->mParams[
'filesize'],
369 'chunkSize' => $chunkSize
372 $this->dieWithError(
'apierror-stashfailed-nosession',
'stashfailed' );
373 } elseif ( $progress[
'result'] !==
'Continue' || $progress[
'stage'] !==
'uploading' ) {
374 $this->dieWithError(
'apierror-stashfailed-complete',
'stashfailed' );
377 $status = $this->mUpload->addChunk(
378 $chunkPath, $chunkSize, $this->mParams[
'offset'] );
379 if ( !$status->isGood() ) {
381 'offset' => $this->mUpload->getOffset(),
383 $this->log->info(
"Chunked upload stash failure {status} for {user}",
385 'status' => (
string)$status,
387 'filename' => $this->mParams[
'filename'] ??
'-',
388 'filekey' => $this->mParams[
'filekey'] ??
'-',
389 'filesize' => $this->mParams[
'filesize'],
390 'chunkSize' => $chunkSize,
391 'offset' => $this->mUpload->getOffset()
394 $this->dieStatusWithCode( $status,
'stashfailed', $extradata );
396 $this->log->debug(
"Got chunk for {filename} with offset {offset} for {user}",
399 'filename' => $this->mParams[
'filename'] ??
'-',
400 'filekey' => $this->mParams[
'filekey'] ??
'-',
401 'filesize' => $this->mParams[
'filesize'],
402 'chunkSize' => $chunkSize,
403 'offset' => $this->mUpload->getOffset()
410 if ( $totalSoFar == $this->mParams[
'filesize'] ) {
411 if ( $this->mParams[
'async'] ) {
415 [
'result' =>
'Poll',
416 'stage' =>
'queued',
'status' => Status::newGood() ]
422 $this->jobQueueGroup->lazyPush(
new AssembleUploadChunksJob( [
423 'filename' => $this->mParams[
'filename'],
424 'filekey' => $filekey,
425 'filesize' => $this->mParams[
'filesize'],
426 'session' => $this->
getContext()->exportSession()
428 $this->log->info(
"Received final chunk of {filename} for {user}, queuing assemble job",
431 'filename' => $this->mParams[
'filename'] ??
'-',
432 'filekey' => $this->mParams[
'filekey'] ??
'-',
433 'filesize' => $this->mParams[
'filesize'],
434 'chunkSize' => $chunkSize,
437 $result[
'result'] =
'Poll';
438 $result[
'stage'] =
'queued';
440 $this->log->info(
"Received final chunk of {filename} for {user}, assembling immediately",
443 'filename' => $this->mParams[
'filename'] ??
'-',
444 'filekey' => $this->mParams[
'filekey'] ??
'-',
445 'filesize' => $this->mParams[
'filesize'],
446 'chunkSize' => $chunkSize,
450 $status = $this->mUpload->concatenateChunks();
451 if ( !$status->isGood() ) {
455 [
'result' =>
'Failure',
'stage' =>
'assembling',
'status' => $status ]
457 $this->log->info(
"Non jobqueue assembly of {filename} failed because {status}",
460 'filename' => $this->mParams[
'filename'] ??
'-',
461 'filekey' => $this->mParams[
'filekey'] ??
'-',
462 'filesize' => $this->mParams[
'filesize'],
463 'chunkSize' => $chunkSize,
464 'status' => (
string)$status
467 $this->dieStatusWithCode( $status,
'stashfailed' );
471 $warnings = $this->getApiWarnings();
473 $result[
'warnings'] = $warnings;
479 $this->mUpload->stash->removeFile( $filekey );
480 $filekey = $this->mUpload->getStashFile()->getFileKey();
482 $result[
'result'] =
'Success';
489 'result' =>
'Continue',
490 'stage' =>
'uploading',
491 'offset' => $totalSoFar,
492 'status' => Status::newGood(),
495 $result[
'result'] =
'Continue';
496 $result[
'offset'] = $totalSoFar;
499 $result[
'filekey'] = $filekey;
516 private function performStash( $failureMode, &$data =
null ) {
517 $isPartial = (bool)$this->mParams[
'chunk'];
519 $status = $this->mUpload->tryStashFile( $this->
getUser(), $isPartial );
521 if ( $status->isGood() && !$status->getValue() ) {
523 $status->fatal(
new ApiMessage(
'apierror-stashinvalidfile',
'stashfailed' ) );
525 }
catch ( Exception $e ) {
526 $debugMessage =
'Stashing temporary file failed: ' . get_class( $e ) .
' ' . $e->getMessage();
527 $this->log->info( $debugMessage,
530 'filename' => $this->mParams[
'filename'] ??
'-',
531 'filekey' => $this->mParams[
'filekey'] ??
'-'
535 $status = Status::newFatal( $this->getErrorFormatter()->getMessageFromException(
536 $e, [
'wrap' =>
new ApiMessage(
'apierror-stashexception',
'stashfailed' ) ]
540 if ( $status->isGood() ) {
541 $stashFile = $status->getValue();
542 $data[
'filekey'] = $stashFile->getFileKey();
544 $data[
'sessionkey'] = $data[
'filekey'];
545 return $data[
'filekey'];
548 if ( $status->getMessage()->getKey() ===
'uploadstash-exception' ) {
551 [ $exceptionType, $message ] = $status->getMessage()->getParams();
552 $debugMessage =
'Stashing temporary file failed: ' . $exceptionType .
' ' . $message;
553 $this->log->info( $debugMessage,
556 'filename' => $this->mParams[
'filename'] ??
'-',
557 'filekey' => $this->mParams[
'filekey'] ??
'-'
562 $this->log->info(
"Stash upload failure {status}",
564 'status' => (
string)$status,
566 'filename' => $this->mParams[
'filename'] ??
'-',
567 'filekey' => $this->mParams[
'filekey'] ??
'-'
571 if ( $failureMode !==
'optional' ) {
572 $this->dieStatus( $status );
574 $data[
'stasherrors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
588 private function dieRecoverableError( $errors, $parameter =
null ): never {
589 $this->performStash(
'optional', $data );
592 $data[
'invalidparameter'] = $parameter;
596 foreach ( $errors as $error ) {
597 $msg = ApiMessage::create( $error );
598 $msg->setApiData( $msg->getApiData() + $data );
601 $this->dieStatus( $sv );
616 foreach ( $status->getMessages() as $error ) {
617 $msg = ApiMessage::create( $error, $overrideCode );
618 if ( $moreExtraData ) {
619 $msg->setApiData( $msg->getApiData() + $moreExtraData );
623 $this->dieStatus( $sv );
635 if ( !$this->mParams[
'chunk'] ) {
636 $this->requireOnlyOneParameter( $this->mParams,
637 'filekey',
'file',
'url' );
641 if ( $this->mParams[
'checkstatus'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
642 $statusKey = $this->mParams[
'filekey'] ?: UploadFromUrl::getCacheKey( $this->mParams );
643 $progress = UploadBase::getSessionStatus( $this->
getUser(), $statusKey );
645 $this->log->info(
"Cannot check upload status due to missing upload session for {user}",
647 'user' => $this->
getUser()->getName(),
648 'filename' => $this->mParams[
'filename'] ??
'-',
649 'filekey' => $this->mParams[
'filekey'] ??
'-'
652 $this->dieWithError(
'apierror-upload-missingresult',
'missingresult' );
653 } elseif ( !$progress[
'status']->isGood() ) {
654 $this->dieStatusWithCode( $progress[
'status'],
'stashfailed' );
656 if ( isset( $progress[
'status']->value[
'verification'] ) ) {
657 $this->checkVerification( $progress[
'status']->value[
'verification'] );
659 if ( isset( $progress[
'status']->value[
'warnings'] ) ) {
660 $warnings = $this->transformWarnings( $progress[
'status']->value[
'warnings'] );
662 $progress[
'warnings'] = $warnings;
665 unset( $progress[
'status'] );
667 if ( isset( $progress[
'imageinfo'] ) ) {
668 $imageinfo = $progress[
'imageinfo'];
669 unset( $progress[
'imageinfo'] );
672 $this->getResult()->addValue(
null, $this->getModuleName(), $progress );
676 $this->getResult()->addValue( $this->getModuleName(),
'imageinfo', $imageinfo );
683 if ( $this->mParams[
'filename'] ===
null ) {
684 $this->dieWithError( [
'apierror-missingparam',
'filename' ] );
687 if ( $this->mParams[
'chunk'] ) {
690 if ( isset( $this->mParams[
'filekey'] ) ) {
691 if ( $this->mParams[
'offset'] === 0 ) {
692 $this->dieWithError(
'apierror-upload-filekeynotallowed',
'filekeynotallowed' );
696 $this->mUpload->continueChunks(
697 $this->mParams[
'filename'],
698 $this->mParams[
'filekey'],
699 $this->getMain()->getUpload(
'chunk' )
702 if ( $this->mParams[
'offset'] !== 0 ) {
703 $this->dieWithError(
'apierror-upload-filekeyneeded',
'filekeyneeded' );
707 $this->mUpload->initialize(
708 $this->mParams[
'filename'],
709 $this->getMain()->getUpload(
'chunk' )
712 } elseif ( isset( $this->mParams[
'filekey'] ) ) {
714 if ( !UploadFromStash::isValidKey( $this->mParams[
'filekey'] ) ) {
715 $this->dieWithError(
'apierror-invalid-file-key' );
721 $this->mUpload->initialize(
722 $this->mParams[
'filekey'], $this->mParams[
'filename'], !$this->mParams[
'async']
724 } elseif ( isset( $this->mParams[
'file'] ) ) {
728 if ( $this->mParams[
'async'] ) {
729 $this->dieWithError(
'apierror-cannot-async-upload-file' );
733 $this->mUpload->initialize(
734 $this->mParams[
'filename'],
735 $this->getMain()->getUpload(
'file' )
737 } elseif ( isset( $this->mParams[
'url'] ) ) {
739 if ( !UploadFromUrl::isEnabled() ) {
740 $this->dieWithError(
'copyuploaddisabled' );
743 if ( !UploadFromUrl::isAllowedHost( $this->mParams[
'url'] ) ) {
744 $this->dieWithError(
'apierror-copyuploadbaddomain' );
747 if ( !UploadFromUrl::isAllowedUrl( $this->mParams[
'url'] ) ) {
748 $this->dieWithError(
'apierror-copyuploadbadurl' );
752 $this->mUpload->
initialize( $this->mParams[
'filename'],
753 $this->mParams[
'url'] );
766 $permission = $this->mUpload->isAllowed( $user );
768 if ( $permission !==
true ) {
769 if ( !$user->isNamed() ) {
770 $this->dieWithError( [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ] );
773 $this->dieStatus( User::newFatalPermissionDeniedStatus( $permission ) );
777 if ( $user->isBlockedFromUpload() ) {
779 $this->dieBlocked( $user->getBlock() );
787 if ( $this->mParams[
'chunk'] ) {
788 $maxSize = UploadBase::getMaxUploadSize();
789 if ( $this->mParams[
'filesize'] > $maxSize ) {
790 $this->dieWithError(
'file-too-large' );
792 if ( !$this->mUpload->getTitle() ) {
793 $this->dieWithError(
'illegal-filename' );
797 $verification = $this->mUpload->validateName();
798 if ( $verification ===
true ) {
801 } elseif ( $this->mParams[
'async'] && ( $this->mParams[
'filekey'] || $this->mParams[
'url'] ) ) {
805 $verification = $this->mUpload->validateName();
806 if ( $verification ===
true ) {
810 wfDebug( __METHOD__ .
" about to verify" );
812 $verification = $this->mUpload->verifyUpload();
814 if ( $verification[
'status'] === UploadBase::OK ) {
817 $this->log->info(
"File verification of {filename} failed for {user} because {result}",
819 'user' => $this->
getUser()->getName(),
820 'resultCode' => $verification[
'status'],
821 'result' => $this->mUpload->getVerificationErrorCode( $verification[
'status'] ),
822 'filename' => $this->mParams[
'filename'] ??
'-',
823 'details' => $verification[
'details'] ??
''
829 $this->checkVerification( $verification );
838 $status = $this->mUpload->convertVerifyErrorToStatus( $verification );
839 if ( $status->isRecoverableError() ) {
840 $this->dieRecoverableError( [ $status->asApiMessage() ], $status->getInvalidParameter() );
843 $this->dieWithError( $status->asApiMessage() );
855 $warnings = UploadBase::makeWarningsSerializable(
856 $this->mUpload->checkWarnings( $this->getUser() )
859 return $this->transformWarnings( $warnings );
865 ApiResult::setIndexedTagName( $warnings,
'warning' );
867 if ( isset( $warnings[
'duplicate'] ) ) {
868 $dupes = array_column( $warnings[
'duplicate'],
'fileName' );
869 ApiResult::setIndexedTagName( $dupes,
'duplicate' );
870 $warnings[
'duplicate'] = $dupes;
873 if ( isset( $warnings[
'exists'] ) ) {
874 $warning = $warnings[
'exists'];
875 unset( $warnings[
'exists'] );
876 $localFile = $warning[
'normalizedFile'] ?? $warning[
'file'];
877 $warnings[$warning[
'warning']] = $localFile[
'fileName'];
880 if ( isset( $warnings[
'no-change'] ) ) {
881 $file = $warnings[
'no-change'];
882 unset( $warnings[
'no-change'] );
884 $warnings[
'nochange'] = [
885 'timestamp' =>
wfTimestamp( TS_ISO_8601, $file[
'timestamp'] )
889 if ( isset( $warnings[
'duplicate-version'] ) ) {
891 foreach ( $warnings[
'duplicate-version'] as $dupe ) {
893 'timestamp' =>
wfTimestamp( TS_ISO_8601, $dupe[
'timestamp'] )
896 unset( $warnings[
'duplicate-version'] );
898 ApiResult::setIndexedTagName( $dupes,
'ver' );
899 $warnings[
'duplicateversions'] = $dupes;
902 if ( $this->mParams[
'async'] && $this->mParams[
'url'] ) {
903 unset( $warnings[
'empty-file'] );
917 $this->log->info(
"Upload stashing of {filename} failed for {user} because {error}",
919 'user' => $this->
getUser()->getName(),
920 'error' => get_class( $e ),
921 'filename' => $this->mParams[
'filename'] ??
'-',
922 'filekey' => $this->mParams[
'filekey'] ??
'-'
926 switch ( get_class( $e ) ) {
927 case UploadStashFileNotFoundException::class:
928 $wrap =
'apierror-stashedfilenotfound';
930 case UploadStashBadPathException::class:
931 $wrap =
'apierror-stashpathinvalid';
933 case UploadStashFileException::class:
934 $wrap =
'apierror-stashfilestorage';
936 case UploadStashZeroLengthFileException::class:
937 $wrap =
'apierror-stashzerolength';
939 case UploadStashNotLoggedInException::class:
940 return StatusValue::newFatal( ApiMessage::create(
941 [
'apierror-mustbeloggedin', $this->msg(
'action-upload' ) ],
'stashnotloggedin'
943 case UploadStashWrongOwnerException::class:
944 $wrap =
'apierror-stashwrongowner';
946 case UploadStashNoSuchKeyException::class:
947 $wrap =
'apierror-stashnosuchfilekey';
950 $wrap = [
'uploadstash-exception', get_class( $e ) ];
953 return StatusValue::newFatal(
954 $this->getErrorFormatter()->getMessageFromException( $e, [
'wrap' => $wrap ] )
967 $this->mParams[
'text'] ??= $this->mParams[
'comment'];
970 $file = $this->mUpload->getLocalFile();
972 $title = $file->getTitle();
980 $this->mParams[
'watchlist'], $title, $user,
'watchdefault'
983 if ( !$watch && $this->mParams[
'watchlist'] ==
'preferences' && !$file->exists() ) {
992 if ( $this->mParams[
'watch'] ) {
996 if ( $this->mParams[
'tags'] ) {
997 $status = ChangeTags::canAddTagsAccompanyingChange( $this->mParams[
'tags'], $this->
getAuthority() );
998 if ( !$status->isOK() ) {
999 $this->dieStatus( $status );
1005 if ( $this->mParams[
'async'] ) {
1007 if ( $this->mParams[
'filekey'] ) {
1010 'filename' => $this->mParams[
'filename'],
1011 'filekey' => $this->mParams[
'filekey'],
1012 'comment' => $this->mParams[
'comment'],
1013 'tags' => $this->mParams[
'tags'] ?? [],
1014 'text' => $this->mParams[
'text'],
1016 'watchlistexpiry' => $watchlistExpiry,
1017 'session' => $this->
getContext()->exportSession(),
1018 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1021 } elseif ( $this->mParams[
'url'] ) {
1024 'filename' => $this->mParams[
'filename'],
1025 'url' => $this->mParams[
'url'],
1026 'comment' => $this->mParams[
'comment'],
1027 'tags' => $this->mParams[
'tags'] ?? [],
1028 'text' => $this->mParams[
'text'],
1030 'watchlistexpiry' => $watchlistExpiry,
1031 'session' => $this->
getContext()->exportSession(),
1032 'ignorewarnings' => $this->mParams[
'ignorewarnings']
1036 $this->dieWithError(
'apierror-no-async-support',
'publishfailed' );
1042 $cacheKey =
$job->getCacheKey();
1045 $progress = UploadBase::getSessionStatus( $this->
getUser(), $cacheKey );
1046 if ( $progress && $progress[
'result'] ===
'Poll' ) {
1047 $this->dieWithError(
'apierror-upload-inprogress',
'publishfailed' );
1049 UploadBase::setSessionStatus(
1052 [
'result' =>
'Poll',
'stage' =>
'queued',
'status' => Status::newGood() ]
1055 $this->jobQueueGroup->push(
$job );
1056 $this->log->info(
"Sending publish job of {filename} for {user}",
1058 'user' => $this->
getUser()->getName(),
1059 'filename' => $this->mParams[
'filename'] ??
'-'
1062 $result[
'result'] =
'Poll';
1063 $result[
'stage'] =
'queued';
1066 $status = $this->mUpload->performUpload(
1067 $this->mParams[
'comment'],
1068 $this->mParams[
'text'],
1071 $this->mParams[
'tags'] ?? [],
1075 if ( !$status->isGood() ) {
1076 $this->log->info(
"Non-async API upload publish failed for {user} because {status}",
1078 'user' => $this->
getUser()->getName(),
1079 'filename' => $this->mParams[
'filename'] ??
'-',
1080 'filekey' => $this->mParams[
'filekey'] ??
'-',
1081 'status' => (
string)$status
1084 $this->dieRecoverableError( $status->getMessages() );
1086 $result[
'result'] =
'Success';
1089 $result[
'filename'] = $file->getName();
1090 if ( $warnings && count( $warnings ) > 0 ) {
1091 $result[
'warnings'] = $warnings;
1111 ParamValidator::PARAM_TYPE =>
'string',
1114 ParamValidator::PARAM_DEFAULT =>
''
1117 ParamValidator::PARAM_TYPE =>
'tags',
1118 ParamValidator::PARAM_ISMULTI =>
true,
1121 ParamValidator::PARAM_TYPE =>
'text',
1124 ParamValidator::PARAM_DEFAULT =>
false,
1125 ParamValidator::PARAM_DEPRECATED =>
true,
1138 'ignorewarnings' =>
false,
1140 ParamValidator::PARAM_TYPE =>
'upload',
1145 ParamValidator::PARAM_DEPRECATED =>
true,
1150 ParamValidator::PARAM_TYPE =>
'integer',
1151 IntegerDef::PARAM_MIN => 0,
1152 IntegerDef::PARAM_MAX => UploadBase::getMaxUploadSize(),
1155 ParamValidator::PARAM_TYPE =>
'integer',
1156 IntegerDef::PARAM_MIN => 0,
1159 ParamValidator::PARAM_TYPE =>
'upload',
1163 'checkstatus' =>
false,
1177 'action=upload&filename=Wiki.png' .
1178 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC'
1179 =>
'apihelp-upload-example-url',
1180 'action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC'
1181 =>
'apihelp-upload-example-filekey',
1187 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
1192class_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 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