MediaWiki  REL1_19
SpecialUpload.php
Go to the documentation of this file.
00001 <?php
00031 class SpecialUpload extends SpecialPage {
00037         public function __construct( $request = null ) {
00038                 parent::__construct( 'Upload', 'upload' );
00039         }
00040 
00042         public $mRequest;                       // The WebRequest or FauxRequest this form is supposed to handle
00043         public $mSourceType;
00044 
00048         public $mUpload;
00049 
00053         public $mLocalFile;
00054         public $mUploadClicked;
00055 
00057         public $mDesiredDestName;       // The requested target file name
00058         public $mComment;
00059         public $mLicense;
00060 
00062         public $mIgnoreWarning;
00063         public $mWatchThis;
00064         public $mCopyrightStatus;
00065         public $mCopyrightSource;
00066 
00068         public $mDestWarningAck;
00069         public $mForReUpload;           // The user followed an "overwrite this file" link
00070         public $mCancelUpload;          // The user clicked "Cancel and return to upload form" button
00071         public $mTokenOk;
00072         public $mUploadSuccessful = false;      // Subclasses can use this to determine whether a file was uploaded
00073 
00075         public $uploadFormTextTop;
00076         public $uploadFormTextAfterSummary;
00077 
00078         public $mWatchthis;
00079 
00083         protected function loadRequest() {
00084                 $this->mRequest = $request = $this->getRequest();
00085                 $this->mSourceType        = $request->getVal( 'wpSourceType', 'file' );
00086                 $this->mUpload            = UploadBase::createFromRequest( $request );
00087                 $this->mUploadClicked     = $request->wasPosted()
00088                         && ( $request->getCheck( 'wpUpload' )
00089                                 || $request->getCheck( 'wpUploadIgnoreWarning' ) );
00090 
00091                 // Guess the desired name from the filename if not provided
00092                 $this->mDesiredDestName   = $request->getText( 'wpDestFile' );
00093                 if( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) {
00094                         $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' );
00095                 }
00096                 $this->mComment           = $request->getText( 'wpUploadDescription' );
00097                 $this->mLicense           = $request->getText( 'wpLicense' );
00098 
00099 
00100                 $this->mDestWarningAck    = $request->getText( 'wpDestFileWarningAck' );
00101                 $this->mIgnoreWarning     = $request->getCheck( 'wpIgnoreWarning' )
00102                         || $request->getCheck( 'wpUploadIgnoreWarning' );
00103                 $this->mWatchthis         = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isLoggedIn();
00104                 $this->mCopyrightStatus   = $request->getText( 'wpUploadCopyStatus' );
00105                 $this->mCopyrightSource   = $request->getText( 'wpUploadSource' );
00106 
00107 
00108                 $this->mForReUpload       = $request->getBool( 'wpForReUpload' ); // updating a file
00109                 $this->mCancelUpload      = $request->getCheck( 'wpCancelUpload' )
00110                                                                  || $request->getCheck( 'wpReUpload' ); // b/w compat
00111 
00112                 // If it was posted check for the token (no remote POST'ing with user credentials)
00113                 $token = $request->getVal( 'wpEditToken' );
00114                 $this->mTokenOk = $this->getUser()->matchEditToken( $token );
00115 
00116                 $this->uploadFormTextTop = '';
00117                 $this->uploadFormTextAfterSummary = '';
00118         }
00119 
00128         public function userCanExecute( User $user ) {
00129                 return UploadBase::isEnabled() && parent::userCanExecute( $user );
00130         }
00131 
00135         public function execute( $par ) {
00136                 $this->setHeaders();
00137                 $this->outputHeader();
00138 
00139                 # Check uploading enabled
00140                 if( !UploadBase::isEnabled() ) {
00141                         throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' );
00142                 }
00143 
00144                 # Check permissions
00145                 $user = $this->getUser();
00146                 $permissionRequired = UploadBase::isAllowed( $user );
00147                 if( $permissionRequired !== true ) {
00148                         throw new PermissionsError( $permissionRequired );
00149                 }
00150 
00151                 # Check blocks
00152                 if( $user->isBlocked() ) {
00153                         throw new UserBlockedError( $user->mBlock );
00154                 }
00155 
00156                 # Check whether we actually want to allow changing stuff
00157                 $this->checkReadOnly();
00158 
00159                 $this->loadRequest();
00160 
00161                 # Unsave the temporary file in case this was a cancelled upload
00162                 if ( $this->mCancelUpload ) {
00163                         if ( !$this->unsaveUploadedFile() ) {
00164                                 # Something went wrong, so unsaveUploadedFile showed a warning
00165                                 return;
00166                         }
00167                 }
00168 
00169                 # Process upload or show a form
00170                 if (
00171                         $this->mTokenOk && !$this->mCancelUpload &&
00172                         ( $this->mUpload && $this->mUploadClicked )
00173                 ) {
00174                         $this->processUpload();
00175                 } else {
00176                         # Backwards compatibility hook
00177                         if( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) {
00178                                 wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
00179                                 return;
00180                         }
00181                         $this->showUploadForm( $this->getUploadForm() );
00182                 }
00183 
00184                 # Cleanup
00185                 if ( $this->mUpload ) {
00186                         $this->mUpload->cleanupTempFile();
00187                 }
00188         }
00189 
00195         protected function showUploadForm( $form ) {
00196                 # Add links if file was previously deleted
00197                 if ( $this->mDesiredDestName ) {
00198                         $this->showViewDeletedLinks();
00199                 }
00200 
00201                 if ( $form instanceof HTMLForm ) {
00202                         $form->show();
00203                 } else {
00204                         $this->getOutput()->addHTML( $form );
00205                 }
00206 
00207         }
00208 
00217         protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) {
00218                 # Initialize form
00219                 $form = new UploadForm( array(
00220                         'watch' => $this->getWatchCheck(),
00221                         'forreupload' => $this->mForReUpload,
00222                         'sessionkey' => $sessionKey,
00223                         'hideignorewarning' => $hideIgnoreWarning,
00224                         'destwarningack' => (bool)$this->mDestWarningAck,
00225 
00226                         'description' => $this->mComment,
00227                         'texttop' => $this->uploadFormTextTop,
00228                         'textaftersummary' => $this->uploadFormTextAfterSummary,
00229                         'destfile' => $this->mDesiredDestName,
00230                 ), $this->getContext() );
00231                 $form->setTitle( $this->getTitle() );
00232 
00233                 # Check the token, but only if necessary
00234                 if(
00235                         !$this->mTokenOk && !$this->mCancelUpload &&
00236                         ( $this->mUpload && $this->mUploadClicked )
00237                 ) {
00238                         $form->addPreText( wfMsgExt( 'session_fail_preview', 'parseinline' ) );
00239                 }
00240 
00241                 # Give a notice if the user is uploading a file that has been deleted or moved
00242                 # Note that this is independent from the message 'filewasdeleted' that requires JS
00243                 $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
00244                 $delNotice = ''; // empty by default
00245                 if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) {
00246                         LogEventsList::showLogExtract( $delNotice, array( 'delete', 'move' ),
00247                                 $desiredTitleObj,
00248                                 '', array( 'lim' => 10,
00249                                            'conds' => array( "log_action != 'revision'" ),
00250                                            'showIfEmpty' => false,
00251                                            'msgKey' => array( 'upload-recreate-warning' ) )
00252                         );
00253                 }
00254                 $form->addPreText( $delNotice );
00255 
00256                 # Add text to form
00257                 $form->addPreText( '<div id="uploadtext">' .
00258                         wfMsgExt( 'uploadtext', 'parse', array( $this->mDesiredDestName ) ) .
00259                         '</div>' );
00260                 # Add upload error message
00261                 $form->addPreText( $message );
00262 
00263                 # Add footer to form
00264                 $uploadFooter = wfMessage( 'uploadfooter' );
00265                 if ( !$uploadFooter->isDisabled() ) {
00266                         $form->addPostText( '<div id="mw-upload-footer-message">'
00267                                 . $this->getOutput()->parse( $uploadFooter->plain() ) . "</div>\n" );
00268                 }
00269 
00270                 return $form;
00271         }
00272 
00276         protected function showViewDeletedLinks() {
00277                 $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
00278                 $user = $this->getUser();
00279                 // Show a subtitle link to deleted revisions (to sysops et al only)
00280                 if( $title instanceof Title ) {
00281                         $count = $title->isDeleted();
00282                         if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) {
00283                                 $link = wfMsgExt(
00284                                         $user->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
00285                                         array( 'parse', 'replaceafter' ),
00286                                         Linker::linkKnown(
00287                                                 SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
00288                                                 wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
00289                                         )
00290                                 );
00291                                 $this->getOutput()->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
00292                         }
00293                 }
00294         }
00295 
00307         protected function showRecoverableUploadError( $message ) {
00308                 $sessionKey = $this->mUpload->stashSession();
00309                 $message = '<h2>' . wfMsgHtml( 'uploaderror' ) . "</h2>\n" .
00310                         '<div class="error">' . $message . "</div>\n";
00311 
00312                 $form = $this->getUploadForm( $message, $sessionKey );
00313                 $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
00314                 $this->showUploadForm( $form );
00315         }
00324         protected function showUploadWarning( $warnings ) {
00325                 # If there are no warnings, or warnings we can ignore, return early.
00326                 # mDestWarningAck is set when some javascript has shown the warning
00327                 # to the user. mForReUpload is set when the user clicks the "upload a
00328                 # new version" link.
00329                 if ( !$warnings || ( count( $warnings ) == 1 &&
00330                         isset( $warnings['exists'] ) &&
00331                         ( $this->mDestWarningAck || $this->mForReUpload ) ) )
00332                 {
00333                         return false;
00334                 }
00335 
00336                 $sessionKey = $this->mUpload->stashSession();
00337 
00338                 $warningHtml = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n"
00339                         . '<ul class="warning">';
00340                 foreach( $warnings as $warning => $args ) {
00341                         if( $warning == 'exists' ) {
00342                                 $msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n";
00343                         } elseif( $warning == 'duplicate' ) {
00344                                 $msg = self::getDupeWarning( $args );
00345                         } elseif( $warning == 'duplicate-archive' ) {
00346                                 $msg = "\t<li>" . wfMsgExt( 'file-deleted-duplicate', 'parseinline',
00347                                                 array( Title::makeTitle( NS_FILE, $args )->getPrefixedText() ) )
00348                                         . "</li>\n";
00349                         } else {
00350                                 if ( $args === true ) {
00351                                         $args = array();
00352                                 } elseif ( !is_array( $args ) ) {
00353                                         $args = array( $args );
00354                                 }
00355                                 $msg = "\t<li>" . wfMsgExt( $warning, 'parseinline', $args ) . "</li>\n";
00356                         }
00357                         $warningHtml .= $msg;
00358                 }
00359                 $warningHtml .= "</ul>\n";
00360                 $warningHtml .= wfMsgExt( 'uploadwarning-text', 'parse' );
00361 
00362                 $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
00363                 $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
00364                 $form->addButton( 'wpUploadIgnoreWarning', wfMsg( 'ignorewarning' ) );
00365                 $form->addButton( 'wpCancelUpload', wfMsg( 'reuploaddesc' ) );
00366 
00367                 $this->showUploadForm( $form );
00368 
00369                 # Indicate that we showed a form
00370                 return true;
00371         }
00372 
00378         protected function showUploadError( $message ) {
00379                 $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
00380                         '<div class="error">' . $message . "</div>\n";
00381                 $this->showUploadForm( $this->getUploadForm( $message ) );
00382         }
00383 
00388         protected function processUpload() {
00389                 // Fetch the file if required
00390                 $status = $this->mUpload->fetchFile();
00391                 if( !$status->isOK() ) {
00392                         $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) );
00393                         return;
00394                 }
00395 
00396                 if( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
00397                         wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
00398                         // This code path is deprecated. If you want to break upload processing
00399                         // do so by hooking into the appropriate hooks in UploadBase::verifyUpload
00400                         // and UploadBase::verifyFile.
00401                         // If you use this hook to break uploading, the user will be returned
00402                         // an empty form with no error message whatsoever.
00403                         return;
00404                 }
00405 
00406                 // Upload verification
00407                 $details = $this->mUpload->verifyUpload();
00408                 if ( $details['status'] != UploadBase::OK ) {
00409                         $this->processVerificationError( $details );
00410                         return;
00411                 }
00412 
00413                 // Verify permissions for this title
00414                 $permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() );
00415                 if( $permErrors !== true ) {
00416                         $code = array_shift( $permErrors[0] );
00417                         $this->showRecoverableUploadError( wfMsgExt( $code,
00418                                         'parseinline', $permErrors[0] ) );
00419                         return;
00420                 }
00421 
00422                 $this->mLocalFile = $this->mUpload->getLocalFile();
00423 
00424                 // Check warnings if necessary
00425                 if( !$this->mIgnoreWarning ) {
00426                         $warnings = $this->mUpload->checkWarnings();
00427                         if( $this->showUploadWarning( $warnings ) ) {
00428                                 return;
00429                         }
00430                 }
00431 
00432                 // Get the page text if this is not a reupload
00433                 if( !$this->mForReUpload ) {
00434                         $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
00435                                 $this->mCopyrightStatus, $this->mCopyrightSource );
00436                 } else {
00437                         $pageText = false;
00438                 }
00439                 $status = $this->mUpload->performUpload( $this->mComment, $pageText, $this->mWatchthis, $this->getUser() );
00440                 if ( !$status->isGood() ) {
00441                         $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) );
00442                         return;
00443                 }
00444 
00445                 // Success, redirect to description page
00446                 $this->mUploadSuccessful = true;
00447                 wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
00448                 $this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
00449         }
00450 
00459         public static function getInitialPageText( $comment = '', $license = '', $copyStatus = '', $source = '' ) {
00460                 global $wgUseCopyrightUpload, $wgForceUIMsgAsContentMsg;
00461                 $wgForceUIMsgAsContentMsg = (array) $wgForceUIMsgAsContentMsg;
00462 
00463                 $msg = array();
00464                 /* These messages are transcluded into the actual text of the description page.
00465                  * Thus, forcing them as content messages makes the upload to produce an int: template
00466                  * instead of hardcoding it there in the uploader language.
00467                  */
00468                 foreach( array( 'license-header', 'filedesc', 'filestatus', 'filesource' ) as $msgName ) {
00469                         if ( in_array( $msgName, $wgForceUIMsgAsContentMsg ) ) {
00470                                 $msg[$msgName] = "{{int:$msgName}}";
00471                         } else {
00472                                 $msg[$msgName] = wfMsgForContent( $msgName );
00473                         }
00474                 }
00475 
00476                 if ( $wgUseCopyrightUpload ) {
00477                         $licensetxt = '';
00478                         if ( $license != '' ) {
00479                                 $licensetxt = '== ' . $msg[ 'license-header' ] . " ==\n" . '{{' . $license . '}}' . "\n";
00480                         }
00481                         $pageText = '== ' . $msg[ 'filedesc' ] . " ==\n" . $comment . "\n" .
00482                                 '== ' . $msg[ 'filestatus' ] . " ==\n" . $copyStatus . "\n" .
00483                                 "$licensetxt" .
00484                                 '== ' . $msg[ 'filesource' ] . " ==\n" . $source;
00485                 } else {
00486                         if ( $license != '' ) {
00487                                 $filedesc = $comment == '' ? '' : '== ' . $msg[ 'filedesc' ] . " ==\n" . $comment . "\n";
00488                                         $pageText = $filedesc .
00489                                         '== ' . $msg[ 'license-header' ] . " ==\n" . '{{' . $license . '}}' . "\n";
00490                         } else {
00491                                 $pageText = $comment;
00492                         }
00493                 }
00494                 return $pageText;
00495         }
00496 
00509         protected function getWatchCheck() {
00510                 if( $this->getUser()->getOption( 'watchdefault' ) ) {
00511                         // Watch all edits!
00512                         return true;
00513                 }
00514 
00515                 $local = wfLocalFile( $this->mDesiredDestName );
00516                 if( $local && $local->exists() ) {
00517                         // We're uploading a new version of an existing file.
00518                         // No creation, so don't watch it if we're not already.
00519                         return $local->getTitle()->userIsWatching();
00520                 } else {
00521                         // New page should get watched if that's our option.
00522                         return $this->getUser()->getOption( 'watchcreations' );
00523                 }
00524         }
00525 
00526 
00532         protected function processVerificationError( $details ) {
00533                 global $wgFileExtensions;
00534 
00535                 switch( $details['status'] ) {
00536 
00538                         case UploadBase::MIN_LENGTH_PARTNAME:
00539                                 $this->showRecoverableUploadError( wfMsgHtml( 'minlength1' ) );
00540                                 break;
00541                         case UploadBase::ILLEGAL_FILENAME:
00542                                 $this->showRecoverableUploadError( wfMsgExt( 'illegalfilename',
00543                                         'parseinline', $details['filtered'] ) );
00544                                 break;
00545                         case UploadBase::FILENAME_TOO_LONG:
00546                                 $this->showRecoverableUploadError( wfMsgHtml( 'filename-toolong' ) );
00547                                 break;
00548                         case UploadBase::FILETYPE_MISSING:
00549                                 $this->showRecoverableUploadError( wfMsgExt( 'filetype-missing',
00550                                         'parseinline' ) );
00551                                 break;
00552                         case UploadBase::WINDOWS_NONASCII_FILENAME:
00553                                 $this->showRecoverableUploadError( wfMsgExt( 'windows-nonascii-filename',
00554                                         'parseinline' ) );
00555                                 break;
00556 
00558                         case UploadBase::EMPTY_FILE:
00559                                 $this->showUploadError( wfMsgHtml( 'emptyfile' ) );
00560                                 break;
00561                         case UploadBase::FILE_TOO_LARGE:
00562                                 $this->showUploadError( wfMsgHtml( 'largefileserver' ) );
00563                                 break;
00564                         case UploadBase::FILETYPE_BADTYPE:
00565                                 $msg = wfMessage( 'filetype-banned-type' );
00566                                 if ( isset( $details['blacklistedExt'] ) ) {
00567                                         $msg->params( $this->getLanguage()->commaList( $details['blacklistedExt'] ) );
00568                                 } else {
00569                                         $msg->params( $details['finalExt'] );
00570                                 }
00571                                 $msg->params( $this->getLanguage()->commaList( $wgFileExtensions ),
00572                                         count( $wgFileExtensions ) );
00573 
00574                                 // Add PLURAL support for the first parameter. This results
00575                                 // in a bit unlogical parameter sequence, but does not break
00576                                 // old translations
00577                                 if ( isset( $details['blacklistedExt'] ) ) {
00578                                         $msg->params( count( $details['blacklistedExt'] ) );
00579                                 } else {
00580                                         $msg->params( 1 );
00581                                 }
00582 
00583                                 $this->showUploadError( $msg->parse() );
00584                                 break;
00585                         case UploadBase::VERIFICATION_ERROR:
00586                                 unset( $details['status'] );
00587                                 $code = array_shift( $details['details'] );
00588                                 $this->showUploadError( wfMsgExt( $code, 'parseinline', $details['details'] ) );
00589                                 break;
00590                         case UploadBase::HOOK_ABORTED:
00591                                 if ( is_array( $details['error'] ) ) { # allow hooks to return error details in an array
00592                                         $args = $details['error'];
00593                                         $error = array_shift( $args );
00594                                 } else {
00595                                         $error = $details['error'];
00596                                         $args = null;
00597                                 }
00598 
00599                                 $this->showUploadError( wfMsgExt( $error, 'parseinline', $args ) );
00600                                 break;
00601                         default:
00602                                 throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
00603                 }
00604         }
00605 
00611         protected function unsaveUploadedFile() {
00612                 if ( !( $this->mUpload instanceof UploadFromStash ) ) {
00613                         return true;
00614                 }
00615                 $success = $this->mUpload->unsaveUploadedFile();
00616                 if ( !$success ) {
00617                         $this->getOutput()->showFileDeleteError( $this->mUpload->getTempPath() );
00618                         return false;
00619                 } else {
00620                         return true;
00621                 }
00622         }
00623 
00624         /*** Functions for formatting warnings ***/
00625 
00633         public static function getExistsWarning( $exists ) {
00634                 if ( !$exists ) {
00635                         return '';
00636                 }
00637 
00638                 $file = $exists['file'];
00639                 $filename = $file->getTitle()->getPrefixedText();
00640                 $warning = '';
00641 
00642                 if( $exists['warning'] == 'exists' ) {
00643                         // Exact match
00644                         $warning = wfMsgExt( 'fileexists', 'parseinline', $filename );
00645                 } elseif( $exists['warning'] == 'page-exists' ) {
00646                         // Page exists but file does not
00647                         $warning = wfMsgExt( 'filepageexists', 'parseinline', $filename );
00648                 } elseif ( $exists['warning'] == 'exists-normalized' ) {
00649                         $warning = wfMsgExt( 'fileexists-extension', 'parseinline', $filename,
00650                                 $exists['normalizedFile']->getTitle()->getPrefixedText() );
00651                 } elseif ( $exists['warning'] == 'thumb' ) {
00652                         // Swapped argument order compared with other messages for backwards compatibility
00653                         $warning = wfMsgExt( 'fileexists-thumbnail-yes', 'parseinline',
00654                                 $exists['thumbFile']->getTitle()->getPrefixedText(), $filename );
00655                 } elseif ( $exists['warning'] == 'thumb-name' ) {
00656                         // Image w/o '180px-' does not exists, but we do not like these filenames
00657                         $name = $file->getName();
00658                         $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
00659                         $warning = wfMsgExt( 'file-thumbnail-no', 'parseinline', $badPart );
00660                 } elseif ( $exists['warning'] == 'bad-prefix' ) {
00661                         $warning = wfMsgExt( 'filename-bad-prefix', 'parseinline', $exists['prefix'] );
00662                 } elseif ( $exists['warning'] == 'was-deleted' ) {
00663                         # If the file existed before and was deleted, warn the user of this
00664                         $ltitle = SpecialPage::getTitleFor( 'Log' );
00665                         $llink = Linker::linkKnown(
00666                                 $ltitle,
00667                                 wfMsgHtml( 'deletionlog' ),
00668                                 array(),
00669                                 array(
00670                                         'type' => 'delete',
00671                                         'page' => $filename
00672                                 )
00673                         );
00674                         $warning = wfMsgExt( 'filewasdeleted', array( 'parse', 'replaceafter' ), $llink );
00675                 }
00676 
00677                 return $warning;
00678         }
00679 
00686         public static function ajaxGetExistsWarning( $filename ) {
00687                 $file = wfFindFile( $filename );
00688                 if( !$file ) {
00689                         // Force local file so we have an object to do further checks against
00690                         // if there isn't an exact match...
00691                         $file = wfLocalFile( $filename );
00692                 }
00693                 $s = '&#160;';
00694                 if ( $file ) {
00695                         $exists = UploadBase::getExistsWarning( $file );
00696                         $warning = self::getExistsWarning( $exists );
00697                         if ( $warning !== '' ) {
00698                                 $s = "<div>$warning</div>";
00699                         }
00700                 }
00701                 return $s;
00702         }
00703 
00709         public static function getDupeWarning( $dupes ) {
00710                 global $wgOut;
00711                 if( $dupes ) {
00712                         $msg = '<gallery>';
00713                         foreach( $dupes as $file ) {
00714                                 $title = $file->getTitle();
00715                                 $msg .= $title->getPrefixedText() .
00716                                         '|' . $title->getText() . "\n";
00717                         }
00718                         $msg .= '</gallery>';
00719                         return '<li>' .
00720                                 wfMsgExt( 'file-exists-duplicate', array( 'parse' ), count( $dupes ) ) .
00721                                 $wgOut->parse( $msg ) .
00722                                 "</li>\n";
00723                 } else {
00724                         return '';
00725                 }
00726         }
00727 
00728 }
00729 
00733 class UploadForm extends HTMLForm {
00734         protected $mWatch;
00735         protected $mForReUpload;
00736         protected $mSessionKey;
00737         protected $mHideIgnoreWarning;
00738         protected $mDestWarningAck;
00739         protected $mDestFile;
00740 
00741         protected $mComment;
00742         protected $mTextTop;
00743         protected $mTextAfterSummary;
00744 
00745         protected $mSourceIds;
00746 
00747         protected $mMaxFileSize = array();
00748 
00749         protected $mMaxUploadSize = array();
00750 
00751         public function __construct( array $options = array(), IContextSource $context = null ) {
00752                 $this->mWatch = !empty( $options['watch'] );
00753                 $this->mForReUpload = !empty( $options['forreupload'] );
00754                 $this->mSessionKey = isset( $options['sessionkey'] )
00755                                 ? $options['sessionkey'] : '';
00756                 $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] );
00757                 $this->mDestWarningAck = !empty( $options['destwarningack'] );
00758                 $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : '';
00759 
00760                 $this->mComment = isset( $options['description'] ) ?
00761                         $options['description'] : '';
00762 
00763                 $this->mTextTop = isset( $options['texttop'] )
00764                         ? $options['texttop'] : '';
00765 
00766                 $this->mTextAfterSummary = isset( $options['textaftersummary'] )
00767                         ? $options['textaftersummary'] : '';
00768 
00769                 $sourceDescriptor = $this->getSourceSection();
00770                 $descriptor = $sourceDescriptor
00771                         + $this->getDescriptionSection()
00772                         + $this->getOptionsSection();
00773 
00774                 wfRunHooks( 'UploadFormInitDescriptor', array( &$descriptor ) );
00775                 parent::__construct( $descriptor, $context, 'upload' );
00776 
00777                 # Set some form properties
00778                 $this->setSubmitText( wfMsg( 'uploadbtn' ) );
00779                 $this->setSubmitName( 'wpUpload' );
00780                 # Used message keys: 'accesskey-upload', 'tooltip-upload'
00781                 $this->setSubmitTooltip( 'upload' );
00782                 $this->setId( 'mw-upload-form' );
00783 
00784                 # Build a list of IDs for javascript insertion
00785                 $this->mSourceIds = array();
00786                 foreach ( $sourceDescriptor as $field ) {
00787                         if ( !empty( $field['id'] ) ) {
00788                                 $this->mSourceIds[] = $field['id'];
00789                         }
00790                 }
00791 
00792         }
00793 
00800         protected function getSourceSection() {
00801                 if ( $this->mSessionKey ) {
00802                         return array(
00803                                 'SessionKey' => array(
00804                                         'type' => 'hidden',
00805                                         'default' => $this->mSessionKey,
00806                                 ),
00807                                 'SourceType' => array(
00808                                         'type' => 'hidden',
00809                                         'default' => 'Stash',
00810                                 ),
00811                         );
00812                 }
00813 
00814                 $canUploadByUrl = UploadFromUrl::isEnabled() && UploadFromUrl::isAllowed( $this->getUser() );
00815                 $radio = $canUploadByUrl;
00816                 $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) );
00817 
00818                 $descriptor = array();
00819                 if ( $this->mTextTop ) {
00820                         $descriptor['UploadFormTextTop'] = array(
00821                                 'type' => 'info',
00822                                 'section' => 'source',
00823                                 'default' => $this->mTextTop,
00824                                 'raw' => true,
00825                         );
00826                 }
00827 
00828                 $this->mMaxUploadSize['file'] = UploadBase::getMaxUploadSize( 'file' );
00829                 # Limit to upload_max_filesize unless we are running under HipHop and
00830                 # that setting doesn't exist
00831                 if ( !wfIsHipHop() ) {
00832                         $this->mMaxUploadSize['file'] = min( $this->mMaxUploadSize['file'],
00833                                 wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ) );
00834                 }
00835 
00836                 $descriptor['UploadFile'] = array(
00837                         'class' => 'UploadSourceField',
00838                         'section' => 'source',
00839                         'type' => 'file',
00840                         'id' => 'wpUploadFile',
00841                         'label-message' => 'sourcefilename',
00842                         'upload-type' => 'File',
00843                         'radio' => &$radio,
00844                         'help' => wfMsgExt( 'upload-maxfilesize',
00845                                         array( 'parseinline', 'escapenoentities' ),
00846                                         $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['file'] )
00847                                 ) . ' ' . wfMsgHtml( 'upload_source_file' ),
00848                         'checked' => $selectedSourceType == 'file',
00849                 );
00850                 if ( $canUploadByUrl ) {
00851                         $this->mMaxUploadSize['url'] = UploadBase::getMaxUploadSize( 'url' );
00852                         $descriptor['UploadFileURL'] = array(
00853                                 'class' => 'UploadSourceField',
00854                                 'section' => 'source',
00855                                 'id' => 'wpUploadFileURL',
00856                                 'label-message' => 'sourceurl',
00857                                 'upload-type' => 'url',
00858                                 'radio' => &$radio,
00859                                 'help' => wfMsgExt( 'upload-maxfilesize',
00860                                                 array( 'parseinline', 'escapenoentities' ),
00861                                                 $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['url'] )
00862                                         ) . ' ' . wfMsgHtml( 'upload_source_url' ),
00863                                 'checked' => $selectedSourceType == 'url',
00864                         );
00865                 }
00866                 wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
00867 
00868                 $descriptor['Extensions'] = array(
00869                         'type' => 'info',
00870                         'section' => 'source',
00871                         'default' => $this->getExtensionsMessage(),
00872                         'raw' => true,
00873                 );
00874                 return $descriptor;
00875         }
00876 
00882         protected function getExtensionsMessage() {
00883                 # Print a list of allowed file extensions, if so configured.  We ignore
00884                 # MIME type here, it's incomprehensible to most people and too long.
00885                 global $wgCheckFileExtensions, $wgStrictFileExtensions,
00886                 $wgFileExtensions, $wgFileBlacklist;
00887 
00888                 if( $wgCheckFileExtensions ) {
00889                         if( $wgStrictFileExtensions ) {
00890                                 # Everything not permitted is banned
00891                                 $extensionsList =
00892                                         '<div id="mw-upload-permitted">' .
00893                                         wfMsgExt( 'upload-permitted', 'parse', $this->getContext()->getLanguage()->commaList( $wgFileExtensions ) ) .
00894                                         "</div>\n";
00895                         } else {
00896                                 # We have to list both preferred and prohibited
00897                                 $extensionsList =
00898                                         '<div id="mw-upload-preferred">' .
00899                                         wfMsgExt( 'upload-preferred', 'parse', $this->getContext()->getLanguage()->commaList( $wgFileExtensions ) ) .
00900                                         "</div>\n" .
00901                                         '<div id="mw-upload-prohibited">' .
00902                                         wfMsgExt( 'upload-prohibited', 'parse', $this->getContext()->getLanguage()->commaList( $wgFileBlacklist ) ) .
00903                                         "</div>\n";
00904                         }
00905                 } else {
00906                         # Everything is permitted.
00907                         $extensionsList = '';
00908                 }
00909                 return $extensionsList;
00910         }
00911 
00918         protected function getDescriptionSection() {
00919                 if ( $this->mSessionKey ) {
00920                         $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash();
00921                         try {
00922                                 $file = $stash->getFile( $this->mSessionKey );
00923                         } catch ( MWException $e ) {
00924                                 $file = null;
00925                         }
00926                         if ( $file ) {
00927                                 global $wgContLang;
00928 
00929                                 $mto = $file->transform( array( 'width' => 120 ) );
00930                                 $this->addHeaderText(
00931                                         '<div class="thumb t' . $wgContLang->alignEnd() . '">' .
00932                                         Html::element( 'img', array(
00933                                                 'src' => $mto->getUrl(),
00934                                                 'class' => 'thumbimage',
00935                                         ) ) . '</div>', 'description' );
00936                         }
00937                 }
00938 
00939                 $descriptor = array(
00940                         'DestFile' => array(
00941                                 'type' => 'text',
00942                                 'section' => 'description',
00943                                 'id' => 'wpDestFile',
00944                                 'label-message' => 'destfilename',
00945                                 'size' => 60,
00946                                 'default' => $this->mDestFile,
00947                                 # @todo FIXME: Hack to work around poor handling of the 'default' option in HTMLForm
00948                                 'nodata' => strval( $this->mDestFile ) !== '',
00949                         ),
00950                         'UploadDescription' => array(
00951                                 'type' => 'textarea',
00952                                 'section' => 'description',
00953                                 'id' => 'wpUploadDescription',
00954                                 'label-message' => $this->mForReUpload
00955                                         ? 'filereuploadsummary'
00956                                         : 'fileuploadsummary',
00957                                 'default' => $this->mComment,
00958                                 'cols' => intval( $this->getUser()->getOption( 'cols' ) ),
00959                                 'rows' => 8,
00960                         )
00961                 );
00962                 if ( $this->mTextAfterSummary ) {
00963                         $descriptor['UploadFormTextAfterSummary'] = array(
00964                                 'type' => 'info',
00965                                 'section' => 'description',
00966                                 'default' => $this->mTextAfterSummary,
00967                                 'raw' => true,
00968                         );
00969                 }
00970 
00971                 $descriptor += array(
00972                         'EditTools' => array(
00973                                 'type' => 'edittools',
00974                                 'section' => 'description',
00975                                 'message' => 'edittools-upload',
00976                         )
00977                 );
00978 
00979                 if ( $this->mForReUpload ) {
00980                         $descriptor['DestFile']['readonly'] = true;
00981                 } else {
00982                         $descriptor['License'] = array(
00983                                 'type' => 'select',
00984                                 'class' => 'Licenses',
00985                                 'section' => 'description',
00986                                 'id' => 'wpLicense',
00987                                 'label-message' => 'license',
00988                         );
00989                 }
00990 
00991                 global $wgUseCopyrightUpload;
00992                 if ( $wgUseCopyrightUpload ) {
00993                         $descriptor['UploadCopyStatus'] = array(
00994                                 'type' => 'text',
00995                                 'section' => 'description',
00996                                 'id' => 'wpUploadCopyStatus',
00997                                 'label-message' => 'filestatus',
00998                         );
00999                         $descriptor['UploadSource'] = array(
01000                                 'type' => 'text',
01001                                 'section' => 'description',
01002                                 'id' => 'wpUploadSource',
01003                                 'label-message' => 'filesource',
01004                         );
01005                 }
01006 
01007                 return $descriptor;
01008         }
01009 
01016         protected function getOptionsSection() {
01017                 $user = $this->getUser();
01018                 if ( $user->isLoggedIn() ) {
01019                         $descriptor = array(
01020                                 'Watchthis' => array(
01021                                         'type' => 'check',
01022                                         'id' => 'wpWatchthis',
01023                                         'label-message' => 'watchthisupload',
01024                                         'section' => 'options',
01025                                         'default' => $user->getOption( 'watchcreations' ),
01026                                 )
01027                         );
01028                 }
01029                 if ( !$this->mHideIgnoreWarning ) {
01030                         $descriptor['IgnoreWarning'] = array(
01031                                 'type' => 'check',
01032                                 'id' => 'wpIgnoreWarning',
01033                                 'label-message' => 'ignorewarnings',
01034                                 'section' => 'options',
01035                         );
01036                 }
01037 
01038                 $descriptor['DestFileWarningAck'] = array(
01039                         'type' => 'hidden',
01040                         'id' => 'wpDestFileWarningAck',
01041                         'default' => $this->mDestWarningAck ? '1' : '',
01042                 );
01043 
01044                 if ( $this->mForReUpload ) {
01045                         $descriptor['ForReUpload'] = array(
01046                                 'type' => 'hidden',
01047                                 'id' => 'wpForReUpload',
01048                                 'default' => '1',
01049                         );
01050                 }
01051 
01052                 return $descriptor;
01053         }
01054 
01058         public function show() {
01059                 $this->addUploadJS();
01060                 parent::show();
01061         }
01062 
01066         protected function addUploadJS() {
01067                 global $wgUseAjax, $wgAjaxUploadDestCheck, $wgAjaxLicensePreview, $wgEnableAPI, $wgStrictFileExtensions;
01068 
01069                 $useAjaxDestCheck = $wgUseAjax && $wgAjaxUploadDestCheck;
01070                 $useAjaxLicensePreview = $wgUseAjax && $wgAjaxLicensePreview && $wgEnableAPI;
01071                 $this->mMaxUploadSize['*'] = UploadBase::getMaxUploadSize();
01072 
01073                 $scriptVars = array(
01074                         'wgAjaxUploadDestCheck' => $useAjaxDestCheck,
01075                         'wgAjaxLicensePreview' => $useAjaxLicensePreview,
01076                         'wgUploadAutoFill' => !$this->mForReUpload &&
01077                                 // If we received mDestFile from the request, don't autofill
01078                                 // the wpDestFile textbox
01079                                 $this->mDestFile === '',
01080                         'wgUploadSourceIds' => $this->mSourceIds,
01081                         'wgStrictFileExtensions' => $wgStrictFileExtensions,
01082                         'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ),
01083                         'wgMaxUploadSize' => $this->mMaxUploadSize,
01084                 );
01085 
01086                 $out = $this->getOutput();
01087                 $out->addJsConfigVars( $scriptVars );
01088 
01089 
01090                 $out->addModules( array(
01091                         'mediawiki.action.edit', // For <charinsert> support
01092                         'mediawiki.legacy.upload', // Old form stuff...
01093                         'mediawiki.special.upload', // Newer extras for thumbnail preview.
01094                 ) );
01095         }
01096 
01102         function trySubmit() {
01103                 return false;
01104         }
01105 
01106 }
01107 
01111 class UploadSourceField extends HTMLTextField {
01112 
01117         function getLabelHtml( $cellAttributes = array() ) {
01118                 $id = "wpSourceType{$this->mParams['upload-type']}";
01119                 $label = Html::rawElement( 'label', array( 'for' => $id ), $this->mLabel );
01120 
01121                 if ( !empty( $this->mParams['radio'] ) ) {
01122                         $attribs = array(
01123                                 'name' => 'wpSourceType',
01124                                 'type' => 'radio',
01125                                 'id' => $id,
01126                                 'value' => $this->mParams['upload-type'],
01127                         );
01128                         if ( !empty( $this->mParams['checked'] ) ) {
01129                                 $attribs['checked'] = 'checked';
01130                         }
01131                         $label .= Html::element( 'input', $attribs );
01132                 }
01133 
01134                 return Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes, $label );
01135         }
01136 
01140         function getSize() {
01141                 return isset( $this->mParams['size'] )
01142                         ? $this->mParams['size']
01143                         : 60;
01144         }
01145 }
01146