r107644 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r107643‎ | r107644 | r107645 >
Date:19:01, 30 December 2011
Author:yaron
Status:ok
Tags:
Comment:
SF_UploadWindow2.php renamed to SF_UploadWindow.php, now that old class (which provided compatibility for MW < 1.16) is no longer needed
Modified paths:
  • /trunk/extensions/SemanticForms/specials/SF_UploadWindow.php (added) (history)
  • /trunk/extensions/SemanticForms/specials/SF_UploadWindow2.php (deleted) (history)

Diff [purge]

Index: trunk/extensions/SemanticForms/specials/SF_UploadWindow2.php
@@ -1,1152 +0,0 @@
2 -<?php
3 -/**
4 - * SFUploadWindow2 - used for uploading files from within a form, for
5 - * MediaWiki version 1.16+.
6 - * This class is nearly identical to MediaWiki's SpecialUpload class, with
7 - * a few changes to remove skin CSS and HTML, and to populate the relevant
8 - * field in the form with the name of the uploaded form.
9 - *
10 - * @author Yaron Koren
11 - * @file
12 - * @ingroup SF
13 - */
14 -
15 -/**
16 - * @ingroup SFSpecialPages
17 - */
18 -class SFUploadWindow2Proto extends UnlistedSpecialPage {
19 - /**
20 - * Constructor : initialise object
21 - * Get data POSTed through the form and assign them to the object
22 - * @param WebRequest $request Data posted.
23 - */
24 - public function __construct( $request = null ) {
25 - global $wgRequest;
26 -
27 - parent::__construct( 'UploadWindow', 'upload' );
28 -
29 - $this->loadRequest( is_null( $request ) ? $wgRequest : $request );
30 - }
31 -
32 - /** Misc variables **/
33 - public $mRequest; // The WebRequest or FauxRequest this form is supposed to handle
34 - public $mSourceType;
35 - public $mUpload;
36 - public $mLocalFile;
37 - public $mUploadClicked;
38 -
39 - /** User input variables from the "description" section **/
40 - public $mDesiredDestName; // The requested target file name
41 - public $mComment;
42 - public $mLicense;
43 -
44 - /** User input variables from the root section **/
45 - public $mIgnoreWarning;
46 - public $mWatchThis;
47 - public $mCopyrightStatus;
48 - public $mCopyrightSource;
49 -
50 - /** Hidden variables **/
51 - public $mForReUpload; // The user followed an "overwrite this file" link
52 - public $mCancelUpload; // The user clicked "Cancel and return to upload form" button
53 - public $mTokenOk;
54 -
55 - /** used by Semantic Forms **/
56 - public $mInputID;
57 - public $mDelimiter;
58 -
59 - /**
60 - * Initialize instance variables from request and create an Upload handler
61 - *
62 - * @param WebRequest $request The request to extract variables from
63 - */
64 - protected function loadRequest( $request ) {
65 - global $wgUser;
66 -
67 - $this->mRequest = $request;
68 - $this->mSourceType = $request->getVal( 'wpSourceType', 'file' );
69 - $this->mUpload = UploadBase::createFromRequest( $request );
70 - $this->mUploadClicked = $request->wasPosted()
71 - && ( $request->getCheck( 'wpUpload' )
72 - || $request->getCheck( 'wpUploadIgnoreWarning' ) );
73 -
74 - // Guess the desired name from the filename if not provided
75 - $this->mDesiredDestName = $request->getText( 'wpDestFile' );
76 - if ( !$this->mDesiredDestName )
77 - $this->mDesiredDestName = $request->getText( 'wpUploadFile' );
78 - $this->mComment = $request->getText( 'wpUploadDescription' );
79 - $this->mLicense = $request->getText( 'wpLicense' );
80 -
81 -
82 - $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' );
83 - $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' )
84 - || $request->getCheck( 'wpUploadIgnoreWarning' );
85 - $this->mWatchthis = $request->getBool( 'wpWatchthis' );
86 - $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
87 - $this->mCopyrightSource = $request->getText( 'wpUploadSource' );
88 -
89 -
90 - $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
91 - $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' )
92 - || $request->getCheck( 'wpReUpload' ); // b/w compat
93 -
94 - // If it was posted check for the token (no remote POST'ing with user credentials)
95 - $token = $request->getVal( 'wpEditToken' );
96 - if ( $this->mSourceType == 'file' && $token == null ) {
97 - // Skip token check for file uploads as that can't be faked via JS...
98 - // Some client-side tools don't expect to need to send wpEditToken
99 - // with their submissions, as that's new in 1.16.
100 - $this->mTokenOk = true;
101 - } else {
102 - $this->mTokenOk = $wgUser->matchEditToken( $token );
103 - }
104 - $this->mInputID = $request->getText( 'sfInputID' );
105 - $this->mDelimiter = $request->getText( 'sfDelimiter' );
106 - }
107 -
108 - /**
109 - * Special page entry point
110 - */
111 - public function execute( $par ) {
112 - global $wgUser, $wgOut;
113 - // Disable $wgOut - we'll print out the page manually, taking
114 - // the body created by the form, plus the necessary Javascript
115 - // files, and turning them into an HTML page.
116 - $wgOut->disable();
117 - // This line is needed to get around Squid caching.
118 - $wgOut->sendCacheControl();
119 -
120 - $this->setHeaders();
121 - $this->outputHeader();
122 -
123 - # Check uploading enabled
124 - if ( !UploadBase::isEnabled() ) {
125 - $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext' );
126 - print $wgOut->getHTML();
127 - return;
128 - }
129 -
130 - # Check permissions
131 - global $wgGroupPermissions;
132 - if ( !$wgUser->isAllowed( 'upload' ) ) {
133 - if ( !$wgUser->isLoggedIn() && ( $wgGroupPermissions['user']['upload']
134 - || $wgGroupPermissions['autoconfirmed']['upload'] ) ) {
135 - // Custom message if logged-in users without any special rights can upload
136 - $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
137 - } else {
138 - $wgOut->permissionRequired( 'upload' );
139 - }
140 - print $wgOut->getHTML();
141 - return;
142 - }
143 -
144 - # Check blocks
145 - if ( $wgUser->isBlocked() ) {
146 - $wgOut->blockedPage();
147 - print $wgOut->getHTML();
148 - return;
149 - }
150 -
151 - # Check whether we actually want to allow changing stuff
152 - if ( wfReadOnly() ) {
153 - $wgOut->readOnlyPage();
154 - print $wgOut->getHTML();
155 - return;
156 - }
157 -
158 - # Unsave the temporary file in case this was a cancelled upload
159 - if ( $this->mCancelUpload ) {
160 - if ( !$this->unsaveUploadedFile() )
161 - # Something went wrong, so unsaveUploadedFile showed a warning
162 - return;
163 - }
164 -
165 - # Process upload or show a form
166 - if ( $this->mTokenOk && !$this->mCancelUpload
167 - && ( $this->mUpload && $this->mUploadClicked ) ) {
168 - $this->processUpload();
169 - } else {
170 - $this->showUploadForm( $this->getUploadForm() );
171 - }
172 -
173 - # Cleanup
174 - if ( $this->mUpload )
175 - $this->mUpload->cleanupTempFile();
176 - }
177 -
178 - /**
179 - * Show the main upload form and optionally add the session key to the
180 - * output. This hides the source selection.
181 - *
182 - * @param string $message HTML message to be shown at top of form
183 - * @param string $sessionKey Session key of the stashed upload
184 - */
185 - protected function showUploadForm( $form ) {
186 - # Add links if file was previously deleted
187 - if ( !$this->mDesiredDestName )
188 - $this->showViewDeletedLinks();
189 -
190 - $form->show();
191 - }
192 -
193 - /**
194 - * Get an UploadForm instance with title and text properly set.
195 - *
196 - * @param string $message HTML string to add to the form
197 - * @param string $sessionKey Session key in case this is a stashed upload
198 - * @return UploadForm
199 - */
200 - protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) {
201 - global $wgOut;
202 -
203 - # Initialize form
204 - $form = new SFUploadForm( array(
205 - 'watch' => $this->watchCheck(),
206 - 'forreupload' => $this->mForReUpload,
207 - 'sessionkey' => $sessionKey,
208 - 'hideignorewarning' => $hideIgnoreWarning,
209 - 'destfile' => $this->mDesiredDestName,
210 - 'sfInputID' => $this->mInputID,
211 - 'sfDelimiter' => $this->mDelimiter,
212 - ) );
213 - $form->setTitle( $this->getTitle() );
214 -
215 - # Check the token, but only if necessary
216 - if ( !$this->mTokenOk && !$this->mCancelUpload
217 - && ( $this->mUpload && $this->mUploadClicked ) )
218 - $form->addPreText( wfMsgExt( 'session_fail_preview', 'parseinline' ) );
219 -
220 - # Add text to form
221 - // $form->addPreText( '<div id="uploadtext">' . wfMsgExt( 'uploadtext', 'parse' ) . '</div>');
222 - # Add upload error message
223 - $form->addPreText( $message );
224 -
225 - # Add footer to form
226 - $uploadFooter = wfMsgNoTrans( 'uploadfooter' );
227 - if ( $uploadFooter != '-' && !wfEmptyMsg( 'uploadfooter', $uploadFooter ) ) {
228 - $form->addPostText( '<div id="mw-upload-footer-message">'
229 - . $wgOut->parse( $uploadFooter ) . "</div>\n" );
230 - }
231 -
232 - return $form;
233 -
234 - }
235 -
236 - /**
237 - * Shows the "view X deleted revivions link""
238 - */
239 - protected function showViewDeletedLinks() {
240 - global $wgOut, $wgUser;
241 -
242 - $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
243 - // Show a subtitle link to deleted revisions (to sysops et al only)
244 - if ( $title instanceof Title && ( $count = $title->isDeleted() ) > 0 && $wgUser->isAllowed( 'deletedhistory' ) ) {
245 - $link = wfMsgExt(
246 - $wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
247 - array( 'parse', 'replaceafter' ),
248 - $wgUser->getSkin()->linkKnown(
249 - SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
250 - wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
251 - )
252 - );
253 - $wgOut->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
254 - }
255 -
256 - // Show the relevant lines from deletion log (for still deleted files only)
257 - if ( $title instanceof Title && $title->isDeletedQuick() && !$title->exists() ) {
258 - $this->showDeletionLog( $wgOut, $title->getPrefixedText() );
259 - }
260 - }
261 -
262 - /**
263 - * Stashes the upload and shows the main upload form.
264 - *
265 - * Note: only errors that can be handled by changing the name or
266 - * description should be redirected here. It should be assumed that the
267 - * file itself is sane and has passed UploadBase::verifyFile. This
268 - * essentially means that UploadBase::VERIFICATION_ERROR and
269 - * UploadBase::EMPTY_FILE should not be passed here.
270 - *
271 - * @param string $message HTML message to be passed to mainUploadForm
272 - */
273 - protected function recoverableUploadError( $message ) {
274 - $sessionKey = $this->mUpload->stashSession();
275 - $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
276 - '<div class="error">' . $message . "</div>\n";
277 -
278 - $form = $this->getUploadForm( $message, $sessionKey );
279 - $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
280 - $this->showUploadForm( $form );
281 - }
282 - /**
283 - * Stashes the upload, shows the main form, but adds an "continue anyway button"
284 - *
285 - * @param array $warnings
286 - */
287 - protected function uploadWarning( $warnings ) {
288 - $sessionKey = $this->mUpload->stashSession();
289 -
290 - $warningHtml = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n"
291 - . '<ul class="warning">';
292 - foreach ( $warnings as $warning => $args ) {
293 - $msg = '';
294 - if ( $warning == 'exists' ) {
295 - $msg = self::getExistsWarning( $args );
296 - } elseif ( $warning == 'duplicate' ) {
297 - $msg = self::getDupeWarning( $args );
298 - } elseif ( $warning == 'duplicate-archive' ) {
299 - $msg = "\t<li>" . wfMsgExt( 'file-deleted-duplicate', 'parseinline',
300 - array( Title::makeTitle( NS_FILE, $args )->getPrefixedText() ) )
301 - . "</li>\n";
302 - } else {
303 - if ( is_bool( $args ) )
304 - $args = array();
305 - elseif ( !is_array( $args ) )
306 - $args = array( $args );
307 - $msg = "\t<li>" . wfMsgExt( $warning, 'parseinline', $args ) . "</li>\n";
308 - }
309 - $warningHtml .= $msg;
310 - }
311 - $warningHtml .= "</ul>\n";
312 - $warningHtml .= wfMsgExt( 'uploadwarning-text', 'parse' );
313 -
314 - $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
315 - $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
316 - $form->addButton( 'wpUploadIgnoreWarning', wfMsg( 'ignorewarning' ) );
317 - $form->addButton( 'wpCancelUpload', wfMsg( 'reuploaddesc' ) );
318 -
319 - $this->showUploadForm( $form );
320 - }
321 -
322 - /**
323 - * Show the upload form with error message, but do not stash the file.
324 - *
325 - * @param string $message
326 - */
327 - protected function uploadError( $message ) {
328 - $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
329 - '<div class="error">' . $message . "</div>\n";
330 - $this->showUploadForm( $this->getUploadForm( $message ) );
331 - }
332 -
333 - /**
334 - * Do the upload.
335 - * Checks are made in SpecialUpload::execute()
336 - */
337 - protected function processUpload() {
338 - global $wgUser, $wgOut;
339 -
340 - // Verify permissions
341 - $permErrors = $this->mUpload->verifyPermissions( $wgUser );
342 - if ( $permErrors !== true )
343 - return $wgOut->showPermissionsErrorPage( $permErrors );
344 -
345 - // Fetch the file if required
346 - $status = $this->mUpload->fetchFile();
347 - if ( !$status->isOK() )
348 - return $this->showUploadForm( $this->getUploadForm( $wgOut->parse( $status->getWikiText() ) ) );
349 -
350 - // Upload verification
351 - $details = $this->mUpload->verifyUpload();
352 - if ( $details['status'] != UploadBase::OK )
353 - return $this->processVerificationError( $details );
354 -
355 - $this->mLocalFile = $this->mUpload->getLocalFile();
356 -
357 - // Check warnings if necessary
358 - if ( !$this->mIgnoreWarning ) {
359 - $warnings = $this->mUpload->checkWarnings();
360 - if ( count( $warnings ) )
361 - return $this->uploadWarning( $warnings );
362 - }
363 -
364 - // Get the page text if this is not a reupload
365 - if ( !$this->mForReUpload ) {
366 - $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
367 - $this->mCopyrightStatus, $this->mCopyrightSource );
368 - } else {
369 - $pageText = false;
370 - }
371 - $status = $this->mUpload->performUpload( $this->mComment, $pageText, $this->mWatchthis, $wgUser );
372 - if ( !$status->isGood() )
373 - return $this->uploadError( $wgOut->parse( $status->getWikiText() ) );
374 -
375 - // $wgOut->redirect( $this->mLocalFile->getTitle()->getFullURL() );
376 - // Semantic Forms change - output Javascript to either
377 - // fill in or append to the field in original form, and
378 - // close the window
379 - # Chop off any directories in the given filename
380 - if ( $this->mDesiredDestName ) {
381 - $basename = $this->mDesiredDestName;
382 - } else {
383 - $basename = $this->mSrcName;
384 - }
385 -
386 - $basename = str_replace( '_', ' ', $basename );
387 - // UTF8-decoding is needed for IE
388 - $basename = utf8_decode( $basename );
389 -
390 - $output .= <<<END
391 - <script type="text/javascript">
392 - var input = parent.window.jQuery( parent.document.getElementById("{$this->mInputID}") );
393 -END;
394 -
395 - if ( $this->mDelimiter == null ) {
396 - $output .= <<<END
397 - input.val( '$basename' );
398 - input.change();
399 -END;
400 - } else {
401 - $output .= <<<END
402 - // if the current value is blank, set it to this file name;
403 - // if it's not blank and ends in a space or delimiter, append
404 - // the file name; if it ends with a normal character, append
405 - // both a delimiter and a file name; and add on a delimiter
406 - // at the end in any case
407 - var cur_value = parent.document.getElementById("{$this->mInputID}").value;
408 -
409 - if (cur_value === '') {
410 - input.val( '$basename' + '{$this->mDelimiter} ' );
411 - input.change();
412 - } else {
413 - var last_char = cur_value.charAt(cur_value.length - 1);
414 - if (last_char == '{$this->mDelimiter}' || last_char == ' ') {
415 - parent.document.getElementById("{$this->mInputID}").value += '$basename' + '{$this->mDelimiter} ';
416 - input.change();
417 - } else {
418 - parent.document.getElementById("{$this->mInputID}").value += '{$this->mDelimiter} $basename{$this->mDelimiter} ';
419 - input.change();
420 - }
421 - }
422 -
423 -END;
424 - }
425 - $output .= <<<END
426 - parent.jQuery.fancybox.close();
427 - </script>
428 -
429 -END;
430 - // $wgOut->addHTML( $output );
431 - print $output;
432 - $img = null; // @todo: added to avoid passing a ref to null - should this be defined somewhere?
433 -
434 - wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
435 - }
436 -
437 - /**
438 - * Get the initial image page text based on a comment and optional file status information
439 - */
440 - public static function getInitialPageText( $comment = '', $license = '', $copyStatus = '', $source = '' ) {
441 - global $wgUseCopyrightUpload;
442 - if ( $wgUseCopyrightUpload ) {
443 - $licensetxt = '';
444 - if ( $license !== '' ) {
445 - $licensetxt = '== ' . wfMsgForContent( 'license-header' ) . " ==\n" . '{{' . $license . '}}' . "\n";
446 - }
447 - $pageText = '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n" .
448 - '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
449 - "$licensetxt" .
450 - '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
451 - } else {
452 - if ( $license !== '' ) {
453 - $filedesc = $comment === '' ? '' : '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n";
454 - $pageText = $filedesc .
455 - '== ' . wfMsgForContent ( 'license-header' ) . " ==\n" . '{{' . $license . '}}' . "\n";
456 - } else {
457 - $pageText = $comment;
458 - }
459 - }
460 - return $pageText;
461 - }
462 -
463 - /**
464 - * See if we should check the 'watch this page' checkbox on the form
465 - * based on the user's preferences and whether we're being asked
466 - * to create a new file or update an existing one.
467 - *
468 - * In the case where 'watch edits' is off but 'watch creations' is on,
469 - * we'll leave the box unchecked.
470 - *
471 - * Note that the page target can be changed *on the form*, so our check
472 - * state can get out of sync.
473 - */
474 - protected function watchCheck() {
475 - global $wgUser;
476 - if ( $wgUser->getOption( 'watchdefault' ) ) {
477 - // Watch all edits!
478 - return true;
479 - }
480 -
481 - $local = wfLocalFile( $this->mDesiredDestName );
482 - if ( $local && $local->exists() ) {
483 - // We're uploading a new version of an existing file.
484 - // No creation, so don't watch it if we're not already.
485 - return $local->getTitle()->userIsWatching();
486 - } else {
487 - // New page should get watched if that's our option.
488 - return $wgUser->getOption( 'watchcreations' );
489 - }
490 - }
491 -
492 -
493 - /**
494 - * Provides output to the user for a result of UploadBase::verifyUpload
495 - *
496 - * @param array $details Result of UploadBase::verifyUpload
497 - */
498 - protected function processVerificationError( $details ) {
499 - global $wgFileExtensions, $wgLang;
500 -
501 - switch( $details['status'] ) {
502 -
503 - /** Statuses that only require name changing **/
504 - case UploadBase::MIN_LENGTH_PARTNAME:
505 - $this->recoverableUploadError( wfMsgHtml( 'minlength1' ) );
506 - break;
507 - case UploadBase::ILLEGAL_FILENAME:
508 - $this->recoverableUploadError( wfMsgExt( 'illegalfilename',
509 - 'parseinline', $details['filtered'] ) );
510 - break;
511 - case UploadBase::OVERWRITE_EXISTING_FILE:
512 - $this->recoverableUploadError( wfMsgExt( $details['overwrite'],
513 - 'parseinline' ) );
514 - break;
515 - case UploadBase::FILETYPE_MISSING:
516 - $this->recoverableUploadError( wfMsgExt( 'filetype-missing',
517 - 'parseinline' ) );
518 - break;
519 -
520 - /** Statuses that require reuploading **/
521 - case UploadBase::EMPTY_FILE:
522 - $this->showUploadForm( $this->getUploadForm( wfMsgHtml( 'emptyfile' ) ) );
523 - break;
524 - case UploadBase::FILETYPE_BADTYPE:
525 - $finalExt = $details['finalExt'];
526 - $this->uploadError(
527 - wfMsgExt( 'filetype-banned-type',
528 - array( 'parseinline' ),
529 - htmlspecialchars( $finalExt ),
530 - implode(
531 - wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
532 - $wgFileExtensions
533 - ),
534 - $wgLang->formatNum( count( $wgFileExtensions ) )
535 - )
536 - );
537 - break;
538 - case UploadBase::VERIFICATION_ERROR:
539 - unset( $details['status'] );
540 - $code = array_shift( $details['details'] );
541 - $this->uploadError( wfMsgExt( $code, 'parseinline', $details['details'] ) );
542 - break;
543 - case UploadBase::HOOK_ABORTED:
544 - $error = $details['error'];
545 - $this->uploadError( wfMsgExt( $error, 'parseinline' ) );
546 - break;
547 - default:
548 - throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
549 - }
550 - }
551 -
552 - /**
553 - * Remove a temporarily kept file stashed by saveTempUploadedFile().
554 - * @access private
555 - * @return success
556 - */
557 - protected function unsaveUploadedFile() {
558 - global $wgOut;
559 - if ( !( $this->mUpload instanceof UploadFromStash ) )
560 - return true;
561 - $success = $this->mUpload->unsaveUploadedFile();
562 - if ( ! $success ) {
563 - $wgOut->showFileDeleteError( $this->mUpload->getTempPath() );
564 - return false;
565 - } else {
566 - return true;
567 - }
568 - }
569 -
570 - /*** Functions for formatting warnings ***/
571 -
572 - /**
573 - * Formats a result of UploadBase::getExistsWarning as HTML
574 - * This check is static and can be done pre-upload via AJAX
575 - *
576 - * @param array $exists The result of UploadBase::getExistsWarning
577 - * @return string Empty string if there is no warning or an HTML fragment
578 - * consisting of one or more <li> elements if there is a warning.
579 - */
580 - public static function getExistsWarning( $exists ) {
581 - global $wgUser;
582 -
583 - if ( !$exists )
584 - return '';
585 -
586 - $file = $exists['file'];
587 - $filename = $file->getTitle()->getPrefixedText();
588 - $warning = array();
589 -
590 - $sk = $wgUser->getSkin();
591 -
592 - if ( $exists['warning'] == 'exists' ) {
593 - // Exact match
594 - $warning[] = '<li>' . wfMsgExt( 'fileexists', 'parseinline', $filename ) . '</li>';
595 - } elseif ( $exists['warning'] == 'page-exists' ) {
596 - // Page exists but file does not
597 - $warning[] = '<li>' . wfMsgExt( 'filepageexists', 'parseinline', $filename ) . '</li>';
598 - } elseif ( $exists['warning'] == 'exists-normalized' ) {
599 - $warning[] = '<li>' . wfMsgExt( 'fileexists-extension', 'parseinline', $filename,
600 - $exists['normalizedFile']->getTitle()->getPrefixedText() ) . '</li>';
601 - } elseif ( $exists['warning'] == 'thumb' ) {
602 - // Swapped argument order compared with other messages for backwards compatibility
603 - $warning[] = '<li>' . wfMsgExt( 'fileexists-thumbnail-yes', 'parseinline',
604 - $exists['thumbFile']->getTitle()->getPrefixedText(), $filename ) . '</li>';
605 - } elseif ( $exists['warning'] == 'thumb-name' ) {
606 - // Image w/o '180px-' does not exists, but we do not like these filenames
607 - $name = $file->getName();
608 - $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
609 - $warning[] = '<li>' . wfMsgExt( 'file-thumbnail-no', 'parseinline', $badPart ) . '</li>';
610 - } elseif ( $exists['warning'] == 'bad-prefix' ) {
611 - $warning[] = '<li>' . wfMsgExt( 'filename-bad-prefix', 'parseinline', $exists['prefix'] ) . '</li>';
612 - } elseif ( $exists['warning'] == 'was-deleted' ) {
613 - # If the file existed before and was deleted, warn the user of this
614 - $ltitle = SpecialPage::getTitleFor( 'Log' );
615 - $llink = $sk->linkKnown(
616 - $ltitle,
617 - wfMsgHtml( 'deletionlog' ),
618 - array(),
619 - array(
620 - 'type' => 'delete',
621 - 'page' => $filename
622 - )
623 - );
624 - $warning[] = '<li>' . wfMsgWikiHtml( 'filewasdeleted', $llink ) . '</li>';
625 - }
626 -
627 - return implode( "\n", $warning );
628 - }
629 -
630 - /**
631 - * Get a list of warnings
632 - *
633 - * @param string local filename, e.g. 'file exists', 'non-descriptive filename'
634 - * @return array list of warning messages
635 - */
636 - public static function ajaxGetExistsWarning( $filename ) {
637 - $file = wfFindFile( $filename );
638 - if ( !$file ) {
639 - // Force local file so we have an object to do further checks against
640 - // if there isn't an exact match...
641 - $file = wfLocalFile( $filename );
642 - }
643 - $s = '&#160;';
644 - if ( $file ) {
645 - $exists = UploadBase::getExistsWarning( $file );
646 - $warning = self::getExistsWarning( $exists );
647 - if ( $warning !== '' ) {
648 - $s = "<ul>$warning</ul>";
649 - }
650 - }
651 - return $s;
652 - }
653 -
654 - /**
655 - * Render a preview of a given license for the AJAX preview on upload
656 - *
657 - * @param string $license
658 - * @return string
659 - */
660 - public static function ajaxGetLicensePreview( $license ) {
661 - global $wgParser, $wgUser;
662 - $text = '{{' . $license . '}}';
663 - $title = Title::makeTitle( NS_FILE, 'Sample.jpg' );
664 - $options = ParserOptions::newFromUser( $wgUser );
665 -
666 - // Expand subst: first, then live templates...
667 - $text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options );
668 - $output = $wgParser->parse( $text, $title, $options );
669 -
670 - return $output->getText();
671 - }
672 -
673 - /**
674 - * Construct a warning and a gallery from an array of duplicate files.
675 - */
676 - public static function getDupeWarning( $dupes ) {
677 - if ( $dupes ) {
678 - global $wgOut;
679 - $msg = "<gallery>";
680 - foreach ( $dupes as $file ) {
681 - $title = $file->getTitle();
682 - $msg .= $title->getPrefixedText() .
683 - "|" . $title->getText() . "\n";
684 - }
685 - $msg .= "</gallery>";
686 - return "<li>" .
687 - wfMsgExt( "file-exists-duplicate", array( "parse" ), count( $dupes ) ) .
688 - $wgOut->parse( $msg ) .
689 - "</li>\n";
690 - } else {
691 - return '';
692 - }
693 - }
694 -
695 -}
696 -
697 -/**
698 - * Sub class of HTMLForm that provides the form section of SpecialUpload
699 - */
700 -class SFUploadForm extends HTMLForm {
701 - protected $mWatch;
702 - protected $mForReUpload;
703 - protected $mSessionKey;
704 - protected $mHideIgnoreWarning;
705 - protected $mDestWarningAck;
706 -
707 - protected $mSourceIds;
708 -
709 - public function __construct( $options = array() ) {
710 - $this->mWatch = !empty( $options['watch'] );
711 - $this->mForReUpload = !empty( $options['forreupload'] );
712 - $this->mSessionKey = isset( $options['sessionkey'] )
713 - ? $options['sessionkey'] : '';
714 - $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] );
715 - $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : '';
716 -
717 - $sourceDescriptor = $this->getSourceSection();
718 - $descriptor = $sourceDescriptor
719 - + $this->getDescriptionSection()
720 - + $this->getOptionsSection();
721 -
722 - wfRunHooks( 'UploadFormInitDescriptor', array( $descriptor ) );
723 - parent::__construct( $descriptor, 'upload' );
724 -
725 - # Set some form properties
726 - $this->setSubmitText( wfMsg( 'uploadbtn' ) );
727 - $this->setSubmitName( 'wpUpload' );
728 - $this->setSubmitTooltip( 'upload' );
729 - $this->setId( 'mw-upload-form' );
730 -
731 - # Build a list of IDs for javascript insertion
732 - $this->mSourceIds = array();
733 - foreach ( $sourceDescriptor as $key => $field ) {
734 - if ( !empty( $field['id'] ) )
735 - $this->mSourceIds[] = $field['id'];
736 - }
737 - // added for Semantic Forms
738 - $this->addHiddenField( 'sfInputID', $options['sfInputID'] );
739 - $this->addHiddenField( 'sfDelimiter', $options['sfDelimiter'] );
740 -
741 - }
742 -
743 - /**
744 - * Get the descriptor of the fieldset that contains the file source
745 - * selection. The section is 'source'
746 - *
747 - * @return array Descriptor array
748 - */
749 - protected function getSourceSection() {
750 - global $wgLang, $wgUser, $wgRequest;
751 -
752 - if ( $this->mSessionKey ) {
753 - return array(
754 - 'wpSessionKey' => array(
755 - 'type' => 'hidden',
756 - 'default' => $this->mSessionKey,
757 - ),
758 - 'wpSourceType' => array(
759 - 'type' => 'hidden',
760 - 'default' => 'Stash',
761 - ),
762 - );
763 - }
764 -
765 - $canUploadByUrl = UploadFromUrl::isEnabled() && $wgUser->isAllowed( 'upload_by_url' );
766 - $radio = $canUploadByUrl;
767 - $selectedSourceType = strtolower( $wgRequest->getText( 'wpSourceType', 'File' ) );
768 -
769 - $descriptor = array();
770 - $descriptor['UploadFile'] = array(
771 - 'class' => 'SFUploadSourceField',
772 - 'section' => 'source',
773 - 'type' => 'file',
774 - 'id' => 'wpUploadFile',
775 - 'label-message' => 'sourcefilename',
776 - 'upload-type' => 'File',
777 - 'radio' => &$radio,
778 - 'help' => wfMsgExt( 'upload-maxfilesize',
779 - array( 'parseinline', 'escapenoentities' ),
780 - $wgLang->formatSize(
781 - wfShorthandToInteger( ini_get( 'upload_max_filesize' ) )
782 - )
783 - ) . ' ' . wfMsgHtml( 'upload_source_file' ),
784 - 'checked' => $selectedSourceType == 'file',
785 - );
786 - if ( $canUploadByUrl ) {
787 - global $wgMaxUploadSize;
788 - $descriptor['UploadFileURL'] = array(
789 - 'class' => 'SFUploadSourceField',
790 - 'section' => 'source',
791 - 'id' => 'wpUploadFileURL',
792 - 'label-message' => 'sourceurl',
793 - 'upload-type' => 'Url',
794 - 'radio' => &$radio,
795 - 'help' => wfMsgExt( 'upload-maxfilesize',
796 - array( 'parseinline', 'escapenoentities' ),
797 - $wgLang->formatSize( $wgMaxUploadSize )
798 - ) . ' ' . wfMsgHtml( 'upload_source_url' ),
799 - 'checked' => $selectedSourceType == 'url',
800 - );
801 - }
802 - wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
803 -
804 - $descriptor['Extensions'] = array(
805 - 'type' => 'info',
806 - 'section' => 'source',
807 - 'default' => $this->getExtensionsMessage(),
808 - 'raw' => true,
809 - );
810 - return $descriptor;
811 - }
812 -
813 -
814 - /**
815 - * Get the messages indicating which extensions are preferred and prohibitted.
816 - *
817 - * @return string HTML string containing the message
818 - */
819 - protected function getExtensionsMessage() {
820 - # Print a list of allowed file extensions, if so configured. We ignore
821 - # MIME type here, it's incomprehensible to most people and too long.
822 - global $wgLang, $wgCheckFileExtensions, $wgStrictFileExtensions,
823 - $wgFileExtensions, $wgFileBlacklist;
824 -
825 - $allowedExtensions = '';
826 - if ( $wgCheckFileExtensions ) {
827 - if ( $wgStrictFileExtensions ) {
828 - # Everything not permitted is banned
829 - $extensionsList =
830 - '<div id="mw-upload-permitted">' .
831 - wfMsgWikiHtml( 'upload-permitted', $wgLang->commaList( $wgFileExtensions ) ) .
832 - "</div>\n";
833 - } else {
834 - # We have to list both preferred and prohibited
835 - $extensionsList =
836 - '<div id="mw-upload-preferred">' .
837 - wfMsgWikiHtml( 'upload-preferred', $wgLang->commaList( $wgFileExtensions ) ) .
838 - "</div>\n" .
839 - '<div id="mw-upload-prohibited">' .
840 - wfMsgWikiHtml( 'upload-prohibited', $wgLang->commaList( $wgFileBlacklist ) ) .
841 - "</div>\n";
842 - }
843 - } else {
844 - # Everything is permitted.
845 - $extensionsList = '';
846 - }
847 - return $extensionsList;
848 - }
849 -
850 - /**
851 - * Get the descriptor of the fieldset that contains the file description
852 - * input. The section is 'description'
853 - *
854 - * @return array Descriptor array
855 - */
856 - protected function getDescriptionSection() {
857 - global $wgUser, $wgOut;
858 -
859 - $cols = intval( $wgUser->getOption( 'cols' ) );
860 - if ( $wgUser->getOption( 'editwidth' ) ) {
861 - $wgOut->addInlineStyle( '#mw-htmlform-description { width: 100%; }' );
862 - }
863 -
864 - $descriptor = array(
865 - 'DestFile' => array(
866 - 'type' => 'text',
867 - 'section' => 'description',
868 - 'id' => 'wpDestFile',
869 - 'label-message' => 'destfilename',
870 - 'size' => 60,
871 - ),
872 - 'UploadDescription' => array(
873 - 'type' => 'textarea',
874 - 'section' => 'description',
875 - 'id' => 'wpUploadDescription',
876 - 'label-message' => $this->mForReUpload
877 - ? 'filereuploadsummary'
878 - : 'fileuploadsummary',
879 - 'cols' => $cols,
880 - 'rows' => 4,
881 - ),
882 -/*
883 - 'EditTools' => array(
884 - 'type' => 'edittools',
885 - 'section' => 'description',
886 - ),
887 -*/
888 - 'License' => array(
889 - 'type' => 'select',
890 - 'class' => 'Licenses',
891 - 'section' => 'description',
892 - 'id' => 'wpLicense',
893 - 'label-message' => 'license',
894 - ),
895 - );
896 - if ( $this->mForReUpload )
897 - $descriptor['DestFile']['readonly'] = true;
898 -
899 - global $wgUseCopyrightUpload;
900 - if ( $wgUseCopyrightUpload ) {
901 - $descriptor['UploadCopyStatus'] = array(
902 - 'type' => 'text',
903 - 'section' => 'description',
904 - 'id' => 'wpUploadCopyStatus',
905 - 'label-message' => 'filestatus',
906 - );
907 - $descriptor['UploadSource'] = array(
908 - 'type' => 'text',
909 - 'section' => 'description',
910 - 'id' => 'wpUploadSource',
911 - 'label-message' => 'filesource',
912 - );
913 - }
914 -
915 - return $descriptor;
916 - }
917 -
918 - /**
919 - * Get the descriptor of the fieldset that contains the upload options,
920 - * such as "watch this file". The section is 'options'
921 - *
922 - * @return array Descriptor array
923 - */
924 - protected function getOptionsSection() {
925 - $descriptor = array(
926 - 'Watchthis' => array(
927 - 'type' => 'check',
928 - 'id' => 'wpWatchthis',
929 - 'label-message' => 'watchthisupload',
930 - 'section' => 'options',
931 - )
932 - );
933 - if ( !$this->mHideIgnoreWarning ) {
934 - $descriptor['IgnoreWarning'] = array(
935 - 'type' => 'check',
936 - 'id' => 'wpIgnoreWarning',
937 - 'label-message' => 'ignorewarnings',
938 - 'section' => 'options',
939 - );
940 - }
941 - $descriptor['DestFileWarningAck'] = array(
942 - 'type' => 'hidden',
943 - 'id' => 'wpDestFileWarningAck',
944 - 'default' => $this->mDestWarningAck ? '1' : '',
945 - );
946 -
947 -
948 - return $descriptor;
949 -
950 - }
951 -
952 - /**
953 - * Add the upload JS and show the form.
954 - */
955 - public function show() {
956 - $this->addUploadJS();
957 - parent::show();
958 - // disable $wgOut - we'll print out the page manually,
959 - // taking the body created by the form, plus the necessary
960 - // Javascript files, and turning them into an HTML page
961 - global $wgOut, $wgUser, $wgTitle, $wgLanguageCode,
962 - $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces, $wgContLang;
963 -
964 - $wgOut->disable();
965 - $sk = $wgUser->getSkin();
966 - $sk->initPage( $wgOut ); // need to call this to set skin name correctly
967 - $wgTitle = SpecialPage::getTitleFor( 'Upload' );
968 -
969 - if ( method_exists( $wgOut, 'addModules' ) ) {
970 - $wgOut->addModules( array( 'mediawiki.action.edit', 'mediawiki.legacy.upload', 'mediawiki.legacy.wikibits', 'mediawiki.legacy.ajax' ) );
971 - // Method was added in MW 1.18
972 - if ( method_exists( $wgOut, 'getBottomScripts' ) ) {
973 - $head_scripts = $wgOut->getHeadScripts( $sk );
974 - $body_scripts = $wgOut->getBottomScripts( $sk );
975 - } else {
976 - $head_scripts = '';
977 - $body_scripts = $wgOut->getHeadScripts( $sk );
978 - }
979 - } else {
980 - global $wgJsMimeType, $wgStylePath, $wgStyleVersion;
981 - $vars_js = Skin::makeGlobalVariablesScript( array( 'skinname' => $sk->getSkinName() ) );
982 - $head_scripts = <<<END
983 -$vars_js
984 -<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/wikibits.js?$wgStyleVersion"></script>
985 -{$wgOut->getScript()}
986 -<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/ajax.js?$wgStyleVersion"></script>
987 -<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/ajaxwatch.js?$wgStyleVersion"></script>
988 -
989 -END;
990 - $body_scripts = '';
991 - }
992 -
993 - $text = <<<END
994 -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
995 -<html xmlns="{$wgXhtmlDefaultNamespace}"
996 -END;
997 - foreach ( $wgXhtmlNamespaces as $tag => $ns ) {
998 - $text .= "xmlns:{$tag}=\"{$ns}\" ";
999 - }
1000 - $dir = $wgContLang->isRTL() ? "rtl" : "ltr";
1001 - $text .= "xml:lang=\"{$wgLanguageCode}\" lang=\"{$wgLanguageCode}\" dir=\"{$dir}\">";
1002 -
1003 - $text .= <<<END
1004 -
1005 -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1006 -<head>
1007 -$head_scripts
1008 -</head>
1009 -<body>
1010 -{$wgOut->getHTML()}
1011 -$body_scripts
1012 -</body>
1013 -</html>
1014 -
1015 -
1016 -END;
1017 - print $text;
1018 - }
1019 -
1020 - /**
1021 - * Add upload JS to $wgOut
1022 - *
1023 - * @param bool $autofill Whether or not to autofill the destination
1024 - * filename text box
1025 - */
1026 - protected function addUploadJS( $autofill = true ) {
1027 - global $wgUseAjax, $wgAjaxUploadDestCheck, $wgAjaxLicensePreview;
1028 - global $wgStrictFileExtensions;
1029 - global $wgEnableJS2system;
1030 - global $wgOut;
1031 -
1032 - $scriptVars = array(
1033 - 'wgAjaxUploadDestCheck' => $wgUseAjax && $wgAjaxUploadDestCheck,
1034 - 'wgAjaxLicensePreview' => $wgUseAjax && $wgAjaxLicensePreview,
1035 - 'wgUploadAutoFill' => (bool)$autofill &&
1036 - // If we received mDestFile from the request, don't autofill
1037 - // the wpDestFile textbox
1038 - $this->mDestFile === '',
1039 - 'wgUploadSourceIds' => $this->mSourceIds,
1040 - 'wgStrictFileExtensions' => $wgStrictFileExtensions,
1041 - 'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ),
1042 - );
1043 -
1044 - $wgOut->addScript( Skin::makeVariablesScript( $scriptVars ) );
1045 -
1046 - // MW < 1.17
1047 - if ( ! class_exists( 'ResourceLoader' ) ) {
1048 - // For <charinsert> support; not provided by js2 yet
1049 - $wgOut->addScriptFile( 'edit.js' );
1050 -
1051 - if ( $wgEnableJS2system ) {
1052 - // JS2 upload scripts
1053 - $wgOut->addScriptClass( 'uploadPage' );
1054 - } else {
1055 - // Legacy upload javascript
1056 - $wgOut->addScriptFile( 'upload.js' );
1057 - }
1058 - }
1059 - }
1060 -
1061 - /**
1062 - * Empty function; submission is handled elsewhere.
1063 - *
1064 - * @return bool false
1065 - */
1066 - function trySubmit() {
1067 - return false;
1068 - }
1069 -
1070 -}
1071 -
1072 -/**
1073 - * A form field that contains a radio box in the label.
1074 - */
1075 -class SFUploadSourceField extends HTMLTextField {
1076 -
1077 - function getLabelHtml( $cellAttributes = array() ) {
1078 - $id = "wpSourceType{$this->mParams['upload-type']}";
1079 - $label = Html::rawElement( 'label', array( 'for' => $id ), $this->mLabel );
1080 -
1081 - if ( !empty( $this->mParams['radio'] ) ) {
1082 - $attribs = array(
1083 - 'name' => 'wpSourceType',
1084 - 'type' => 'radio',
1085 - 'id' => $id,
1086 - 'value' => $this->mParams['upload-type'],
1087 - );
1088 -
1089 - if ( !empty( $this->mParams['checked'] ) )
1090 - $attribs['checked'] = 'checked';
1091 - $label .= Html::element( 'input', $attribs );
1092 - }
1093 -
1094 - return Html::rawElement( 'td', array( 'class' => 'mw-label' ), $label );
1095 - }
1096 -
1097 - function getSize() {
1098 - return isset( $this->mParams['size'] )
1099 - ? $this->mParams['size']
1100 - : 60;
1101 - }
1102 -
1103 -}
1104 -
1105 -global $wgVersion;
1106 -$uceMethod = new ReflectionMethod( 'SpecialPage', 'userCanExecute' );
1107 -$uceParams = $uceMethod->getParameters();
1108 -// @TODO The "User" class was added to the function header
1109 -// for SpecialPage::userCanExecute in MW 1.18 (r86407) - somehow
1110 -// both the old and new signatures need to be supported. When support
1111 -// is dropped for MW below 1.18 this should be reintegrated into one
1112 -// class.
1113 -if ( $uceParams[0]->getClass() ) { // found a class definition for param $user
1114 -
1115 - /**
1116 - * Class variant for MW 1.18+
1117 - */
1118 - class SFUploadWindow2 extends SFUploadWindow2Proto {
1119 - /**
1120 - * This page can be shown if uploading is enabled.
1121 - * Handle permission checking elsewhere in order to be able to show
1122 - * custom error messages.
1123 - *
1124 - * @param User $user
1125 - * @return bool
1126 - */
1127 - public function userCanExecute( User $user ) {
1128 - return UploadBase::isEnabled() && parent::userCanExecute( $user );
1129 - }
1130 -
1131 -
1132 - }
1133 -
1134 -} else {
1135 -
1136 - /**
1137 - * Class variant for MW up to 1.17
1138 - */
1139 - class SFUploadWindow2 extends SFUploadWindow2Proto {
1140 - /**
1141 - * This page can be shown if uploading is enabled.
1142 - * Handle permission checking elsewhere in order to be able to show
1143 - * custom error messages.
1144 - *
1145 - * @param User $user
1146 - * @return bool
1147 - */
1148 - public function userCanExecute( $user ) {
1149 - return UploadBase::isEnabled() && parent::userCanExecute( $user );
1150 - }
1151 - }
1152 -
1153 -}
Index: trunk/extensions/SemanticForms/specials/SF_UploadWindow.php
@@ -0,0 +1,1152 @@
 2+<?php
 3+/**
 4+ * SFUploadWindow2 - used for uploading files from within a form, for
 5+ * MediaWiki version 1.16+.
 6+ * This class is nearly identical to MediaWiki's SpecialUpload class, with
 7+ * a few changes to remove skin CSS and HTML, and to populate the relevant
 8+ * field in the form with the name of the uploaded form.
 9+ *
 10+ * @author Yaron Koren
 11+ * @file
 12+ * @ingroup SF
 13+ */
 14+
 15+/**
 16+ * @ingroup SFSpecialPages
 17+ */
 18+class SFUploadWindow2Proto extends UnlistedSpecialPage {
 19+ /**
 20+ * Constructor : initialise object
 21+ * Get data POSTed through the form and assign them to the object
 22+ * @param WebRequest $request Data posted.
 23+ */
 24+ public function __construct( $request = null ) {
 25+ global $wgRequest;
 26+
 27+ parent::__construct( 'UploadWindow', 'upload' );
 28+
 29+ $this->loadRequest( is_null( $request ) ? $wgRequest : $request );
 30+ }
 31+
 32+ /** Misc variables **/
 33+ public $mRequest; // The WebRequest or FauxRequest this form is supposed to handle
 34+ public $mSourceType;
 35+ public $mUpload;
 36+ public $mLocalFile;
 37+ public $mUploadClicked;
 38+
 39+ /** User input variables from the "description" section **/
 40+ public $mDesiredDestName; // The requested target file name
 41+ public $mComment;
 42+ public $mLicense;
 43+
 44+ /** User input variables from the root section **/
 45+ public $mIgnoreWarning;
 46+ public $mWatchThis;
 47+ public $mCopyrightStatus;
 48+ public $mCopyrightSource;
 49+
 50+ /** Hidden variables **/
 51+ public $mForReUpload; // The user followed an "overwrite this file" link
 52+ public $mCancelUpload; // The user clicked "Cancel and return to upload form" button
 53+ public $mTokenOk;
 54+
 55+ /** used by Semantic Forms **/
 56+ public $mInputID;
 57+ public $mDelimiter;
 58+
 59+ /**
 60+ * Initialize instance variables from request and create an Upload handler
 61+ *
 62+ * @param WebRequest $request The request to extract variables from
 63+ */
 64+ protected function loadRequest( $request ) {
 65+ global $wgUser;
 66+
 67+ $this->mRequest = $request;
 68+ $this->mSourceType = $request->getVal( 'wpSourceType', 'file' );
 69+ $this->mUpload = UploadBase::createFromRequest( $request );
 70+ $this->mUploadClicked = $request->wasPosted()
 71+ && ( $request->getCheck( 'wpUpload' )
 72+ || $request->getCheck( 'wpUploadIgnoreWarning' ) );
 73+
 74+ // Guess the desired name from the filename if not provided
 75+ $this->mDesiredDestName = $request->getText( 'wpDestFile' );
 76+ if ( !$this->mDesiredDestName )
 77+ $this->mDesiredDestName = $request->getText( 'wpUploadFile' );
 78+ $this->mComment = $request->getText( 'wpUploadDescription' );
 79+ $this->mLicense = $request->getText( 'wpLicense' );
 80+
 81+
 82+ $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' );
 83+ $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' )
 84+ || $request->getCheck( 'wpUploadIgnoreWarning' );
 85+ $this->mWatchthis = $request->getBool( 'wpWatchthis' );
 86+ $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
 87+ $this->mCopyrightSource = $request->getText( 'wpUploadSource' );
 88+
 89+
 90+ $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
 91+ $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' )
 92+ || $request->getCheck( 'wpReUpload' ); // b/w compat
 93+
 94+ // If it was posted check for the token (no remote POST'ing with user credentials)
 95+ $token = $request->getVal( 'wpEditToken' );
 96+ if ( $this->mSourceType == 'file' && $token == null ) {
 97+ // Skip token check for file uploads as that can't be faked via JS...
 98+ // Some client-side tools don't expect to need to send wpEditToken
 99+ // with their submissions, as that's new in 1.16.
 100+ $this->mTokenOk = true;
 101+ } else {
 102+ $this->mTokenOk = $wgUser->matchEditToken( $token );
 103+ }
 104+ $this->mInputID = $request->getText( 'sfInputID' );
 105+ $this->mDelimiter = $request->getText( 'sfDelimiter' );
 106+ }
 107+
 108+ /**
 109+ * Special page entry point
 110+ */
 111+ public function execute( $par ) {
 112+ global $wgUser, $wgOut;
 113+ // Disable $wgOut - we'll print out the page manually, taking
 114+ // the body created by the form, plus the necessary Javascript
 115+ // files, and turning them into an HTML page.
 116+ $wgOut->disable();
 117+ // This line is needed to get around Squid caching.
 118+ $wgOut->sendCacheControl();
 119+
 120+ $this->setHeaders();
 121+ $this->outputHeader();
 122+
 123+ # Check uploading enabled
 124+ if ( !UploadBase::isEnabled() ) {
 125+ $wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext' );
 126+ print $wgOut->getHTML();
 127+ return;
 128+ }
 129+
 130+ # Check permissions
 131+ global $wgGroupPermissions;
 132+ if ( !$wgUser->isAllowed( 'upload' ) ) {
 133+ if ( !$wgUser->isLoggedIn() && ( $wgGroupPermissions['user']['upload']
 134+ || $wgGroupPermissions['autoconfirmed']['upload'] ) ) {
 135+ // Custom message if logged-in users without any special rights can upload
 136+ $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
 137+ } else {
 138+ $wgOut->permissionRequired( 'upload' );
 139+ }
 140+ print $wgOut->getHTML();
 141+ return;
 142+ }
 143+
 144+ # Check blocks
 145+ if ( $wgUser->isBlocked() ) {
 146+ $wgOut->blockedPage();
 147+ print $wgOut->getHTML();
 148+ return;
 149+ }
 150+
 151+ # Check whether we actually want to allow changing stuff
 152+ if ( wfReadOnly() ) {
 153+ $wgOut->readOnlyPage();
 154+ print $wgOut->getHTML();
 155+ return;
 156+ }
 157+
 158+ # Unsave the temporary file in case this was a cancelled upload
 159+ if ( $this->mCancelUpload ) {
 160+ if ( !$this->unsaveUploadedFile() )
 161+ # Something went wrong, so unsaveUploadedFile showed a warning
 162+ return;
 163+ }
 164+
 165+ # Process upload or show a form
 166+ if ( $this->mTokenOk && !$this->mCancelUpload
 167+ && ( $this->mUpload && $this->mUploadClicked ) ) {
 168+ $this->processUpload();
 169+ } else {
 170+ $this->showUploadForm( $this->getUploadForm() );
 171+ }
 172+
 173+ # Cleanup
 174+ if ( $this->mUpload )
 175+ $this->mUpload->cleanupTempFile();
 176+ }
 177+
 178+ /**
 179+ * Show the main upload form and optionally add the session key to the
 180+ * output. This hides the source selection.
 181+ *
 182+ * @param string $message HTML message to be shown at top of form
 183+ * @param string $sessionKey Session key of the stashed upload
 184+ */
 185+ protected function showUploadForm( $form ) {
 186+ # Add links if file was previously deleted
 187+ if ( !$this->mDesiredDestName )
 188+ $this->showViewDeletedLinks();
 189+
 190+ $form->show();
 191+ }
 192+
 193+ /**
 194+ * Get an UploadForm instance with title and text properly set.
 195+ *
 196+ * @param string $message HTML string to add to the form
 197+ * @param string $sessionKey Session key in case this is a stashed upload
 198+ * @return UploadForm
 199+ */
 200+ protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) {
 201+ global $wgOut;
 202+
 203+ # Initialize form
 204+ $form = new SFUploadForm( array(
 205+ 'watch' => $this->watchCheck(),
 206+ 'forreupload' => $this->mForReUpload,
 207+ 'sessionkey' => $sessionKey,
 208+ 'hideignorewarning' => $hideIgnoreWarning,
 209+ 'destfile' => $this->mDesiredDestName,
 210+ 'sfInputID' => $this->mInputID,
 211+ 'sfDelimiter' => $this->mDelimiter,
 212+ ) );
 213+ $form->setTitle( $this->getTitle() );
 214+
 215+ # Check the token, but only if necessary
 216+ if ( !$this->mTokenOk && !$this->mCancelUpload
 217+ && ( $this->mUpload && $this->mUploadClicked ) )
 218+ $form->addPreText( wfMsgExt( 'session_fail_preview', 'parseinline' ) );
 219+
 220+ # Add text to form
 221+ // $form->addPreText( '<div id="uploadtext">' . wfMsgExt( 'uploadtext', 'parse' ) . '</div>');
 222+ # Add upload error message
 223+ $form->addPreText( $message );
 224+
 225+ # Add footer to form
 226+ $uploadFooter = wfMsgNoTrans( 'uploadfooter' );
 227+ if ( $uploadFooter != '-' && !wfEmptyMsg( 'uploadfooter', $uploadFooter ) ) {
 228+ $form->addPostText( '<div id="mw-upload-footer-message">'
 229+ . $wgOut->parse( $uploadFooter ) . "</div>\n" );
 230+ }
 231+
 232+ return $form;
 233+
 234+ }
 235+
 236+ /**
 237+ * Shows the "view X deleted revivions link""
 238+ */
 239+ protected function showViewDeletedLinks() {
 240+ global $wgOut, $wgUser;
 241+
 242+ $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
 243+ // Show a subtitle link to deleted revisions (to sysops et al only)
 244+ if ( $title instanceof Title && ( $count = $title->isDeleted() ) > 0 && $wgUser->isAllowed( 'deletedhistory' ) ) {
 245+ $link = wfMsgExt(
 246+ $wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
 247+ array( 'parse', 'replaceafter' ),
 248+ $wgUser->getSkin()->linkKnown(
 249+ SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
 250+ wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
 251+ )
 252+ );
 253+ $wgOut->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
 254+ }
 255+
 256+ // Show the relevant lines from deletion log (for still deleted files only)
 257+ if ( $title instanceof Title && $title->isDeletedQuick() && !$title->exists() ) {
 258+ $this->showDeletionLog( $wgOut, $title->getPrefixedText() );
 259+ }
 260+ }
 261+
 262+ /**
 263+ * Stashes the upload and shows the main upload form.
 264+ *
 265+ * Note: only errors that can be handled by changing the name or
 266+ * description should be redirected here. It should be assumed that the
 267+ * file itself is sane and has passed UploadBase::verifyFile. This
 268+ * essentially means that UploadBase::VERIFICATION_ERROR and
 269+ * UploadBase::EMPTY_FILE should not be passed here.
 270+ *
 271+ * @param string $message HTML message to be passed to mainUploadForm
 272+ */
 273+ protected function recoverableUploadError( $message ) {
 274+ $sessionKey = $this->mUpload->stashSession();
 275+ $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
 276+ '<div class="error">' . $message . "</div>\n";
 277+
 278+ $form = $this->getUploadForm( $message, $sessionKey );
 279+ $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
 280+ $this->showUploadForm( $form );
 281+ }
 282+ /**
 283+ * Stashes the upload, shows the main form, but adds an "continue anyway button"
 284+ *
 285+ * @param array $warnings
 286+ */
 287+ protected function uploadWarning( $warnings ) {
 288+ $sessionKey = $this->mUpload->stashSession();
 289+
 290+ $warningHtml = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n"
 291+ . '<ul class="warning">';
 292+ foreach ( $warnings as $warning => $args ) {
 293+ $msg = '';
 294+ if ( $warning == 'exists' ) {
 295+ $msg = self::getExistsWarning( $args );
 296+ } elseif ( $warning == 'duplicate' ) {
 297+ $msg = self::getDupeWarning( $args );
 298+ } elseif ( $warning == 'duplicate-archive' ) {
 299+ $msg = "\t<li>" . wfMsgExt( 'file-deleted-duplicate', 'parseinline',
 300+ array( Title::makeTitle( NS_FILE, $args )->getPrefixedText() ) )
 301+ . "</li>\n";
 302+ } else {
 303+ if ( is_bool( $args ) )
 304+ $args = array();
 305+ elseif ( !is_array( $args ) )
 306+ $args = array( $args );
 307+ $msg = "\t<li>" . wfMsgExt( $warning, 'parseinline', $args ) . "</li>\n";
 308+ }
 309+ $warningHtml .= $msg;
 310+ }
 311+ $warningHtml .= "</ul>\n";
 312+ $warningHtml .= wfMsgExt( 'uploadwarning-text', 'parse' );
 313+
 314+ $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
 315+ $form->setSubmitText( wfMsg( 'upload-tryagain' ) );
 316+ $form->addButton( 'wpUploadIgnoreWarning', wfMsg( 'ignorewarning' ) );
 317+ $form->addButton( 'wpCancelUpload', wfMsg( 'reuploaddesc' ) );
 318+
 319+ $this->showUploadForm( $form );
 320+ }
 321+
 322+ /**
 323+ * Show the upload form with error message, but do not stash the file.
 324+ *
 325+ * @param string $message
 326+ */
 327+ protected function uploadError( $message ) {
 328+ $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
 329+ '<div class="error">' . $message . "</div>\n";
 330+ $this->showUploadForm( $this->getUploadForm( $message ) );
 331+ }
 332+
 333+ /**
 334+ * Do the upload.
 335+ * Checks are made in SpecialUpload::execute()
 336+ */
 337+ protected function processUpload() {
 338+ global $wgUser, $wgOut;
 339+
 340+ // Verify permissions
 341+ $permErrors = $this->mUpload->verifyPermissions( $wgUser );
 342+ if ( $permErrors !== true )
 343+ return $wgOut->showPermissionsErrorPage( $permErrors );
 344+
 345+ // Fetch the file if required
 346+ $status = $this->mUpload->fetchFile();
 347+ if ( !$status->isOK() )
 348+ return $this->showUploadForm( $this->getUploadForm( $wgOut->parse( $status->getWikiText() ) ) );
 349+
 350+ // Upload verification
 351+ $details = $this->mUpload->verifyUpload();
 352+ if ( $details['status'] != UploadBase::OK )
 353+ return $this->processVerificationError( $details );
 354+
 355+ $this->mLocalFile = $this->mUpload->getLocalFile();
 356+
 357+ // Check warnings if necessary
 358+ if ( !$this->mIgnoreWarning ) {
 359+ $warnings = $this->mUpload->checkWarnings();
 360+ if ( count( $warnings ) )
 361+ return $this->uploadWarning( $warnings );
 362+ }
 363+
 364+ // Get the page text if this is not a reupload
 365+ if ( !$this->mForReUpload ) {
 366+ $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
 367+ $this->mCopyrightStatus, $this->mCopyrightSource );
 368+ } else {
 369+ $pageText = false;
 370+ }
 371+ $status = $this->mUpload->performUpload( $this->mComment, $pageText, $this->mWatchthis, $wgUser );
 372+ if ( !$status->isGood() )
 373+ return $this->uploadError( $wgOut->parse( $status->getWikiText() ) );
 374+
 375+ // $wgOut->redirect( $this->mLocalFile->getTitle()->getFullURL() );
 376+ // Semantic Forms change - output Javascript to either
 377+ // fill in or append to the field in original form, and
 378+ // close the window
 379+ # Chop off any directories in the given filename
 380+ if ( $this->mDesiredDestName ) {
 381+ $basename = $this->mDesiredDestName;
 382+ } else {
 383+ $basename = $this->mSrcName;
 384+ }
 385+
 386+ $basename = str_replace( '_', ' ', $basename );
 387+ // UTF8-decoding is needed for IE
 388+ $basename = utf8_decode( $basename );
 389+
 390+ $output .= <<<END
 391+ <script type="text/javascript">
 392+ var input = parent.window.jQuery( parent.document.getElementById("{$this->mInputID}") );
 393+END;
 394+
 395+ if ( $this->mDelimiter == null ) {
 396+ $output .= <<<END
 397+ input.val( '$basename' );
 398+ input.change();
 399+END;
 400+ } else {
 401+ $output .= <<<END
 402+ // if the current value is blank, set it to this file name;
 403+ // if it's not blank and ends in a space or delimiter, append
 404+ // the file name; if it ends with a normal character, append
 405+ // both a delimiter and a file name; and add on a delimiter
 406+ // at the end in any case
 407+ var cur_value = parent.document.getElementById("{$this->mInputID}").value;
 408+
 409+ if (cur_value === '') {
 410+ input.val( '$basename' + '{$this->mDelimiter} ' );
 411+ input.change();
 412+ } else {
 413+ var last_char = cur_value.charAt(cur_value.length - 1);
 414+ if (last_char == '{$this->mDelimiter}' || last_char == ' ') {
 415+ parent.document.getElementById("{$this->mInputID}").value += '$basename' + '{$this->mDelimiter} ';
 416+ input.change();
 417+ } else {
 418+ parent.document.getElementById("{$this->mInputID}").value += '{$this->mDelimiter} $basename{$this->mDelimiter} ';
 419+ input.change();
 420+ }
 421+ }
 422+
 423+END;
 424+ }
 425+ $output .= <<<END
 426+ parent.jQuery.fancybox.close();
 427+ </script>
 428+
 429+END;
 430+ // $wgOut->addHTML( $output );
 431+ print $output;
 432+ $img = null; // @todo: added to avoid passing a ref to null - should this be defined somewhere?
 433+
 434+ wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
 435+ }
 436+
 437+ /**
 438+ * Get the initial image page text based on a comment and optional file status information
 439+ */
 440+ public static function getInitialPageText( $comment = '', $license = '', $copyStatus = '', $source = '' ) {
 441+ global $wgUseCopyrightUpload;
 442+ if ( $wgUseCopyrightUpload ) {
 443+ $licensetxt = '';
 444+ if ( $license !== '' ) {
 445+ $licensetxt = '== ' . wfMsgForContent( 'license-header' ) . " ==\n" . '{{' . $license . '}}' . "\n";
 446+ }
 447+ $pageText = '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n" .
 448+ '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" .
 449+ "$licensetxt" .
 450+ '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ;
 451+ } else {
 452+ if ( $license !== '' ) {
 453+ $filedesc = $comment === '' ? '' : '== ' . wfMsgForContent ( 'filedesc' ) . " ==\n" . $comment . "\n";
 454+ $pageText = $filedesc .
 455+ '== ' . wfMsgForContent ( 'license-header' ) . " ==\n" . '{{' . $license . '}}' . "\n";
 456+ } else {
 457+ $pageText = $comment;
 458+ }
 459+ }
 460+ return $pageText;
 461+ }
 462+
 463+ /**
 464+ * See if we should check the 'watch this page' checkbox on the form
 465+ * based on the user's preferences and whether we're being asked
 466+ * to create a new file or update an existing one.
 467+ *
 468+ * In the case where 'watch edits' is off but 'watch creations' is on,
 469+ * we'll leave the box unchecked.
 470+ *
 471+ * Note that the page target can be changed *on the form*, so our check
 472+ * state can get out of sync.
 473+ */
 474+ protected function watchCheck() {
 475+ global $wgUser;
 476+ if ( $wgUser->getOption( 'watchdefault' ) ) {
 477+ // Watch all edits!
 478+ return true;
 479+ }
 480+
 481+ $local = wfLocalFile( $this->mDesiredDestName );
 482+ if ( $local && $local->exists() ) {
 483+ // We're uploading a new version of an existing file.
 484+ // No creation, so don't watch it if we're not already.
 485+ return $local->getTitle()->userIsWatching();
 486+ } else {
 487+ // New page should get watched if that's our option.
 488+ return $wgUser->getOption( 'watchcreations' );
 489+ }
 490+ }
 491+
 492+
 493+ /**
 494+ * Provides output to the user for a result of UploadBase::verifyUpload
 495+ *
 496+ * @param array $details Result of UploadBase::verifyUpload
 497+ */
 498+ protected function processVerificationError( $details ) {
 499+ global $wgFileExtensions, $wgLang;
 500+
 501+ switch( $details['status'] ) {
 502+
 503+ /** Statuses that only require name changing **/
 504+ case UploadBase::MIN_LENGTH_PARTNAME:
 505+ $this->recoverableUploadError( wfMsgHtml( 'minlength1' ) );
 506+ break;
 507+ case UploadBase::ILLEGAL_FILENAME:
 508+ $this->recoverableUploadError( wfMsgExt( 'illegalfilename',
 509+ 'parseinline', $details['filtered'] ) );
 510+ break;
 511+ case UploadBase::OVERWRITE_EXISTING_FILE:
 512+ $this->recoverableUploadError( wfMsgExt( $details['overwrite'],
 513+ 'parseinline' ) );
 514+ break;
 515+ case UploadBase::FILETYPE_MISSING:
 516+ $this->recoverableUploadError( wfMsgExt( 'filetype-missing',
 517+ 'parseinline' ) );
 518+ break;
 519+
 520+ /** Statuses that require reuploading **/
 521+ case UploadBase::EMPTY_FILE:
 522+ $this->showUploadForm( $this->getUploadForm( wfMsgHtml( 'emptyfile' ) ) );
 523+ break;
 524+ case UploadBase::FILETYPE_BADTYPE:
 525+ $finalExt = $details['finalExt'];
 526+ $this->uploadError(
 527+ wfMsgExt( 'filetype-banned-type',
 528+ array( 'parseinline' ),
 529+ htmlspecialchars( $finalExt ),
 530+ implode(
 531+ wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
 532+ $wgFileExtensions
 533+ ),
 534+ $wgLang->formatNum( count( $wgFileExtensions ) )
 535+ )
 536+ );
 537+ break;
 538+ case UploadBase::VERIFICATION_ERROR:
 539+ unset( $details['status'] );
 540+ $code = array_shift( $details['details'] );
 541+ $this->uploadError( wfMsgExt( $code, 'parseinline', $details['details'] ) );
 542+ break;
 543+ case UploadBase::HOOK_ABORTED:
 544+ $error = $details['error'];
 545+ $this->uploadError( wfMsgExt( $error, 'parseinline' ) );
 546+ break;
 547+ default:
 548+ throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
 549+ }
 550+ }
 551+
 552+ /**
 553+ * Remove a temporarily kept file stashed by saveTempUploadedFile().
 554+ * @access private
 555+ * @return success
 556+ */
 557+ protected function unsaveUploadedFile() {
 558+ global $wgOut;
 559+ if ( !( $this->mUpload instanceof UploadFromStash ) )
 560+ return true;
 561+ $success = $this->mUpload->unsaveUploadedFile();
 562+ if ( ! $success ) {
 563+ $wgOut->showFileDeleteError( $this->mUpload->getTempPath() );
 564+ return false;
 565+ } else {
 566+ return true;
 567+ }
 568+ }
 569+
 570+ /*** Functions for formatting warnings ***/
 571+
 572+ /**
 573+ * Formats a result of UploadBase::getExistsWarning as HTML
 574+ * This check is static and can be done pre-upload via AJAX
 575+ *
 576+ * @param array $exists The result of UploadBase::getExistsWarning
 577+ * @return string Empty string if there is no warning or an HTML fragment
 578+ * consisting of one or more <li> elements if there is a warning.
 579+ */
 580+ public static function getExistsWarning( $exists ) {
 581+ global $wgUser;
 582+
 583+ if ( !$exists )
 584+ return '';
 585+
 586+ $file = $exists['file'];
 587+ $filename = $file->getTitle()->getPrefixedText();
 588+ $warning = array();
 589+
 590+ $sk = $wgUser->getSkin();
 591+
 592+ if ( $exists['warning'] == 'exists' ) {
 593+ // Exact match
 594+ $warning[] = '<li>' . wfMsgExt( 'fileexists', 'parseinline', $filename ) . '</li>';
 595+ } elseif ( $exists['warning'] == 'page-exists' ) {
 596+ // Page exists but file does not
 597+ $warning[] = '<li>' . wfMsgExt( 'filepageexists', 'parseinline', $filename ) . '</li>';
 598+ } elseif ( $exists['warning'] == 'exists-normalized' ) {
 599+ $warning[] = '<li>' . wfMsgExt( 'fileexists-extension', 'parseinline', $filename,
 600+ $exists['normalizedFile']->getTitle()->getPrefixedText() ) . '</li>';
 601+ } elseif ( $exists['warning'] == 'thumb' ) {
 602+ // Swapped argument order compared with other messages for backwards compatibility
 603+ $warning[] = '<li>' . wfMsgExt( 'fileexists-thumbnail-yes', 'parseinline',
 604+ $exists['thumbFile']->getTitle()->getPrefixedText(), $filename ) . '</li>';
 605+ } elseif ( $exists['warning'] == 'thumb-name' ) {
 606+ // Image w/o '180px-' does not exists, but we do not like these filenames
 607+ $name = $file->getName();
 608+ $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
 609+ $warning[] = '<li>' . wfMsgExt( 'file-thumbnail-no', 'parseinline', $badPart ) . '</li>';
 610+ } elseif ( $exists['warning'] == 'bad-prefix' ) {
 611+ $warning[] = '<li>' . wfMsgExt( 'filename-bad-prefix', 'parseinline', $exists['prefix'] ) . '</li>';
 612+ } elseif ( $exists['warning'] == 'was-deleted' ) {
 613+ # If the file existed before and was deleted, warn the user of this
 614+ $ltitle = SpecialPage::getTitleFor( 'Log' );
 615+ $llink = $sk->linkKnown(
 616+ $ltitle,
 617+ wfMsgHtml( 'deletionlog' ),
 618+ array(),
 619+ array(
 620+ 'type' => 'delete',
 621+ 'page' => $filename
 622+ )
 623+ );
 624+ $warning[] = '<li>' . wfMsgWikiHtml( 'filewasdeleted', $llink ) . '</li>';
 625+ }
 626+
 627+ return implode( "\n", $warning );
 628+ }
 629+
 630+ /**
 631+ * Get a list of warnings
 632+ *
 633+ * @param string local filename, e.g. 'file exists', 'non-descriptive filename'
 634+ * @return array list of warning messages
 635+ */
 636+ public static function ajaxGetExistsWarning( $filename ) {
 637+ $file = wfFindFile( $filename );
 638+ if ( !$file ) {
 639+ // Force local file so we have an object to do further checks against
 640+ // if there isn't an exact match...
 641+ $file = wfLocalFile( $filename );
 642+ }
 643+ $s = '&#160;';
 644+ if ( $file ) {
 645+ $exists = UploadBase::getExistsWarning( $file );
 646+ $warning = self::getExistsWarning( $exists );
 647+ if ( $warning !== '' ) {
 648+ $s = "<ul>$warning</ul>";
 649+ }
 650+ }
 651+ return $s;
 652+ }
 653+
 654+ /**
 655+ * Render a preview of a given license for the AJAX preview on upload
 656+ *
 657+ * @param string $license
 658+ * @return string
 659+ */
 660+ public static function ajaxGetLicensePreview( $license ) {
 661+ global $wgParser, $wgUser;
 662+ $text = '{{' . $license . '}}';
 663+ $title = Title::makeTitle( NS_FILE, 'Sample.jpg' );
 664+ $options = ParserOptions::newFromUser( $wgUser );
 665+
 666+ // Expand subst: first, then live templates...
 667+ $text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options );
 668+ $output = $wgParser->parse( $text, $title, $options );
 669+
 670+ return $output->getText();
 671+ }
 672+
 673+ /**
 674+ * Construct a warning and a gallery from an array of duplicate files.
 675+ */
 676+ public static function getDupeWarning( $dupes ) {
 677+ if ( $dupes ) {
 678+ global $wgOut;
 679+ $msg = "<gallery>";
 680+ foreach ( $dupes as $file ) {
 681+ $title = $file->getTitle();
 682+ $msg .= $title->getPrefixedText() .
 683+ "|" . $title->getText() . "\n";
 684+ }
 685+ $msg .= "</gallery>";
 686+ return "<li>" .
 687+ wfMsgExt( "file-exists-duplicate", array( "parse" ), count( $dupes ) ) .
 688+ $wgOut->parse( $msg ) .
 689+ "</li>\n";
 690+ } else {
 691+ return '';
 692+ }
 693+ }
 694+
 695+}
 696+
 697+/**
 698+ * Sub class of HTMLForm that provides the form section of SpecialUpload
 699+ */
 700+class SFUploadForm extends HTMLForm {
 701+ protected $mWatch;
 702+ protected $mForReUpload;
 703+ protected $mSessionKey;
 704+ protected $mHideIgnoreWarning;
 705+ protected $mDestWarningAck;
 706+
 707+ protected $mSourceIds;
 708+
 709+ public function __construct( $options = array() ) {
 710+ $this->mWatch = !empty( $options['watch'] );
 711+ $this->mForReUpload = !empty( $options['forreupload'] );
 712+ $this->mSessionKey = isset( $options['sessionkey'] )
 713+ ? $options['sessionkey'] : '';
 714+ $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] );
 715+ $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : '';
 716+
 717+ $sourceDescriptor = $this->getSourceSection();
 718+ $descriptor = $sourceDescriptor
 719+ + $this->getDescriptionSection()
 720+ + $this->getOptionsSection();
 721+
 722+ wfRunHooks( 'UploadFormInitDescriptor', array( $descriptor ) );
 723+ parent::__construct( $descriptor, 'upload' );
 724+
 725+ # Set some form properties
 726+ $this->setSubmitText( wfMsg( 'uploadbtn' ) );
 727+ $this->setSubmitName( 'wpUpload' );
 728+ $this->setSubmitTooltip( 'upload' );
 729+ $this->setId( 'mw-upload-form' );
 730+
 731+ # Build a list of IDs for javascript insertion
 732+ $this->mSourceIds = array();
 733+ foreach ( $sourceDescriptor as $key => $field ) {
 734+ if ( !empty( $field['id'] ) )
 735+ $this->mSourceIds[] = $field['id'];
 736+ }
 737+ // added for Semantic Forms
 738+ $this->addHiddenField( 'sfInputID', $options['sfInputID'] );
 739+ $this->addHiddenField( 'sfDelimiter', $options['sfDelimiter'] );
 740+
 741+ }
 742+
 743+ /**
 744+ * Get the descriptor of the fieldset that contains the file source
 745+ * selection. The section is 'source'
 746+ *
 747+ * @return array Descriptor array
 748+ */
 749+ protected function getSourceSection() {
 750+ global $wgLang, $wgUser, $wgRequest;
 751+
 752+ if ( $this->mSessionKey ) {
 753+ return array(
 754+ 'wpSessionKey' => array(
 755+ 'type' => 'hidden',
 756+ 'default' => $this->mSessionKey,
 757+ ),
 758+ 'wpSourceType' => array(
 759+ 'type' => 'hidden',
 760+ 'default' => 'Stash',
 761+ ),
 762+ );
 763+ }
 764+
 765+ $canUploadByUrl = UploadFromUrl::isEnabled() && $wgUser->isAllowed( 'upload_by_url' );
 766+ $radio = $canUploadByUrl;
 767+ $selectedSourceType = strtolower( $wgRequest->getText( 'wpSourceType', 'File' ) );
 768+
 769+ $descriptor = array();
 770+ $descriptor['UploadFile'] = array(
 771+ 'class' => 'SFUploadSourceField',
 772+ 'section' => 'source',
 773+ 'type' => 'file',
 774+ 'id' => 'wpUploadFile',
 775+ 'label-message' => 'sourcefilename',
 776+ 'upload-type' => 'File',
 777+ 'radio' => &$radio,
 778+ 'help' => wfMsgExt( 'upload-maxfilesize',
 779+ array( 'parseinline', 'escapenoentities' ),
 780+ $wgLang->formatSize(
 781+ wfShorthandToInteger( ini_get( 'upload_max_filesize' ) )
 782+ )
 783+ ) . ' ' . wfMsgHtml( 'upload_source_file' ),
 784+ 'checked' => $selectedSourceType == 'file',
 785+ );
 786+ if ( $canUploadByUrl ) {
 787+ global $wgMaxUploadSize;
 788+ $descriptor['UploadFileURL'] = array(
 789+ 'class' => 'SFUploadSourceField',
 790+ 'section' => 'source',
 791+ 'id' => 'wpUploadFileURL',
 792+ 'label-message' => 'sourceurl',
 793+ 'upload-type' => 'Url',
 794+ 'radio' => &$radio,
 795+ 'help' => wfMsgExt( 'upload-maxfilesize',
 796+ array( 'parseinline', 'escapenoentities' ),
 797+ $wgLang->formatSize( $wgMaxUploadSize )
 798+ ) . ' ' . wfMsgHtml( 'upload_source_url' ),
 799+ 'checked' => $selectedSourceType == 'url',
 800+ );
 801+ }
 802+ wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
 803+
 804+ $descriptor['Extensions'] = array(
 805+ 'type' => 'info',
 806+ 'section' => 'source',
 807+ 'default' => $this->getExtensionsMessage(),
 808+ 'raw' => true,
 809+ );
 810+ return $descriptor;
 811+ }
 812+
 813+
 814+ /**
 815+ * Get the messages indicating which extensions are preferred and prohibitted.
 816+ *
 817+ * @return string HTML string containing the message
 818+ */
 819+ protected function getExtensionsMessage() {
 820+ # Print a list of allowed file extensions, if so configured. We ignore
 821+ # MIME type here, it's incomprehensible to most people and too long.
 822+ global $wgLang, $wgCheckFileExtensions, $wgStrictFileExtensions,
 823+ $wgFileExtensions, $wgFileBlacklist;
 824+
 825+ $allowedExtensions = '';
 826+ if ( $wgCheckFileExtensions ) {
 827+ if ( $wgStrictFileExtensions ) {
 828+ # Everything not permitted is banned
 829+ $extensionsList =
 830+ '<div id="mw-upload-permitted">' .
 831+ wfMsgWikiHtml( 'upload-permitted', $wgLang->commaList( $wgFileExtensions ) ) .
 832+ "</div>\n";
 833+ } else {
 834+ # We have to list both preferred and prohibited
 835+ $extensionsList =
 836+ '<div id="mw-upload-preferred">' .
 837+ wfMsgWikiHtml( 'upload-preferred', $wgLang->commaList( $wgFileExtensions ) ) .
 838+ "</div>\n" .
 839+ '<div id="mw-upload-prohibited">' .
 840+ wfMsgWikiHtml( 'upload-prohibited', $wgLang->commaList( $wgFileBlacklist ) ) .
 841+ "</div>\n";
 842+ }
 843+ } else {
 844+ # Everything is permitted.
 845+ $extensionsList = '';
 846+ }
 847+ return $extensionsList;
 848+ }
 849+
 850+ /**
 851+ * Get the descriptor of the fieldset that contains the file description
 852+ * input. The section is 'description'
 853+ *
 854+ * @return array Descriptor array
 855+ */
 856+ protected function getDescriptionSection() {
 857+ global $wgUser, $wgOut;
 858+
 859+ $cols = intval( $wgUser->getOption( 'cols' ) );
 860+ if ( $wgUser->getOption( 'editwidth' ) ) {
 861+ $wgOut->addInlineStyle( '#mw-htmlform-description { width: 100%; }' );
 862+ }
 863+
 864+ $descriptor = array(
 865+ 'DestFile' => array(
 866+ 'type' => 'text',
 867+ 'section' => 'description',
 868+ 'id' => 'wpDestFile',
 869+ 'label-message' => 'destfilename',
 870+ 'size' => 60,
 871+ ),
 872+ 'UploadDescription' => array(
 873+ 'type' => 'textarea',
 874+ 'section' => 'description',
 875+ 'id' => 'wpUploadDescription',
 876+ 'label-message' => $this->mForReUpload
 877+ ? 'filereuploadsummary'
 878+ : 'fileuploadsummary',
 879+ 'cols' => $cols,
 880+ 'rows' => 4,
 881+ ),
 882+/*
 883+ 'EditTools' => array(
 884+ 'type' => 'edittools',
 885+ 'section' => 'description',
 886+ ),
 887+*/
 888+ 'License' => array(
 889+ 'type' => 'select',
 890+ 'class' => 'Licenses',
 891+ 'section' => 'description',
 892+ 'id' => 'wpLicense',
 893+ 'label-message' => 'license',
 894+ ),
 895+ );
 896+ if ( $this->mForReUpload )
 897+ $descriptor['DestFile']['readonly'] = true;
 898+
 899+ global $wgUseCopyrightUpload;
 900+ if ( $wgUseCopyrightUpload ) {
 901+ $descriptor['UploadCopyStatus'] = array(
 902+ 'type' => 'text',
 903+ 'section' => 'description',
 904+ 'id' => 'wpUploadCopyStatus',
 905+ 'label-message' => 'filestatus',
 906+ );
 907+ $descriptor['UploadSource'] = array(
 908+ 'type' => 'text',
 909+ 'section' => 'description',
 910+ 'id' => 'wpUploadSource',
 911+ 'label-message' => 'filesource',
 912+ );
 913+ }
 914+
 915+ return $descriptor;
 916+ }
 917+
 918+ /**
 919+ * Get the descriptor of the fieldset that contains the upload options,
 920+ * such as "watch this file". The section is 'options'
 921+ *
 922+ * @return array Descriptor array
 923+ */
 924+ protected function getOptionsSection() {
 925+ $descriptor = array(
 926+ 'Watchthis' => array(
 927+ 'type' => 'check',
 928+ 'id' => 'wpWatchthis',
 929+ 'label-message' => 'watchthisupload',
 930+ 'section' => 'options',
 931+ )
 932+ );
 933+ if ( !$this->mHideIgnoreWarning ) {
 934+ $descriptor['IgnoreWarning'] = array(
 935+ 'type' => 'check',
 936+ 'id' => 'wpIgnoreWarning',
 937+ 'label-message' => 'ignorewarnings',
 938+ 'section' => 'options',
 939+ );
 940+ }
 941+ $descriptor['DestFileWarningAck'] = array(
 942+ 'type' => 'hidden',
 943+ 'id' => 'wpDestFileWarningAck',
 944+ 'default' => $this->mDestWarningAck ? '1' : '',
 945+ );
 946+
 947+
 948+ return $descriptor;
 949+
 950+ }
 951+
 952+ /**
 953+ * Add the upload JS and show the form.
 954+ */
 955+ public function show() {
 956+ $this->addUploadJS();
 957+ parent::show();
 958+ // disable $wgOut - we'll print out the page manually,
 959+ // taking the body created by the form, plus the necessary
 960+ // Javascript files, and turning them into an HTML page
 961+ global $wgOut, $wgUser, $wgTitle, $wgLanguageCode,
 962+ $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces, $wgContLang;
 963+
 964+ $wgOut->disable();
 965+ $sk = $wgUser->getSkin();
 966+ $sk->initPage( $wgOut ); // need to call this to set skin name correctly
 967+ $wgTitle = SpecialPage::getTitleFor( 'Upload' );
 968+
 969+ if ( method_exists( $wgOut, 'addModules' ) ) {
 970+ $wgOut->addModules( array( 'mediawiki.action.edit', 'mediawiki.legacy.upload', 'mediawiki.legacy.wikibits', 'mediawiki.legacy.ajax' ) );
 971+ // Method was added in MW 1.18
 972+ if ( method_exists( $wgOut, 'getBottomScripts' ) ) {
 973+ $head_scripts = $wgOut->getHeadScripts( $sk );
 974+ $body_scripts = $wgOut->getBottomScripts( $sk );
 975+ } else {
 976+ $head_scripts = '';
 977+ $body_scripts = $wgOut->getHeadScripts( $sk );
 978+ }
 979+ } else {
 980+ global $wgJsMimeType, $wgStylePath, $wgStyleVersion;
 981+ $vars_js = Skin::makeGlobalVariablesScript( array( 'skinname' => $sk->getSkinName() ) );
 982+ $head_scripts = <<<END
 983+$vars_js
 984+<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/wikibits.js?$wgStyleVersion"></script>
 985+{$wgOut->getScript()}
 986+<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/ajax.js?$wgStyleVersion"></script>
 987+<script type="{$wgJsMimeType}" src="{$wgStylePath}/common/ajaxwatch.js?$wgStyleVersion"></script>
 988+
 989+END;
 990+ $body_scripts = '';
 991+ }
 992+
 993+ $text = <<<END
 994+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 995+<html xmlns="{$wgXhtmlDefaultNamespace}"
 996+END;
 997+ foreach ( $wgXhtmlNamespaces as $tag => $ns ) {
 998+ $text .= "xmlns:{$tag}=\"{$ns}\" ";
 999+ }
 1000+ $dir = $wgContLang->isRTL() ? "rtl" : "ltr";
 1001+ $text .= "xml:lang=\"{$wgLanguageCode}\" lang=\"{$wgLanguageCode}\" dir=\"{$dir}\">";
 1002+
 1003+ $text .= <<<END
 1004+
 1005+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 1006+<head>
 1007+$head_scripts
 1008+</head>
 1009+<body>
 1010+{$wgOut->getHTML()}
 1011+$body_scripts
 1012+</body>
 1013+</html>
 1014+
 1015+
 1016+END;
 1017+ print $text;
 1018+ }
 1019+
 1020+ /**
 1021+ * Add upload JS to $wgOut
 1022+ *
 1023+ * @param bool $autofill Whether or not to autofill the destination
 1024+ * filename text box
 1025+ */
 1026+ protected function addUploadJS( $autofill = true ) {
 1027+ global $wgUseAjax, $wgAjaxUploadDestCheck, $wgAjaxLicensePreview;
 1028+ global $wgStrictFileExtensions;
 1029+ global $wgEnableJS2system;
 1030+ global $wgOut;
 1031+
 1032+ $scriptVars = array(
 1033+ 'wgAjaxUploadDestCheck' => $wgUseAjax && $wgAjaxUploadDestCheck,
 1034+ 'wgAjaxLicensePreview' => $wgUseAjax && $wgAjaxLicensePreview,
 1035+ 'wgUploadAutoFill' => (bool)$autofill &&
 1036+ // If we received mDestFile from the request, don't autofill
 1037+ // the wpDestFile textbox
 1038+ $this->mDestFile === '',
 1039+ 'wgUploadSourceIds' => $this->mSourceIds,
 1040+ 'wgStrictFileExtensions' => $wgStrictFileExtensions,
 1041+ 'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ),
 1042+ );
 1043+
 1044+ $wgOut->addScript( Skin::makeVariablesScript( $scriptVars ) );
 1045+
 1046+ // MW < 1.17
 1047+ if ( ! class_exists( 'ResourceLoader' ) ) {
 1048+ // For <charinsert> support; not provided by js2 yet
 1049+ $wgOut->addScriptFile( 'edit.js' );
 1050+
 1051+ if ( $wgEnableJS2system ) {
 1052+ // JS2 upload scripts
 1053+ $wgOut->addScriptClass( 'uploadPage' );
 1054+ } else {
 1055+ // Legacy upload javascript
 1056+ $wgOut->addScriptFile( 'upload.js' );
 1057+ }
 1058+ }
 1059+ }
 1060+
 1061+ /**
 1062+ * Empty function; submission is handled elsewhere.
 1063+ *
 1064+ * @return bool false
 1065+ */
 1066+ function trySubmit() {
 1067+ return false;
 1068+ }
 1069+
 1070+}
 1071+
 1072+/**
 1073+ * A form field that contains a radio box in the label.
 1074+ */
 1075+class SFUploadSourceField extends HTMLTextField {
 1076+
 1077+ function getLabelHtml( $cellAttributes = array() ) {
 1078+ $id = "wpSourceType{$this->mParams['upload-type']}";
 1079+ $label = Html::rawElement( 'label', array( 'for' => $id ), $this->mLabel );
 1080+
 1081+ if ( !empty( $this->mParams['radio'] ) ) {
 1082+ $attribs = array(
 1083+ 'name' => 'wpSourceType',
 1084+ 'type' => 'radio',
 1085+ 'id' => $id,
 1086+ 'value' => $this->mParams['upload-type'],
 1087+ );
 1088+
 1089+ if ( !empty( $this->mParams['checked'] ) )
 1090+ $attribs['checked'] = 'checked';
 1091+ $label .= Html::element( 'input', $attribs );
 1092+ }
 1093+
 1094+ return Html::rawElement( 'td', array( 'class' => 'mw-label' ), $label );
 1095+ }
 1096+
 1097+ function getSize() {
 1098+ return isset( $this->mParams['size'] )
 1099+ ? $this->mParams['size']
 1100+ : 60;
 1101+ }
 1102+
 1103+}
 1104+
 1105+global $wgVersion;
 1106+$uceMethod = new ReflectionMethod( 'SpecialPage', 'userCanExecute' );
 1107+$uceParams = $uceMethod->getParameters();
 1108+// @TODO The "User" class was added to the function header
 1109+// for SpecialPage::userCanExecute in MW 1.18 (r86407) - somehow
 1110+// both the old and new signatures need to be supported. When support
 1111+// is dropped for MW below 1.18 this should be reintegrated into one
 1112+// class.
 1113+if ( $uceParams[0]->getClass() ) { // found a class definition for param $user
 1114+
 1115+ /**
 1116+ * Class variant for MW 1.18+
 1117+ */
 1118+ class SFUploadWindow2 extends SFUploadWindow2Proto {
 1119+ /**
 1120+ * This page can be shown if uploading is enabled.
 1121+ * Handle permission checking elsewhere in order to be able to show
 1122+ * custom error messages.
 1123+ *
 1124+ * @param User $user
 1125+ * @return bool
 1126+ */
 1127+ public function userCanExecute( User $user ) {
 1128+ return UploadBase::isEnabled() && parent::userCanExecute( $user );
 1129+ }
 1130+
 1131+
 1132+ }
 1133+
 1134+} else {
 1135+
 1136+ /**
 1137+ * Class variant for MW up to 1.17
 1138+ */
 1139+ class SFUploadWindow2 extends SFUploadWindow2Proto {
 1140+ /**
 1141+ * This page can be shown if uploading is enabled.
 1142+ * Handle permission checking elsewhere in order to be able to show
 1143+ * custom error messages.
 1144+ *
 1145+ * @param User $user
 1146+ * @return bool
 1147+ */
 1148+ public function userCanExecute( $user ) {
 1149+ return UploadBase::isEnabled() && parent::userCanExecute( $user );
 1150+ }
 1151+ }
 1152+
 1153+}
Property changes on: trunk/extensions/SemanticForms/specials/SF_UploadWindow.php
___________________________________________________________________
Added: svn:eol-style
11154 + native

Status & tagging log