MediaWiki
REL1_24
|
00001 <?php 00031 class SpecialUpload extends SpecialPage { 00037 public function __construct( $request = null ) { 00038 parent::__construct( 'Upload', 'upload' ); 00039 } 00040 00044 public $mRequest; 00045 public $mSourceType; 00046 00048 public $mUpload; 00049 00051 public $mLocalFile; 00052 public $mUploadClicked; 00053 00057 public $mDesiredDestName; 00058 public $mComment; 00059 public $mLicense; 00060 00063 public $mIgnoreWarning; 00064 public $mWatchthis; 00065 public $mCopyrightStatus; 00066 public $mCopyrightSource; 00067 00070 public $mDestWarningAck; 00071 00073 public $mForReUpload; 00074 00076 public $mCancelUpload; 00077 public $mTokenOk; 00078 00080 public $mUploadSuccessful = false; 00081 00083 public $uploadFormTextTop; 00084 public $uploadFormTextAfterSummary; 00085 00089 protected function loadRequest() { 00090 $this->mRequest = $request = $this->getRequest(); 00091 $this->mSourceType = $request->getVal( 'wpSourceType', 'file' ); 00092 $this->mUpload = UploadBase::createFromRequest( $request ); 00093 $this->mUploadClicked = $request->wasPosted() 00094 && ( $request->getCheck( 'wpUpload' ) 00095 || $request->getCheck( 'wpUploadIgnoreWarning' ) ); 00096 00097 // Guess the desired name from the filename if not provided 00098 $this->mDesiredDestName = $request->getText( 'wpDestFile' ); 00099 if ( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) { 00100 $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' ); 00101 } 00102 $this->mLicense = $request->getText( 'wpLicense' ); 00103 00104 $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' ); 00105 $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' ) 00106 || $request->getCheck( 'wpUploadIgnoreWarning' ); 00107 $this->mWatchthis = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isLoggedIn(); 00108 $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' ); 00109 $this->mCopyrightSource = $request->getText( 'wpUploadSource' ); 00110 00111 $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file 00112 00113 $commentDefault = ''; 00114 $commentMsg = wfMessage( 'upload-default-description' )->inContentLanguage(); 00115 if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) { 00116 $commentDefault = $commentMsg->plain(); 00117 } 00118 $this->mComment = $request->getText( 'wpUploadDescription', $commentDefault ); 00119 00120 $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' ) 00121 || $request->getCheck( 'wpReUpload' ); // b/w compat 00122 00123 // If it was posted check for the token (no remote POST'ing with user credentials) 00124 $token = $request->getVal( 'wpEditToken' ); 00125 $this->mTokenOk = $this->getUser()->matchEditToken( $token ); 00126 00127 $this->uploadFormTextTop = ''; 00128 $this->uploadFormTextAfterSummary = ''; 00129 } 00130 00139 public function userCanExecute( User $user ) { 00140 return UploadBase::isEnabled() && parent::userCanExecute( $user ); 00141 } 00142 00147 public function execute( $par ) { 00148 $this->setHeaders(); 00149 $this->outputHeader(); 00150 00151 # Check uploading enabled 00152 if ( !UploadBase::isEnabled() ) { 00153 throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' ); 00154 } 00155 00156 # Check permissions 00157 $user = $this->getUser(); 00158 $permissionRequired = UploadBase::isAllowed( $user ); 00159 if ( $permissionRequired !== true ) { 00160 throw new PermissionsError( $permissionRequired ); 00161 } 00162 00163 # Check blocks 00164 if ( $user->isBlocked() ) { 00165 throw new UserBlockedError( $user->getBlock() ); 00166 } 00167 00168 # Check whether we actually want to allow changing stuff 00169 $this->checkReadOnly(); 00170 00171 $this->loadRequest(); 00172 00173 # Unsave the temporary file in case this was a cancelled upload 00174 if ( $this->mCancelUpload ) { 00175 if ( !$this->unsaveUploadedFile() ) { 00176 # Something went wrong, so unsaveUploadedFile showed a warning 00177 return; 00178 } 00179 } 00180 00181 # Process upload or show a form 00182 if ( 00183 $this->mTokenOk && !$this->mCancelUpload && 00184 ( $this->mUpload && $this->mUploadClicked ) 00185 ) { 00186 $this->processUpload(); 00187 } else { 00188 # Backwards compatibility hook 00189 if ( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) { 00190 wfDebug( "Hook 'UploadForm:initial' broke output of the upload form\n" ); 00191 00192 return; 00193 } 00194 $this->showUploadForm( $this->getUploadForm() ); 00195 } 00196 00197 # Cleanup 00198 if ( $this->mUpload ) { 00199 $this->mUpload->cleanupTempFile(); 00200 } 00201 } 00202 00208 protected function showUploadForm( $form ) { 00209 # Add links if file was previously deleted 00210 if ( $this->mDesiredDestName ) { 00211 $this->showViewDeletedLinks(); 00212 } 00213 00214 if ( $form instanceof HTMLForm ) { 00215 $form->show(); 00216 } else { 00217 $this->getOutput()->addHTML( $form ); 00218 } 00219 } 00220 00229 protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) { 00230 # Initialize form 00231 $context = new DerivativeContext( $this->getContext() ); 00232 $context->setTitle( $this->getPageTitle() ); // Remove subpage 00233 $form = new UploadForm( array( 00234 'watch' => $this->getWatchCheck(), 00235 'forreupload' => $this->mForReUpload, 00236 'sessionkey' => $sessionKey, 00237 'hideignorewarning' => $hideIgnoreWarning, 00238 'destwarningack' => (bool)$this->mDestWarningAck, 00239 00240 'description' => $this->mComment, 00241 'texttop' => $this->uploadFormTextTop, 00242 'textaftersummary' => $this->uploadFormTextAfterSummary, 00243 'destfile' => $this->mDesiredDestName, 00244 ), $context ); 00245 00246 # Check the token, but only if necessary 00247 if ( 00248 !$this->mTokenOk && !$this->mCancelUpload && 00249 ( $this->mUpload && $this->mUploadClicked ) 00250 ) { 00251 $form->addPreText( $this->msg( 'session_fail_preview' )->parse() ); 00252 } 00253 00254 # Give a notice if the user is uploading a file that has been deleted or moved 00255 # Note that this is independent from the message 'filewasdeleted' that requires JS 00256 $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName ); 00257 $delNotice = ''; // empty by default 00258 if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) { 00259 LogEventsList::showLogExtract( $delNotice, array( 'delete', 'move' ), 00260 $desiredTitleObj, 00261 '', array( 'lim' => 10, 00262 'conds' => array( "log_action != 'revision'" ), 00263 'showIfEmpty' => false, 00264 'msgKey' => array( 'upload-recreate-warning' ) ) 00265 ); 00266 } 00267 $form->addPreText( $delNotice ); 00268 00269 # Add text to form 00270 $form->addPreText( '<div id="uploadtext">' . 00271 $this->msg( 'uploadtext', array( $this->mDesiredDestName ) )->parseAsBlock() . 00272 '</div>' ); 00273 # Add upload error message 00274 $form->addPreText( $message ); 00275 00276 # Add footer to form 00277 $uploadFooter = $this->msg( 'uploadfooter' ); 00278 if ( !$uploadFooter->isDisabled() ) { 00279 $form->addPostText( '<div id="mw-upload-footer-message">' 00280 . $uploadFooter->parseAsBlock() . "</div>\n" ); 00281 } 00282 00283 return $form; 00284 } 00285 00289 protected function showViewDeletedLinks() { 00290 $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName ); 00291 $user = $this->getUser(); 00292 // Show a subtitle link to deleted revisions (to sysops et al only) 00293 if ( $title instanceof Title ) { 00294 $count = $title->isDeleted(); 00295 if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) { 00296 $restorelink = Linker::linkKnown( 00297 SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ), 00298 $this->msg( 'restorelink' )->numParams( $count )->escaped() 00299 ); 00300 $link = $this->msg( $user->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted' ) 00301 ->rawParams( $restorelink )->parseAsBlock(); 00302 $this->getOutput()->addHTML( "<div id=\"contentSub2\">{$link}</div>" ); 00303 } 00304 } 00305 } 00306 00318 protected function showRecoverableUploadError( $message ) { 00319 $sessionKey = $this->mUpload->stashSession(); 00320 $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . "</h2>\n" . 00321 '<div class="error">' . $message . "</div>\n"; 00322 00323 $form = $this->getUploadForm( $message, $sessionKey ); 00324 $form->setSubmitText( $this->msg( 'upload-tryagain' )->escaped() ); 00325 $this->showUploadForm( $form ); 00326 } 00327 00336 protected function showUploadWarning( $warnings ) { 00337 # If there are no warnings, or warnings we can ignore, return early. 00338 # mDestWarningAck is set when some javascript has shown the warning 00339 # to the user. mForReUpload is set when the user clicks the "upload a 00340 # new version" link. 00341 if ( !$warnings || ( count( $warnings ) == 1 00342 && isset( $warnings['exists'] ) 00343 && ( $this->mDestWarningAck || $this->mForReUpload ) ) 00344 ) { 00345 return false; 00346 } 00347 00348 $sessionKey = $this->mUpload->stashSession(); 00349 00350 $warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n" 00351 . '<ul class="warning">'; 00352 foreach ( $warnings as $warning => $args ) { 00353 if ( $warning == 'badfilename' ) { 00354 $this->mDesiredDestName = Title::makeTitle( NS_FILE, $args )->getText(); 00355 } 00356 if ( $warning == 'exists' ) { 00357 $msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n"; 00358 } elseif ( $warning == 'duplicate' ) { 00359 $msg = $this->getDupeWarning( $args ); 00360 } elseif ( $warning == 'duplicate-archive' ) { 00361 if ( $args === '' ) { 00362 $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate-notitle' )->parse() 00363 . "</li>\n"; 00364 } else { 00365 $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate', 00366 Title::makeTitle( NS_FILE, $args )->getPrefixedText() )->parse() 00367 . "</li>\n"; 00368 } 00369 } else { 00370 if ( $args === true ) { 00371 $args = array(); 00372 } elseif ( !is_array( $args ) ) { 00373 $args = array( $args ); 00374 } 00375 $msg = "\t<li>" . $this->msg( $warning, $args )->parse() . "</li>\n"; 00376 } 00377 $warningHtml .= $msg; 00378 } 00379 $warningHtml .= "</ul>\n"; 00380 $warningHtml .= $this->msg( 'uploadwarning-text' )->parseAsBlock(); 00381 00382 $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true ); 00383 $form->setSubmitText( $this->msg( 'upload-tryagain' )->text() ); 00384 $form->addButton( 'wpUploadIgnoreWarning', $this->msg( 'ignorewarning' )->text() ); 00385 $form->addButton( 'wpCancelUpload', $this->msg( 'reuploaddesc' )->text() ); 00386 00387 $this->showUploadForm( $form ); 00388 00389 # Indicate that we showed a form 00390 return true; 00391 } 00392 00398 protected function showUploadError( $message ) { 00399 $message = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n" . 00400 '<div class="error">' . $message . "</div>\n"; 00401 $this->showUploadForm( $this->getUploadForm( $message ) ); 00402 } 00403 00408 protected function processUpload() { 00409 // Fetch the file if required 00410 $status = $this->mUpload->fetchFile(); 00411 if ( !$status->isOK() ) { 00412 $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); 00413 00414 return; 00415 } 00416 00417 if ( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) { 00418 wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" ); 00419 // This code path is deprecated. If you want to break upload processing 00420 // do so by hooking into the appropriate hooks in UploadBase::verifyUpload 00421 // and UploadBase::verifyFile. 00422 // If you use this hook to break uploading, the user will be returned 00423 // an empty form with no error message whatsoever. 00424 return; 00425 } 00426 00427 // Upload verification 00428 $details = $this->mUpload->verifyUpload(); 00429 if ( $details['status'] != UploadBase::OK ) { 00430 $this->processVerificationError( $details ); 00431 00432 return; 00433 } 00434 00435 // Verify permissions for this title 00436 $permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() ); 00437 if ( $permErrors !== true ) { 00438 $code = array_shift( $permErrors[0] ); 00439 $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() ); 00440 00441 return; 00442 } 00443 00444 $this->mLocalFile = $this->mUpload->getLocalFile(); 00445 00446 // Check warnings if necessary 00447 if ( !$this->mIgnoreWarning ) { 00448 $warnings = $this->mUpload->checkWarnings(); 00449 if ( $this->showUploadWarning( $warnings ) ) { 00450 return; 00451 } 00452 } 00453 00454 // Get the page text if this is not a reupload 00455 if ( !$this->mForReUpload ) { 00456 $pageText = self::getInitialPageText( $this->mComment, $this->mLicense, 00457 $this->mCopyrightStatus, $this->mCopyrightSource ); 00458 } else { 00459 $pageText = false; 00460 } 00461 00462 $status = $this->mUpload->performUpload( 00463 $this->mComment, 00464 $pageText, 00465 $this->mWatchthis, 00466 $this->getUser() 00467 ); 00468 00469 if ( !$status->isGood() ) { 00470 $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); 00471 00472 return; 00473 } 00474 00475 // Success, redirect to description page 00476 $this->mUploadSuccessful = true; 00477 wfRunHooks( 'SpecialUploadComplete', array( &$this ) ); 00478 $this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() ); 00479 } 00480 00490 public static function getInitialPageText( $comment = '', $license = '', 00491 $copyStatus = '', $source = '' 00492 ) { 00493 global $wgUseCopyrightUpload, $wgForceUIMsgAsContentMsg; 00494 00495 $msg = array(); 00496 /* These messages are transcluded into the actual text of the description page. 00497 * Thus, forcing them as content messages makes the upload to produce an int: template 00498 * instead of hardcoding it there in the uploader language. 00499 */ 00500 foreach ( array( 'license-header', 'filedesc', 'filestatus', 'filesource' ) as $msgName ) { 00501 if ( in_array( $msgName, (array)$wgForceUIMsgAsContentMsg ) ) { 00502 $msg[$msgName] = "{{int:$msgName}}"; 00503 } else { 00504 $msg[$msgName] = wfMessage( $msgName )->inContentLanguage()->text(); 00505 } 00506 } 00507 00508 if ( $wgUseCopyrightUpload ) { 00509 $licensetxt = ''; 00510 if ( $license != '' ) { 00511 $licensetxt = '== ' . $msg['license-header'] . " ==\n" . '{{' . $license . '}}' . "\n"; 00512 } 00513 $pageText = '== ' . $msg['filedesc'] . " ==\n" . $comment . "\n" . 00514 '== ' . $msg['filestatus'] . " ==\n" . $copyStatus . "\n" . 00515 "$licensetxt" . 00516 '== ' . $msg['filesource'] . " ==\n" . $source; 00517 } else { 00518 if ( $license != '' ) { 00519 $filedesc = $comment == '' ? '' : '== ' . $msg['filedesc'] . " ==\n" . $comment . "\n"; 00520 $pageText = $filedesc . 00521 '== ' . $msg['license-header'] . " ==\n" . '{{' . $license . '}}' . "\n"; 00522 } else { 00523 $pageText = $comment; 00524 } 00525 } 00526 00527 return $pageText; 00528 } 00529 00542 protected function getWatchCheck() { 00543 if ( $this->getUser()->getOption( 'watchdefault' ) ) { 00544 // Watch all edits! 00545 return true; 00546 } 00547 00548 $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName ); 00549 if ( $desiredTitleObj instanceof Title && $this->getUser()->isWatched( $desiredTitleObj ) ) { 00550 // Already watched, don't change that 00551 return true; 00552 } 00553 00554 $local = wfLocalFile( $this->mDesiredDestName ); 00555 if ( $local && $local->exists() ) { 00556 // We're uploading a new version of an existing file. 00557 // No creation, so don't watch it if we're not already. 00558 return false; 00559 } else { 00560 // New page should get watched if that's our option. 00561 return $this->getUser()->getOption( 'watchcreations' ); 00562 } 00563 } 00564 00571 protected function processVerificationError( $details ) { 00572 switch ( $details['status'] ) { 00573 00575 case UploadBase::MIN_LENGTH_PARTNAME: 00576 $this->showRecoverableUploadError( $this->msg( 'minlength1' )->escaped() ); 00577 break; 00578 case UploadBase::ILLEGAL_FILENAME: 00579 $this->showRecoverableUploadError( $this->msg( 'illegalfilename', 00580 $details['filtered'] )->parse() ); 00581 break; 00582 case UploadBase::FILENAME_TOO_LONG: 00583 $this->showRecoverableUploadError( $this->msg( 'filename-toolong' )->escaped() ); 00584 break; 00585 case UploadBase::FILETYPE_MISSING: 00586 $this->showRecoverableUploadError( $this->msg( 'filetype-missing' )->parse() ); 00587 break; 00588 case UploadBase::WINDOWS_NONASCII_FILENAME: 00589 $this->showRecoverableUploadError( $this->msg( 'windows-nonascii-filename' )->parse() ); 00590 break; 00591 00593 case UploadBase::EMPTY_FILE: 00594 $this->showUploadError( $this->msg( 'emptyfile' )->escaped() ); 00595 break; 00596 case UploadBase::FILE_TOO_LARGE: 00597 $this->showUploadError( $this->msg( 'largefileserver' )->escaped() ); 00598 break; 00599 case UploadBase::FILETYPE_BADTYPE: 00600 $msg = $this->msg( 'filetype-banned-type' ); 00601 if ( isset( $details['blacklistedExt'] ) ) { 00602 $msg->params( $this->getLanguage()->commaList( $details['blacklistedExt'] ) ); 00603 } else { 00604 $msg->params( $details['finalExt'] ); 00605 } 00606 $extensions = array_unique( $this->getConfig()->get( 'FileExtensions' ) ); 00607 $msg->params( $this->getLanguage()->commaList( $extensions ), 00608 count( $extensions ) ); 00609 00610 // Add PLURAL support for the first parameter. This results 00611 // in a bit unlogical parameter sequence, but does not break 00612 // old translations 00613 if ( isset( $details['blacklistedExt'] ) ) { 00614 $msg->params( count( $details['blacklistedExt'] ) ); 00615 } else { 00616 $msg->params( 1 ); 00617 } 00618 00619 $this->showUploadError( $msg->parse() ); 00620 break; 00621 case UploadBase::VERIFICATION_ERROR: 00622 unset( $details['status'] ); 00623 $code = array_shift( $details['details'] ); 00624 $this->showUploadError( $this->msg( $code, $details['details'] )->parse() ); 00625 break; 00626 case UploadBase::HOOK_ABORTED: 00627 if ( is_array( $details['error'] ) ) { # allow hooks to return error details in an array 00628 $args = $details['error']; 00629 $error = array_shift( $args ); 00630 } else { 00631 $error = $details['error']; 00632 $args = null; 00633 } 00634 00635 $this->showUploadError( $this->msg( $error, $args )->parse() ); 00636 break; 00637 default: 00638 throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" ); 00639 } 00640 } 00641 00647 protected function unsaveUploadedFile() { 00648 if ( !( $this->mUpload instanceof UploadFromStash ) ) { 00649 return true; 00650 } 00651 $success = $this->mUpload->unsaveUploadedFile(); 00652 if ( !$success ) { 00653 $this->getOutput()->showFileDeleteError( $this->mUpload->getTempPath() ); 00654 00655 return false; 00656 } else { 00657 return true; 00658 } 00659 } 00660 00661 /*** Functions for formatting warnings ***/ 00662 00670 public static function getExistsWarning( $exists ) { 00671 if ( !$exists ) { 00672 return ''; 00673 } 00674 00675 $file = $exists['file']; 00676 $filename = $file->getTitle()->getPrefixedText(); 00677 $warning = ''; 00678 00679 if ( $exists['warning'] == 'exists' ) { 00680 // Exact match 00681 $warning = wfMessage( 'fileexists', $filename )->parse(); 00682 } elseif ( $exists['warning'] == 'page-exists' ) { 00683 // Page exists but file does not 00684 $warning = wfMessage( 'filepageexists', $filename )->parse(); 00685 } elseif ( $exists['warning'] == 'exists-normalized' ) { 00686 $warning = wfMessage( 'fileexists-extension', $filename, 00687 $exists['normalizedFile']->getTitle()->getPrefixedText() )->parse(); 00688 } elseif ( $exists['warning'] == 'thumb' ) { 00689 // Swapped argument order compared with other messages for backwards compatibility 00690 $warning = wfMessage( 'fileexists-thumbnail-yes', 00691 $exists['thumbFile']->getTitle()->getPrefixedText(), $filename )->parse(); 00692 } elseif ( $exists['warning'] == 'thumb-name' ) { 00693 // Image w/o '180px-' does not exists, but we do not like these filenames 00694 $name = $file->getName(); 00695 $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 ); 00696 $warning = wfMessage( 'file-thumbnail-no', $badPart )->parse(); 00697 } elseif ( $exists['warning'] == 'bad-prefix' ) { 00698 $warning = wfMessage( 'filename-bad-prefix', $exists['prefix'] )->parse(); 00699 } elseif ( $exists['warning'] == 'was-deleted' ) { 00700 # If the file existed before and was deleted, warn the user of this 00701 $ltitle = SpecialPage::getTitleFor( 'Log' ); 00702 $llink = Linker::linkKnown( 00703 $ltitle, 00704 wfMessage( 'deletionlog' )->escaped(), 00705 array(), 00706 array( 00707 'type' => 'delete', 00708 'page' => $filename 00709 ) 00710 ); 00711 $warning = wfMessage( 'filewasdeleted' )->rawParams( $llink )->parseAsBlock(); 00712 } 00713 00714 return $warning; 00715 } 00716 00722 public function getDupeWarning( $dupes ) { 00723 if ( !$dupes ) { 00724 return ''; 00725 } 00726 00727 $gallery = ImageGalleryBase::factory( false, $this->getContext() ); 00728 $gallery->setShowBytes( false ); 00729 foreach ( $dupes as $file ) { 00730 $gallery->add( $file->getTitle() ); 00731 } 00732 00733 return '<li>' . 00734 wfMessage( 'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() . 00735 $gallery->toHtml() . "</li>\n"; 00736 } 00737 00738 protected function getGroupName() { 00739 return 'media'; 00740 } 00741 00749 static public function rotationEnabled() { 00750 $bitmapHandler = new BitmapHandler(); 00751 return $bitmapHandler->autoRotateEnabled(); 00752 } 00753 } 00754 00758 class UploadForm extends HTMLForm { 00759 protected $mWatch; 00760 protected $mForReUpload; 00761 protected $mSessionKey; 00762 protected $mHideIgnoreWarning; 00763 protected $mDestWarningAck; 00764 protected $mDestFile; 00765 00766 protected $mComment; 00767 protected $mTextTop; 00768 protected $mTextAfterSummary; 00769 00770 protected $mSourceIds; 00771 00772 protected $mMaxFileSize = array(); 00773 00774 protected $mMaxUploadSize = array(); 00775 00776 public function __construct( array $options = array(), IContextSource $context = null ) { 00777 $this->mWatch = !empty( $options['watch'] ); 00778 $this->mForReUpload = !empty( $options['forreupload'] ); 00779 $this->mSessionKey = isset( $options['sessionkey'] ) ? $options['sessionkey'] : ''; 00780 $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] ); 00781 $this->mDestWarningAck = !empty( $options['destwarningack'] ); 00782 $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : ''; 00783 00784 $this->mComment = isset( $options['description'] ) ? 00785 $options['description'] : ''; 00786 00787 $this->mTextTop = isset( $options['texttop'] ) 00788 ? $options['texttop'] : ''; 00789 00790 $this->mTextAfterSummary = isset( $options['textaftersummary'] ) 00791 ? $options['textaftersummary'] : ''; 00792 00793 $sourceDescriptor = $this->getSourceSection(); 00794 $descriptor = $sourceDescriptor 00795 + $this->getDescriptionSection() 00796 + $this->getOptionsSection(); 00797 00798 wfRunHooks( 'UploadFormInitDescriptor', array( &$descriptor ) ); 00799 parent::__construct( $descriptor, $context, 'upload' ); 00800 00801 # Add a link to edit MediaWik:Licenses 00802 if ( $this->getUser()->isAllowed( 'editinterface' ) ) { 00803 $licensesLink = Linker::link( 00804 Title::makeTitle( NS_MEDIAWIKI, 'Licenses' ), 00805 $this->msg( 'licenses-edit' )->escaped(), 00806 array(), 00807 array( 'action' => 'edit' ) 00808 ); 00809 $editLicenses = '<p class="mw-upload-editlicenses">' . $licensesLink . '</p>'; 00810 $this->addFooterText( $editLicenses, 'description' ); 00811 } 00812 00813 # Set some form properties 00814 $this->setSubmitText( $this->msg( 'uploadbtn' )->text() ); 00815 $this->setSubmitName( 'wpUpload' ); 00816 # Used message keys: 'accesskey-upload', 'tooltip-upload' 00817 $this->setSubmitTooltip( 'upload' ); 00818 $this->setId( 'mw-upload-form' ); 00819 00820 # Build a list of IDs for javascript insertion 00821 $this->mSourceIds = array(); 00822 foreach ( $sourceDescriptor as $field ) { 00823 if ( !empty( $field['id'] ) ) { 00824 $this->mSourceIds[] = $field['id']; 00825 } 00826 } 00827 } 00828 00835 protected function getSourceSection() { 00836 if ( $this->mSessionKey ) { 00837 return array( 00838 'SessionKey' => array( 00839 'type' => 'hidden', 00840 'default' => $this->mSessionKey, 00841 ), 00842 'SourceType' => array( 00843 'type' => 'hidden', 00844 'default' => 'Stash', 00845 ), 00846 ); 00847 } 00848 00849 $canUploadByUrl = UploadFromUrl::isEnabled() 00850 && ( UploadFromUrl::isAllowed( $this->getUser() ) === true ) 00851 && $this->getConfig()->get( 'CopyUploadsFromSpecialUpload' ); 00852 $radio = $canUploadByUrl; 00853 $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) ); 00854 00855 $descriptor = array(); 00856 if ( $this->mTextTop ) { 00857 $descriptor['UploadFormTextTop'] = array( 00858 'type' => 'info', 00859 'section' => 'source', 00860 'default' => $this->mTextTop, 00861 'raw' => true, 00862 ); 00863 } 00864 00865 $this->mMaxUploadSize['file'] = UploadBase::getMaxUploadSize( 'file' ); 00866 # Limit to upload_max_filesize unless we are running under HipHop and 00867 # that setting doesn't exist 00868 if ( !wfIsHHVM() ) { 00869 $this->mMaxUploadSize['file'] = min( $this->mMaxUploadSize['file'], 00870 wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ), 00871 wfShorthandToInteger( ini_get( 'post_max_size' ) ) 00872 ); 00873 } 00874 00875 $descriptor['UploadFile'] = array( 00876 'class' => 'UploadSourceField', 00877 'section' => 'source', 00878 'type' => 'file', 00879 'id' => 'wpUploadFile', 00880 'radio-id' => 'wpSourceTypeFile', 00881 'label-message' => 'sourcefilename', 00882 'upload-type' => 'File', 00883 'radio' => &$radio, 00884 'help' => $this->msg( 'upload-maxfilesize', 00885 $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['file'] ) 00886 )->parse() . 00887 $this->msg( 'word-separator' )->escaped() . 00888 $this->msg( 'upload_source_file' )->escaped(), 00889 'checked' => $selectedSourceType == 'file', 00890 ); 00891 00892 if ( $canUploadByUrl ) { 00893 $this->mMaxUploadSize['url'] = UploadBase::getMaxUploadSize( 'url' ); 00894 $descriptor['UploadFileURL'] = array( 00895 'class' => 'UploadSourceField', 00896 'section' => 'source', 00897 'id' => 'wpUploadFileURL', 00898 'radio-id' => 'wpSourceTypeurl', 00899 'label-message' => 'sourceurl', 00900 'upload-type' => 'url', 00901 'radio' => &$radio, 00902 'help' => $this->msg( 'upload-maxfilesize', 00903 $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['url'] ) 00904 )->parse() . 00905 $this->msg( 'word-separator' )->escaped() . 00906 $this->msg( 'upload_source_url' )->escaped(), 00907 'checked' => $selectedSourceType == 'url', 00908 ); 00909 } 00910 wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) ); 00911 00912 $descriptor['Extensions'] = array( 00913 'type' => 'info', 00914 'section' => 'source', 00915 'default' => $this->getExtensionsMessage(), 00916 'raw' => true, 00917 ); 00918 00919 return $descriptor; 00920 } 00921 00927 protected function getExtensionsMessage() { 00928 # Print a list of allowed file extensions, if so configured. We ignore 00929 # MIME type here, it's incomprehensible to most people and too long. 00930 $config = $this->getConfig(); 00931 00932 if ( $config->get( 'CheckFileExtensions' ) ) { 00933 if ( $config->get( 'StrictFileExtensions' ) ) { 00934 # Everything not permitted is banned 00935 $extensionsList = 00936 '<div id="mw-upload-permitted">' . 00937 $this->msg( 00938 'upload-permitted', 00939 $this->getContext()->getLanguage()->commaList( 00940 array_unique( $config->get( 'FileExtensions' ) ) 00941 ) 00942 )->parseAsBlock() . 00943 "</div>\n"; 00944 } else { 00945 # We have to list both preferred and prohibited 00946 $extensionsList = 00947 '<div id="mw-upload-preferred">' . 00948 $this->msg( 00949 'upload-preferred', 00950 $this->getContext()->getLanguage()->commaList( 00951 array_unique( $config->get( 'FileExtensions' ) ) 00952 ) 00953 )->parseAsBlock() . 00954 "</div>\n" . 00955 '<div id="mw-upload-prohibited">' . 00956 $this->msg( 00957 'upload-prohibited', 00958 $this->getContext()->getLanguage()->commaList( 00959 array_unique( $config->get( 'FileBlacklist' ) ) 00960 ) 00961 )->parseAsBlock() . 00962 "</div>\n"; 00963 } 00964 } else { 00965 # Everything is permitted. 00966 $extensionsList = ''; 00967 } 00968 00969 return $extensionsList; 00970 } 00971 00978 protected function getDescriptionSection() { 00979 $config = $this->getConfig(); 00980 if ( $this->mSessionKey ) { 00981 $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash(); 00982 try { 00983 $file = $stash->getFile( $this->mSessionKey ); 00984 } catch ( MWException $e ) { 00985 $file = null; 00986 } 00987 if ( $file ) { 00988 global $wgContLang; 00989 00990 $mto = $file->transform( array( 'width' => 120 ) ); 00991 $this->addHeaderText( 00992 '<div class="thumb t' . $wgContLang->alignEnd() . '">' . 00993 Html::element( 'img', array( 00994 'src' => $mto->getUrl(), 00995 'class' => 'thumbimage', 00996 ) ) . '</div>', 'description' ); 00997 } 00998 } 00999 01000 $descriptor = array( 01001 'DestFile' => array( 01002 'type' => 'text', 01003 'section' => 'description', 01004 'id' => 'wpDestFile', 01005 'label-message' => 'destfilename', 01006 'size' => 60, 01007 'default' => $this->mDestFile, 01008 # @todo FIXME: Hack to work around poor handling of the 'default' option in HTMLForm 01009 'nodata' => strval( $this->mDestFile ) !== '', 01010 ), 01011 'UploadDescription' => array( 01012 'type' => 'textarea', 01013 'section' => 'description', 01014 'id' => 'wpUploadDescription', 01015 'label-message' => $this->mForReUpload 01016 ? 'filereuploadsummary' 01017 : 'fileuploadsummary', 01018 'default' => $this->mComment, 01019 'cols' => $this->getUser()->getIntOption( 'cols' ), 01020 'rows' => 8, 01021 ) 01022 ); 01023 if ( $this->mTextAfterSummary ) { 01024 $descriptor['UploadFormTextAfterSummary'] = array( 01025 'type' => 'info', 01026 'section' => 'description', 01027 'default' => $this->mTextAfterSummary, 01028 'raw' => true, 01029 ); 01030 } 01031 01032 $descriptor += array( 01033 'EditTools' => array( 01034 'type' => 'edittools', 01035 'section' => 'description', 01036 'message' => 'edittools-upload', 01037 ) 01038 ); 01039 01040 if ( $this->mForReUpload ) { 01041 $descriptor['DestFile']['readonly'] = true; 01042 } else { 01043 $descriptor['License'] = array( 01044 'type' => 'select', 01045 'class' => 'Licenses', 01046 'section' => 'description', 01047 'id' => 'wpLicense', 01048 'label-message' => 'license', 01049 ); 01050 } 01051 01052 if ( $config->get( 'UseCopyrightUpload' ) ) { 01053 $descriptor['UploadCopyStatus'] = array( 01054 'type' => 'text', 01055 'section' => 'description', 01056 'id' => 'wpUploadCopyStatus', 01057 'label-message' => 'filestatus', 01058 ); 01059 $descriptor['UploadSource'] = array( 01060 'type' => 'text', 01061 'section' => 'description', 01062 'id' => 'wpUploadSource', 01063 'label-message' => 'filesource', 01064 ); 01065 } 01066 01067 return $descriptor; 01068 } 01069 01076 protected function getOptionsSection() { 01077 $user = $this->getUser(); 01078 if ( $user->isLoggedIn() ) { 01079 $descriptor = array( 01080 'Watchthis' => array( 01081 'type' => 'check', 01082 'id' => 'wpWatchthis', 01083 'label-message' => 'watchthisupload', 01084 'section' => 'options', 01085 'default' => $this->mWatch, 01086 ) 01087 ); 01088 } 01089 if ( !$this->mHideIgnoreWarning ) { 01090 $descriptor['IgnoreWarning'] = array( 01091 'type' => 'check', 01092 'id' => 'wpIgnoreWarning', 01093 'label-message' => 'ignorewarnings', 01094 'section' => 'options', 01095 ); 01096 } 01097 01098 $descriptor['DestFileWarningAck'] = array( 01099 'type' => 'hidden', 01100 'id' => 'wpDestFileWarningAck', 01101 'default' => $this->mDestWarningAck ? '1' : '', 01102 ); 01103 01104 if ( $this->mForReUpload ) { 01105 $descriptor['ForReUpload'] = array( 01106 'type' => 'hidden', 01107 'id' => 'wpForReUpload', 01108 'default' => '1', 01109 ); 01110 } 01111 01112 return $descriptor; 01113 } 01114 01118 public function show() { 01119 $this->addUploadJS(); 01120 parent::show(); 01121 } 01122 01126 protected function addUploadJS() { 01127 $config = $this->getConfig(); 01128 01129 $useAjaxDestCheck = $config->get( 'UseAjax' ) && $config->get( 'AjaxUploadDestCheck' ); 01130 $useAjaxLicensePreview = $config->get( 'UseAjax' ) && 01131 $config->get( 'AjaxLicensePreview' ) && $config->get( 'EnableAPI' ); 01132 $this->mMaxUploadSize['*'] = UploadBase::getMaxUploadSize(); 01133 01134 $scriptVars = array( 01135 'wgAjaxUploadDestCheck' => $useAjaxDestCheck, 01136 'wgAjaxLicensePreview' => $useAjaxLicensePreview, 01137 'wgUploadAutoFill' => !$this->mForReUpload && 01138 // If we received mDestFile from the request, don't autofill 01139 // the wpDestFile textbox 01140 $this->mDestFile === '', 01141 'wgUploadSourceIds' => $this->mSourceIds, 01142 'wgStrictFileExtensions' => $config->get( 'StrictFileExtensions' ), 01143 'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ), 01144 'wgMaxUploadSize' => $this->mMaxUploadSize, 01145 ); 01146 01147 $out = $this->getOutput(); 01148 $out->addJsConfigVars( $scriptVars ); 01149 01150 $out->addModules( array( 01151 'mediawiki.action.edit', // For <charinsert> support 01152 'mediawiki.special.upload', // Extras for thumbnail and license preview. 01153 ) ); 01154 } 01155 01161 function trySubmit() { 01162 return false; 01163 } 01164 } 01165 01169 class UploadSourceField extends HTMLTextField { 01170 01175 function getLabelHtml( $cellAttributes = array() ) { 01176 $id = $this->mParams['id']; 01177 $label = Html::rawElement( 'label', array( 'for' => $id ), $this->mLabel ); 01178 01179 if ( !empty( $this->mParams['radio'] ) ) { 01180 if ( isset( $this->mParams['radio-id'] ) ) { 01181 $radioId = $this->mParams['radio-id']; 01182 } else { 01183 // Old way. For the benefit of extensions that do not define 01184 // the 'radio-id' key. 01185 $radioId = 'wpSourceType' . $this->mParams['upload-type']; 01186 } 01187 01188 $attribs = array( 01189 'name' => 'wpSourceType', 01190 'type' => 'radio', 01191 'id' => $radioId, 01192 'value' => $this->mParams['upload-type'], 01193 ); 01194 01195 if ( !empty( $this->mParams['checked'] ) ) { 01196 $attribs['checked'] = 'checked'; 01197 } 01198 01199 $label .= Html::element( 'input', $attribs ); 01200 } 01201 01202 return Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes, $label ); 01203 } 01204 01208 function getSize() { 01209 return isset( $this->mParams['size'] ) 01210 ? $this->mParams['size'] 01211 : 60; 01212 } 01213 }