[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * 5 * Created on Aug 21, 2008 6 * 7 * Copyright © 2008 - 2010 Bryan Tong Minh <[email protected]> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 * http://www.gnu.org/copyleft/gpl.html 23 * 24 * @file 25 */ 26 27 /** 28 * @ingroup API 29 */ 30 class ApiUpload extends ApiBase { 31 /** @var UploadBase|UploadFromChunks */ 32 protected $mUpload = null; 33 34 protected $mParams; 35 36 public function execute() { 37 // Check whether upload is enabled 38 if ( !UploadBase::isEnabled() ) { 39 $this->dieUsageMsg( 'uploaddisabled' ); 40 } 41 42 $user = $this->getUser(); 43 44 // Parameter handling 45 $this->mParams = $this->extractRequestParams(); 46 $request = $this->getMain()->getRequest(); 47 // Check if async mode is actually supported (jobs done in cli mode) 48 $this->mParams['async'] = ( $this->mParams['async'] && $this->getConfig()->get( 'EnableAsyncUploads' ) ); 49 // Add the uploaded file to the params array 50 $this->mParams['file'] = $request->getFileName( 'file' ); 51 $this->mParams['chunk'] = $request->getFileName( 'chunk' ); 52 53 // Copy the session key to the file key, for backward compatibility. 54 if ( !$this->mParams['filekey'] && $this->mParams['sessionkey'] ) { 55 $this->logFeatureUsage( 'action=upload&sessionkey' ); 56 $this->mParams['filekey'] = $this->mParams['sessionkey']; 57 } 58 59 // Select an upload module 60 try { 61 if ( !$this->selectUploadModule() ) { 62 return; // not a true upload, but a status request or similar 63 } elseif ( !isset( $this->mUpload ) ) { 64 $this->dieUsage( 'No upload module set', 'nomodule' ); 65 } 66 } catch ( UploadStashException $e ) { // XXX: don't spam exception log 67 $this->dieUsage( get_class( $e ) . ": " . $e->getMessage(), 'stasherror' ); 68 } 69 70 // First check permission to upload 71 $this->checkPermissions( $user ); 72 73 // Fetch the file (usually a no-op) 74 /** @var $status Status */ 75 $status = $this->mUpload->fetchFile(); 76 if ( !$status->isGood() ) { 77 $errors = $status->getErrorsArray(); 78 $error = array_shift( $errors[0] ); 79 $this->dieUsage( 'Error fetching file from remote source', $error, 0, $errors[0] ); 80 } 81 82 // Check if the uploaded file is sane 83 if ( $this->mParams['chunk'] ) { 84 $maxSize = $this->mUpload->getMaxUploadSize(); 85 if ( $this->mParams['filesize'] > $maxSize ) { 86 $this->dieUsage( 'The file you submitted was too large', 'file-too-large' ); 87 } 88 if ( !$this->mUpload->getTitle() ) { 89 $this->dieUsage( 'Invalid file title supplied', 'internal-error' ); 90 } 91 } elseif ( $this->mParams['async'] && $this->mParams['filekey'] ) { 92 // defer verification to background process 93 } else { 94 wfDebug( __METHOD__ . " about to verify\n" ); 95 $this->verifyUpload(); 96 } 97 98 // Check if the user has the rights to modify or overwrite the requested title 99 // (This check is irrelevant if stashing is already requested, since the errors 100 // can always be fixed by changing the title) 101 if ( !$this->mParams['stash'] ) { 102 $permErrors = $this->mUpload->verifyTitlePermissions( $user ); 103 if ( $permErrors !== true ) { 104 $this->dieRecoverableError( $permErrors[0], 'filename' ); 105 } 106 } 107 108 // Get the result based on the current upload context: 109 try { 110 $result = $this->getContextResult(); 111 if ( $result['result'] === 'Success' ) { 112 $result['imageinfo'] = $this->mUpload->getImageInfo( $this->getResult() ); 113 } 114 } catch ( UploadStashException $e ) { // XXX: don't spam exception log 115 $this->dieUsage( get_class( $e ) . ": " . $e->getMessage(), 'stasherror' ); 116 } 117 118 $this->getResult()->addValue( null, $this->getModuleName(), $result ); 119 120 // Cleanup any temporary mess 121 $this->mUpload->cleanupTempFile(); 122 } 123 124 /** 125 * Get an upload result based on upload context 126 * @return array 127 */ 128 private function getContextResult() { 129 $warnings = $this->getApiWarnings(); 130 if ( $warnings && !$this->mParams['ignorewarnings'] ) { 131 // Get warnings formatted in result array format 132 return $this->getWarningsResult( $warnings ); 133 } elseif ( $this->mParams['chunk'] ) { 134 // Add chunk, and get result 135 return $this->getChunkResult( $warnings ); 136 } elseif ( $this->mParams['stash'] ) { 137 // Stash the file and get stash result 138 return $this->getStashResult( $warnings ); 139 } 140 141 // This is the most common case -- a normal upload with no warnings 142 // performUpload will return a formatted properly for the API with status 143 return $this->performUpload( $warnings ); 144 } 145 146 /** 147 * Get Stash Result, throws an exception if the file could not be stashed. 148 * @param array $warnings Array of Api upload warnings 149 * @return array 150 */ 151 private function getStashResult( $warnings ) { 152 $result = array(); 153 // Some uploads can request they be stashed, so as not to publish them immediately. 154 // In this case, a failure to stash ought to be fatal 155 try { 156 $result['result'] = 'Success'; 157 $result['filekey'] = $this->performStash(); 158 $result['sessionkey'] = $result['filekey']; // backwards compatibility 159 if ( $warnings && count( $warnings ) > 0 ) { 160 $result['warnings'] = $warnings; 161 } 162 } catch ( MWException $e ) { 163 $this->dieUsage( $e->getMessage(), 'stashfailed' ); 164 } 165 166 return $result; 167 } 168 169 /** 170 * Get Warnings Result 171 * @param array $warnings Array of Api upload warnings 172 * @return array 173 */ 174 private function getWarningsResult( $warnings ) { 175 $result = array(); 176 $result['result'] = 'Warning'; 177 $result['warnings'] = $warnings; 178 // in case the warnings can be fixed with some further user action, let's stash this upload 179 // and return a key they can use to restart it 180 try { 181 $result['filekey'] = $this->performStash(); 182 $result['sessionkey'] = $result['filekey']; // backwards compatibility 183 } catch ( MWException $e ) { 184 $result['warnings']['stashfailed'] = $e->getMessage(); 185 } 186 187 return $result; 188 } 189 190 /** 191 * Get the result of a chunk upload. 192 * @param array $warnings Array of Api upload warnings 193 * @return array 194 */ 195 private function getChunkResult( $warnings ) { 196 $result = array(); 197 198 $result['result'] = 'Continue'; 199 if ( $warnings && count( $warnings ) > 0 ) { 200 $result['warnings'] = $warnings; 201 } 202 $request = $this->getMain()->getRequest(); 203 $chunkPath = $request->getFileTempname( 'chunk' ); 204 $chunkSize = $request->getUpload( 'chunk' )->getSize(); 205 if ( $this->mParams['offset'] == 0 ) { 206 try { 207 $filekey = $this->performStash(); 208 } catch ( MWException $e ) { 209 // FIXME: Error handling here is wrong/different from rest of this 210 $this->dieUsage( $e->getMessage(), 'stashfailed' ); 211 } 212 } else { 213 $filekey = $this->mParams['filekey']; 214 $status = $this->mUpload->addChunk( 215 $chunkPath, $chunkSize, $this->mParams['offset'] ); 216 if ( !$status->isGood() ) { 217 $this->dieUsage( $status->getWikiText(), 'stashfailed' ); 218 219 return array(); 220 } 221 } 222 223 // Check we added the last chunk: 224 if ( $this->mParams['offset'] + $chunkSize == $this->mParams['filesize'] ) { 225 if ( $this->mParams['async'] ) { 226 $progress = UploadBase::getSessionStatus( $filekey ); 227 if ( $progress && $progress['result'] === 'Poll' ) { 228 $this->dieUsage( "Chunk assembly already in progress.", 'stashfailed' ); 229 } 230 UploadBase::setSessionStatus( 231 $filekey, 232 array( 'result' => 'Poll', 233 'stage' => 'queued', 'status' => Status::newGood() ) 234 ); 235 JobQueueGroup::singleton()->push( new AssembleUploadChunksJob( 236 Title::makeTitle( NS_FILE, $filekey ), 237 array( 238 'filename' => $this->mParams['filename'], 239 'filekey' => $filekey, 240 'session' => $this->getContext()->exportSession() 241 ) 242 ) ); 243 $result['result'] = 'Poll'; 244 $result['stage'] = 'queued'; 245 } else { 246 $status = $this->mUpload->concatenateChunks(); 247 if ( !$status->isGood() ) { 248 $this->dieUsage( $status->getWikiText(), 'stashfailed' ); 249 250 return array(); 251 } 252 253 // The fully concatenated file has a new filekey. So remove 254 // the old filekey and fetch the new one. 255 $this->mUpload->stash->removeFile( $filekey ); 256 $filekey = $this->mUpload->getLocalFile()->getFileKey(); 257 258 $result['result'] = 'Success'; 259 } 260 } 261 $result['filekey'] = $filekey; 262 $result['offset'] = $this->mParams['offset'] + $chunkSize; 263 264 return $result; 265 } 266 267 /** 268 * Stash the file and return the file key 269 * Also re-raises exceptions with slightly more informative message strings (useful for API) 270 * @throws MWException 271 * @return string File key 272 */ 273 private function performStash() { 274 try { 275 $stashFile = $this->mUpload->stashFile(); 276 277 if ( !$stashFile ) { 278 throw new MWException( 'Invalid stashed file' ); 279 } 280 $fileKey = $stashFile->getFileKey(); 281 } catch ( MWException $e ) { 282 $message = 'Stashing temporary file failed: ' . get_class( $e ) . ' ' . $e->getMessage(); 283 wfDebug( __METHOD__ . ' ' . $message . "\n" ); 284 throw new MWException( $message ); 285 } 286 287 return $fileKey; 288 } 289 290 /** 291 * Throw an error that the user can recover from by providing a better 292 * value for $parameter 293 * 294 * @param array $error Error array suitable for passing to dieUsageMsg() 295 * @param string $parameter Parameter that needs revising 296 * @param array $data Optional extra data to pass to the user 297 * @throws UsageException 298 */ 299 private function dieRecoverableError( $error, $parameter, $data = array() ) { 300 try { 301 $data['filekey'] = $this->performStash(); 302 $data['sessionkey'] = $data['filekey']; 303 } catch ( MWException $e ) { 304 $data['stashfailed'] = $e->getMessage(); 305 } 306 $data['invalidparameter'] = $parameter; 307 308 $parsed = $this->parseMsg( $error ); 309 $this->dieUsage( $parsed['info'], $parsed['code'], 0, $data ); 310 } 311 312 /** 313 * Select an upload module and set it to mUpload. Dies on failure. If the 314 * request was a status request and not a true upload, returns false; 315 * otherwise true 316 * 317 * @return bool 318 */ 319 protected function selectUploadModule() { 320 $request = $this->getMain()->getRequest(); 321 322 // chunk or one and only one of the following parameters is needed 323 if ( !$this->mParams['chunk'] ) { 324 $this->requireOnlyOneParameter( $this->mParams, 325 'filekey', 'file', 'url', 'statuskey' ); 326 } 327 328 // Status report for "upload to stash"/"upload from stash" 329 if ( $this->mParams['filekey'] && $this->mParams['checkstatus'] ) { 330 $progress = UploadBase::getSessionStatus( $this->mParams['filekey'] ); 331 if ( !$progress ) { 332 $this->dieUsage( 'No result in status data', 'missingresult' ); 333 } elseif ( !$progress['status']->isGood() ) { 334 $this->dieUsage( $progress['status']->getWikiText(), 'stashfailed' ); 335 } 336 if ( isset( $progress['status']->value['verification'] ) ) { 337 $this->checkVerification( $progress['status']->value['verification'] ); 338 } 339 unset( $progress['status'] ); // remove Status object 340 $this->getResult()->addValue( null, $this->getModuleName(), $progress ); 341 342 return false; 343 } 344 345 if ( $this->mParams['statuskey'] ) { 346 $this->checkAsyncDownloadEnabled(); 347 348 // Status request for an async upload 349 $sessionData = UploadFromUrlJob::getSessionData( $this->mParams['statuskey'] ); 350 if ( !isset( $sessionData['result'] ) ) { 351 $this->dieUsage( 'No result in session data', 'missingresult' ); 352 } 353 if ( $sessionData['result'] == 'Warning' ) { 354 $sessionData['warnings'] = $this->transformWarnings( $sessionData['warnings'] ); 355 $sessionData['sessionkey'] = $this->mParams['statuskey']; 356 } 357 $this->getResult()->addValue( null, $this->getModuleName(), $sessionData ); 358 359 return false; 360 } 361 362 // The following modules all require the filename parameter to be set 363 if ( is_null( $this->mParams['filename'] ) ) { 364 $this->dieUsageMsg( array( 'missingparam', 'filename' ) ); 365 } 366 367 if ( $this->mParams['chunk'] ) { 368 // Chunk upload 369 $this->mUpload = new UploadFromChunks(); 370 if ( isset( $this->mParams['filekey'] ) ) { 371 // handle new chunk 372 $this->mUpload->continueChunks( 373 $this->mParams['filename'], 374 $this->mParams['filekey'], 375 $request->getUpload( 'chunk' ) 376 ); 377 } else { 378 // handle first chunk 379 $this->mUpload->initialize( 380 $this->mParams['filename'], 381 $request->getUpload( 'chunk' ) 382 ); 383 } 384 } elseif ( isset( $this->mParams['filekey'] ) ) { 385 // Upload stashed in a previous request 386 if ( !UploadFromStash::isValidKey( $this->mParams['filekey'] ) ) { 387 $this->dieUsageMsg( 'invalid-file-key' ); 388 } 389 390 $this->mUpload = new UploadFromStash( $this->getUser() ); 391 // This will not download the temp file in initialize() in async mode. 392 // We still have enough information to call checkWarnings() and such. 393 $this->mUpload->initialize( 394 $this->mParams['filekey'], $this->mParams['filename'], !$this->mParams['async'] 395 ); 396 } elseif ( isset( $this->mParams['file'] ) ) { 397 $this->mUpload = new UploadFromFile(); 398 $this->mUpload->initialize( 399 $this->mParams['filename'], 400 $request->getUpload( 'file' ) 401 ); 402 } elseif ( isset( $this->mParams['url'] ) ) { 403 // Make sure upload by URL is enabled: 404 if ( !UploadFromUrl::isEnabled() ) { 405 $this->dieUsageMsg( 'copyuploaddisabled' ); 406 } 407 408 if ( !UploadFromUrl::isAllowedHost( $this->mParams['url'] ) ) { 409 $this->dieUsageMsg( 'copyuploadbaddomain' ); 410 } 411 412 if ( !UploadFromUrl::isAllowedUrl( $this->mParams['url'] ) ) { 413 $this->dieUsageMsg( 'copyuploadbadurl' ); 414 } 415 416 $async = false; 417 if ( $this->mParams['asyncdownload'] ) { 418 $this->checkAsyncDownloadEnabled(); 419 420 if ( $this->mParams['leavemessage'] && !$this->mParams['ignorewarnings'] ) { 421 $this->dieUsage( 'Using leavemessage without ignorewarnings is not supported', 422 'missing-ignorewarnings' ); 423 } 424 425 if ( $this->mParams['leavemessage'] ) { 426 $async = 'async-leavemessage'; 427 } else { 428 $async = 'async'; 429 } 430 } 431 $this->mUpload = new UploadFromUrl; 432 $this->mUpload->initialize( $this->mParams['filename'], 433 $this->mParams['url'], $async ); 434 } 435 436 return true; 437 } 438 439 /** 440 * Checks that the user has permissions to perform this upload. 441 * Dies with usage message on inadequate permissions. 442 * @param User $user The user to check. 443 */ 444 protected function checkPermissions( $user ) { 445 // Check whether the user has the appropriate permissions to upload anyway 446 $permission = $this->mUpload->isAllowed( $user ); 447 448 if ( $permission !== true ) { 449 if ( !$user->isLoggedIn() ) { 450 $this->dieUsageMsg( array( 'mustbeloggedin', 'upload' ) ); 451 } 452 453 $this->dieUsageMsg( 'badaccess-groups' ); 454 } 455 } 456 457 /** 458 * Performs file verification, dies on error. 459 */ 460 protected function verifyUpload() { 461 $verification = $this->mUpload->verifyUpload(); 462 if ( $verification['status'] === UploadBase::OK ) { 463 return; 464 } 465 466 $this->checkVerification( $verification ); 467 } 468 469 /** 470 * Performs file verification, dies on error. 471 * @param array $verification 472 */ 473 protected function checkVerification( array $verification ) { 474 // @todo Move them to ApiBase's message map 475 switch ( $verification['status'] ) { 476 // Recoverable errors 477 case UploadBase::MIN_LENGTH_PARTNAME: 478 $this->dieRecoverableError( 'filename-tooshort', 'filename' ); 479 break; 480 case UploadBase::ILLEGAL_FILENAME: 481 $this->dieRecoverableError( 'illegal-filename', 'filename', 482 array( 'filename' => $verification['filtered'] ) ); 483 break; 484 case UploadBase::FILENAME_TOO_LONG: 485 $this->dieRecoverableError( 'filename-toolong', 'filename' ); 486 break; 487 case UploadBase::FILETYPE_MISSING: 488 $this->dieRecoverableError( 'filetype-missing', 'filename' ); 489 break; 490 case UploadBase::WINDOWS_NONASCII_FILENAME: 491 $this->dieRecoverableError( 'windows-nonascii-filename', 'filename' ); 492 break; 493 494 // Unrecoverable errors 495 case UploadBase::EMPTY_FILE: 496 $this->dieUsage( 'The file you submitted was empty', 'empty-file' ); 497 break; 498 case UploadBase::FILE_TOO_LARGE: 499 $this->dieUsage( 'The file you submitted was too large', 'file-too-large' ); 500 break; 501 502 case UploadBase::FILETYPE_BADTYPE: 503 $extradata = array( 504 'filetype' => $verification['finalExt'], 505 'allowed' => array_values( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) ) 506 ); 507 $this->getResult()->setIndexedTagName( $extradata['allowed'], 'ext' ); 508 509 $msg = "Filetype not permitted: "; 510 if ( isset( $verification['blacklistedExt'] ) ) { 511 $msg .= join( ', ', $verification['blacklistedExt'] ); 512 $extradata['blacklisted'] = array_values( $verification['blacklistedExt'] ); 513 $this->getResult()->setIndexedTagName( $extradata['blacklisted'], 'ext' ); 514 } else { 515 $msg .= $verification['finalExt']; 516 } 517 $this->dieUsage( $msg, 'filetype-banned', 0, $extradata ); 518 break; 519 case UploadBase::VERIFICATION_ERROR: 520 $this->getResult()->setIndexedTagName( $verification['details'], 'detail' ); 521 $this->dieUsage( 'This file did not pass file verification', 'verification-error', 522 0, array( 'details' => $verification['details'] ) ); 523 break; 524 case UploadBase::HOOK_ABORTED: 525 $this->dieUsage( "The modification you tried to make was aborted by an extension hook", 526 'hookaborted', 0, array( 'error' => $verification['error'] ) ); 527 break; 528 default: 529 $this->dieUsage( 'An unknown error occurred', 'unknown-error', 530 0, array( 'code' => $verification['status'] ) ); 531 break; 532 } 533 } 534 535 /** 536 * Check warnings. 537 * Returns a suitable array for inclusion into API results if there were warnings 538 * Returns the empty array if there were no warnings 539 * 540 * @return array 541 */ 542 protected function getApiWarnings() { 543 $warnings = $this->mUpload->checkWarnings(); 544 545 return $this->transformWarnings( $warnings ); 546 } 547 548 protected function transformWarnings( $warnings ) { 549 if ( $warnings ) { 550 // Add indices 551 $result = $this->getResult(); 552 $result->setIndexedTagName( $warnings, 'warning' ); 553 554 if ( isset( $warnings['duplicate'] ) ) { 555 $dupes = array(); 556 /** @var File $dupe */ 557 foreach ( $warnings['duplicate'] as $dupe ) { 558 $dupes[] = $dupe->getName(); 559 } 560 $result->setIndexedTagName( $dupes, 'duplicate' ); 561 $warnings['duplicate'] = $dupes; 562 } 563 564 if ( isset( $warnings['exists'] ) ) { 565 $warning = $warnings['exists']; 566 unset( $warnings['exists'] ); 567 /** @var LocalFile $localFile */ 568 $localFile = isset( $warning['normalizedFile'] ) 569 ? $warning['normalizedFile'] 570 : $warning['file']; 571 $warnings[$warning['warning']] = $localFile->getName(); 572 } 573 } 574 575 return $warnings; 576 } 577 578 /** 579 * Perform the actual upload. Returns a suitable result array on success; 580 * dies on failure. 581 * 582 * @param array $warnings Array of Api upload warnings 583 * @return array 584 */ 585 protected function performUpload( $warnings ) { 586 // Use comment as initial page text by default 587 if ( is_null( $this->mParams['text'] ) ) { 588 $this->mParams['text'] = $this->mParams['comment']; 589 } 590 591 /** @var $file File */ 592 $file = $this->mUpload->getLocalFile(); 593 594 // For preferences mode, we want to watch if 'watchdefault' is set or 595 // if the *file* doesn't exist and 'watchcreations' is set. But 596 // getWatchlistValue()'s automatic handling checks if the *title* 597 // exists or not, so we need to check both prefs manually. 598 $watch = $this->getWatchlistValue( 599 $this->mParams['watchlist'], $file->getTitle(), 'watchdefault' 600 ); 601 if ( !$watch && $this->mParams['watchlist'] == 'preferences' && !$file->exists() ) { 602 $watch = $this->getWatchlistValue( 603 $this->mParams['watchlist'], $file->getTitle(), 'watchcreations' 604 ); 605 } 606 607 // Deprecated parameters 608 if ( $this->mParams['watch'] ) { 609 $this->logFeatureUsage( 'action=upload&watch' ); 610 $watch = true; 611 } 612 613 // No errors, no warnings: do the upload 614 if ( $this->mParams['async'] ) { 615 $progress = UploadBase::getSessionStatus( $this->mParams['filekey'] ); 616 if ( $progress && $progress['result'] === 'Poll' ) { 617 $this->dieUsage( "Upload from stash already in progress.", 'publishfailed' ); 618 } 619 UploadBase::setSessionStatus( 620 $this->mParams['filekey'], 621 array( 'result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood() ) 622 ); 623 JobQueueGroup::singleton()->push( new PublishStashedFileJob( 624 Title::makeTitle( NS_FILE, $this->mParams['filename'] ), 625 array( 626 'filename' => $this->mParams['filename'], 627 'filekey' => $this->mParams['filekey'], 628 'comment' => $this->mParams['comment'], 629 'text' => $this->mParams['text'], 630 'watch' => $watch, 631 'session' => $this->getContext()->exportSession() 632 ) 633 ) ); 634 $result['result'] = 'Poll'; 635 $result['stage'] = 'queued'; 636 } else { 637 /** @var $status Status */ 638 $status = $this->mUpload->performUpload( $this->mParams['comment'], 639 $this->mParams['text'], $watch, $this->getUser() ); 640 641 if ( !$status->isGood() ) { 642 $error = $status->getErrorsArray(); 643 644 if ( count( $error ) == 1 && $error[0][0] == 'async' ) { 645 // The upload can not be performed right now, because the user 646 // requested so 647 return array( 648 'result' => 'Queued', 649 'statuskey' => $error[0][1], 650 ); 651 } 652 653 $this->getResult()->setIndexedTagName( $error, 'error' ); 654 $this->dieUsage( 'An internal error occurred', 'internal-error', 0, $error ); 655 } 656 $result['result'] = 'Success'; 657 } 658 659 $result['filename'] = $file->getName(); 660 if ( $warnings && count( $warnings ) > 0 ) { 661 $result['warnings'] = $warnings; 662 } 663 664 return $result; 665 } 666 667 /** 668 * Checks if asynchronous copy uploads are enabled and throws an error if they are not. 669 */ 670 protected function checkAsyncDownloadEnabled() { 671 if ( !$this->getConfig()->get( 'AllowAsyncCopyUploads' ) ) { 672 $this->dieUsage( 'Asynchronous copy uploads disabled', 'asynccopyuploaddisabled' ); 673 } 674 } 675 676 public function mustBePosted() { 677 return true; 678 } 679 680 public function isWriteMode() { 681 return true; 682 } 683 684 public function getAllowedParams() { 685 $params = array( 686 'filename' => array( 687 ApiBase::PARAM_TYPE => 'string', 688 ), 689 'comment' => array( 690 ApiBase::PARAM_DFLT => '' 691 ), 692 'text' => null, 693 'watch' => array( 694 ApiBase::PARAM_DFLT => false, 695 ApiBase::PARAM_DEPRECATED => true, 696 ), 697 'watchlist' => array( 698 ApiBase::PARAM_DFLT => 'preferences', 699 ApiBase::PARAM_TYPE => array( 700 'watch', 701 'preferences', 702 'nochange' 703 ), 704 ), 705 'ignorewarnings' => false, 706 'file' => array( 707 ApiBase::PARAM_TYPE => 'upload', 708 ), 709 'url' => null, 710 'filekey' => null, 711 'sessionkey' => array( 712 ApiBase::PARAM_DFLT => null, 713 ApiBase::PARAM_DEPRECATED => true, 714 ), 715 'stash' => false, 716 717 'filesize' => null, 718 'offset' => null, 719 'chunk' => array( 720 ApiBase::PARAM_TYPE => 'upload', 721 ), 722 723 'async' => false, 724 'asyncdownload' => false, 725 'leavemessage' => false, 726 'statuskey' => null, 727 'checkstatus' => false, 728 ); 729 730 return $params; 731 } 732 733 public function getParamDescription() { 734 $params = array( 735 'filename' => 'Target filename', 736 'comment' => 'Upload comment. Also used as the initial page text for new ' . 737 'files if "text" is not specified', 738 'text' => 'Initial page text for new files', 739 'watch' => 'Watch the page', 740 'watchlist' => 'Unconditionally add or remove the page from your watchlist, ' . 741 'use preferences or do not change watch', 742 'ignorewarnings' => 'Ignore any warnings', 743 'file' => 'File contents', 744 'url' => 'URL to fetch the file from', 745 'filekey' => 'Key that identifies a previous upload that was stashed temporarily.', 746 'sessionkey' => 'Same as filekey, maintained for backward compatibility.', 747 'stash' => 'If set, the server will not add the file to the repository ' . 748 'and stash it temporarily.', 749 750 'chunk' => 'Chunk contents', 751 'offset' => 'Offset of chunk in bytes', 752 'filesize' => 'Filesize of entire upload', 753 754 'async' => 'Make potentially large file operations asynchronous when possible', 755 'asyncdownload' => 'Make fetching a URL asynchronous', 756 'leavemessage' => 'If asyncdownload is used, leave a message on the user talk page if finished', 757 'statuskey' => 'Fetch the upload status for this file key (upload by URL)', 758 'checkstatus' => 'Only fetch the upload status for the given file key', 759 ); 760 761 return $params; 762 } 763 764 public function getDescription() { 765 return array( 766 'Upload a file, or get the status of pending uploads. Several methods are available:', 767 ' * Upload file contents directly, using the "file" parameter', 768 ' * Have the MediaWiki server fetch a file from a URL, using the "url" parameter', 769 ' * Complete an earlier upload that failed due to warnings, using the "filekey" parameter', 770 'Note that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when', 771 'sending the "file".', 772 ); 773 } 774 775 public function needsToken() { 776 return 'csrf'; 777 } 778 779 public function getExamples() { 780 return array( 781 'api.php?action=upload&filename=Wiki.png' . 782 '&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&token=123ABC' 783 => 'Upload from a URL', 784 'api.php?action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1&token=123ABC' 785 => 'Complete an upload that failed due to warnings', 786 ); 787 } 788 789 public function getHelpUrls() { 790 return 'https://www.mediawiki.org/wiki/API:Upload'; 791 } 792 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |