r64403 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r64402‎ | r64403 | r64404 >
Date:19:10, 30 March 2010
Author:mah
Status:resolved (Comments)
Tags:
Comment:
* Set $titleObj to null by default on getWatchlistValue since it often isn't needed & check that it is set when it is needed. (follow up r64197).
* Refactoring ApiUpload & UploadBase to make it easier to extend & read.
* Use a class constant for the upload session key instead of a hard-coded-across-several-files value.
* Add UploadBase::appendToUploadFile() method to enable protocols that do incremental upload.
Modified paths:
  • /trunk/phase3/includes/api/ApiBase.php (modified) (history)
  • /trunk/phase3/includes/api/ApiUpload.php (modified) (history)
  • /trunk/phase3/includes/upload/UploadBase.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/upload/UploadBase.php
@@ -33,7 +33,12 @@
3434 const HOOK_ABORTED = 11;
3535
3636 const SESSION_VERSION = 2;
 37+ const SESSION_KEYNAME = 'wsUploadData';
3738
 39+ static public function getSessionKeyname() {
 40+ return self::SESSION_KEYNAME;
 41+ }
 42+
3843 /**
3944 * Returns true if uploads are enabled.
4045 * Can be override by subclasses.
@@ -143,13 +148,35 @@
144149 }
145150
146151 /**
147 - * Return the file size
 152+ * Return true if the file is empty
 153+ * @return bool
148154 */
149155 public function isEmptyFile() {
150156 return empty( $this->mFileSize );
151157 }
152158
153159 /**
 160+ * Return the file size
 161+ * @return integer
 162+ */
 163+ public function getFileSize() {
 164+ return $this->mFileSize;
 165+ }
 166+
 167+ /**
 168+ * Append a file to the Repo file
 169+ *
 170+ * @param string $srcPath Path to source file
 171+ * @param string $toAppendPath Path to the Repo file that will be appended to.
 172+ * @return Status Status
 173+ */
 174+ protected function appendToUploadFile( $srcPath, $toAppendPath ) {
 175+ $repo = RepoGroup::singleton()->getLocalRepo();
 176+ $status = $repo->append( $srcPath, $toAppendPath );
 177+ return $status;
 178+ }
 179+
 180+ /**
154181 * @param $srcPath String: the source path
155182 * @return the real path if it was a virtual URL
156183 */
@@ -163,9 +190,9 @@
164191
165192 /**
166193 * Verify whether the upload is sane.
167 - * Returns self::OK or else an array with error information
 194+ * @return mixed self::OK or else an array with error information
168195 */
169 - public function verifyUpload() {
 196+ public function verifyUpload( ) {
170197 /**
171198 * If there was no filename or a zero size given, give up quick.
172199 */
@@ -189,6 +216,31 @@
190217 );
191218 }
192219
 220+ /**
 221+ * Make sure this file can be created
 222+ */
 223+ $result = $this->validateNameAndOverwrite();
 224+ if( $result !== true ) {
 225+ return $result;
 226+ }
 227+
 228+ $error = '';
 229+ if( !wfRunHooks( 'UploadVerification',
 230+ array( $this->mDestName, $this->mTempPath, &$error ) ) ) {
 231+ // @fixme This status needs another name...
 232+ return array( 'status' => self::HOOK_ABORTED, 'error' => $error );
 233+ }
 234+
 235+ return array( 'status' => self::OK );
 236+ }
 237+
 238+ /**
 239+ * Verify that the name is valid and, if necessary, that we can overwrite
 240+ *
 241+ * @return mixed true if valid, otherwise and array with 'status'
 242+ * and other keys
 243+ **/
 244+ public function validateNameAndOverwrite() {
193245 $nt = $this->getTitle();
194246 if( is_null( $nt ) ) {
195247 $result = array( 'status' => $this->mTitleError );
@@ -212,15 +264,7 @@
213265 'overwrite' => $overwrite
214266 );
215267 }
216 -
217 - $error = '';
218 - if( !wfRunHooks( 'UploadVerification',
219 - array( $this->mDestName, $this->mTempPath, &$error ) ) ) {
220 - // This status needs another name...
221 - return array( 'status' => self::HOOK_ABORTED, 'error' => $error );
222 - }
223 -
224 - return array( 'status' => self::OK );
 268+ return true;
225269 }
226270
227271 /**
@@ -511,7 +555,7 @@
512556 }
513557
514558 $key = $this->getSessionKey();
515 - $_SESSION['wsUploadData'][$key] = array(
 559+ $_SESSION[self::SESSION_KEYNAME][$key] = array(
516560 'mTempPath' => $status->value,
517561 'mFileSize' => $this->mFileSize,
518562 'mFileProps' => $this->mFileProps,
@@ -525,7 +569,7 @@
526570 */
527571 protected function getSessionKey() {
528572 $key = mt_rand( 0, 0x7fffffff );
529 - $_SESSION['wsUploadData'][$key] = array();
 573+ $_SESSION[self::SESSION_KEYNAME][$key] = array();
530574 return $key;
531575 }
532576
Index: trunk/phase3/includes/api/ApiBase.php
@@ -535,7 +535,7 @@
536536 /**
537537 * Handle watchlist settings
538538 */
539 - protected function getWatchlistValue ( $watchlist, $titleObj ) {
 539+ protected function getWatchlistValue ( $watchlist, $titleObj = null ) {
540540 switch ( $watchlist ) {
541541 case 'watch':
542542 return true;
@@ -543,7 +543,10 @@
544544 return false;
545545 case 'preferences':
546546 global $wgUser;
547 - if ( $titleObj->exists() && $wgUser->getOption( 'watchdefault' ) && !$titleObj->userIsWatching() ) {
 547+ if ( isset($titleObj)
 548+ && $titleObj->exists()
 549+ && $wgUser->getOption( 'watchdefault' )
 550+ && !$titleObj->userIsWatching() ) {
548551 return true;
549552 }
550553 return null;
Index: trunk/phase3/includes/api/ApiUpload.php
@@ -60,14 +60,14 @@
6161 * Upload stashed in a previous request
6262 */
6363 // Check the session key
64 - if ( !isset( $_SESSION['wsUploadData'][$this->mParams['sessionkey']] ) ) {
 64+ if ( !isset( $_SESSION[UploadBase::getSessionKey()][$this->mParams['sessionkey']] ) ) {
6565 $this->dieUsageMsg( array( 'invalid-session-key' ) );
6666 }
6767
6868 $this->mUpload = new UploadFromStash();
6969 $this->mUpload->initialize( $this->mParams['filename'],
7070 $this->mParams['sessionkey'],
71 - $_SESSION['wsUploadData'][$this->mParams['sessionkey']] );
 71+ $_SESSION[UploadBase::getSessionKey()][$this->mParams['sessionkey']] );
7272 } elseif ( isset( $this->mParams['filename'] ) ) {
7373 /**
7474 * Upload from URL, etc.
@@ -127,59 +127,73 @@
128128 $this->getResult()->addValue( null, $this->getModuleName(), $result );
129129 }
130130
131 - protected function performUpload() {
132 - global $wgUser;
133 - $result = array();
134 - $permErrors = $this->mUpload->verifyPermissions( $wgUser );
135 - if ( $permErrors !== true ) {
136 - $this->dieUsageMsg( array( 'badaccess-groups' ) );
 131+ /**
 132+ * Performs file verification, dies on error.
 133+ *
 134+ * @param $flag integer passed to UploadBase::verifyUpload, set to
 135+ * UploadBase::EMPTY_FILE to skip the empty file check.
 136+ */
 137+ public function verifyUpload( $flag ) {
 138+ $verification = $this->mUpload->verifyUpload( $flag );
 139+ if ( $verification['status'] === UploadBase::OK ) {
 140+ return $verification;
137141 }
138142
 143+ $this->getVerificationError( $verification );
 144+ }
 145+
 146+ /**
 147+ * Produce the usage error
 148+ *
 149+ * @param $verification array an associative array with the status
 150+ * key
 151+ */
 152+ public function getVerificationError( $verification ) {
139153 // TODO: Move them to ApiBase's message map
140 - $verification = $this->mUpload->verifyUpload();
141 - if ( $verification['status'] !== UploadBase::OK ) {
142 - $result['result'] = 'Failure';
143 - switch( $verification['status'] ) {
144 - case UploadBase::EMPTY_FILE:
145 - $this->dieUsage( 'The file you submitted was empty', 'empty-file' );
146 - break;
147 - case UploadBase::FILETYPE_MISSING:
148 - $this->dieUsage( 'The file is missing an extension', 'filetype-missing' );
149 - break;
150 - case UploadBase::FILETYPE_BADTYPE:
151 - global $wgFileExtensions;
152 - $this->dieUsage( 'This type of file is banned', 'filetype-banned',
153 - 0, array(
154 - 'filetype' => $verification['finalExt'],
155 - 'allowed' => $wgFileExtensions
156 - ) );
157 - break;
158 - case UploadBase::MIN_LENGTH_PARTNAME:
159 - $this->dieUsage( 'The filename is too short', 'filename-tooshort' );
160 - break;
161 - case UploadBase::ILLEGAL_FILENAME:
162 - $this->dieUsage( 'The filename is not allowed', 'illegal-filename',
163 - 0, array( 'filename' => $verification['filtered'] ) );
164 - break;
165 - case UploadBase::OVERWRITE_EXISTING_FILE:
166 - $this->dieUsage( 'Overwriting an existing file is not allowed', 'overwrite' );
167 - break;
168 - case UploadBase::VERIFICATION_ERROR:
169 - $this->getResult()->setIndexedTagName( $verification['details'], 'detail' );
170 - $this->dieUsage( 'This file did not pass file verification', 'verification-error',
171 - 0, array( 'details' => $verification['details'] ) );
172 - break;
173 - case UploadBase::HOOK_ABORTED:
174 - $this->dieUsage( "The modification you tried to make was aborted by an extension hook",
175 - 'hookaborted', 0, array( 'error' => $verification['error'] ) );
176 - break;
177 - default:
178 - $this->dieUsage( 'An unknown error occurred', 'unknown-error',
179 - 0, array( 'code' => $verification['status'] ) );
180 - break;
181 - }
182 - return $result;
 154+ switch( $verification['status'] ) {
 155+ case UploadBase::EMPTY_FILE:
 156+ $this->dieUsage( 'The file you submitted was empty', 'empty-file' );
 157+ break;
 158+ case UploadBase::FILETYPE_MISSING:
 159+ $this->dieUsage( 'The file is missing an extension', 'filetype-missing' );
 160+ break;
 161+ case UploadBase::FILETYPE_BADTYPE:
 162+ global $wgFileExtensions;
 163+ $this->dieUsage( 'This type of file is banned', 'filetype-banned',
 164+ 0, array(
 165+ 'filetype' => $verification['finalExt'],
 166+ 'allowed' => $wgFileExtensions
 167+ ) );
 168+ break;
 169+ case UploadBase::MIN_LENGTH_PARTNAME:
 170+ $this->dieUsage( 'The filename is too short', 'filename-tooshort' );
 171+ break;
 172+ case UploadBase::ILLEGAL_FILENAME:
 173+ $this->dieUsage( 'The filename is not allowed', 'illegal-filename',
 174+ 0, array( 'filename' => $verification['filtered'] ) );
 175+ break;
 176+ case UploadBase::OVERWRITE_EXISTING_FILE:
 177+ $this->dieUsage( 'Overwriting an existing file is not allowed', 'overwrite' );
 178+ break;
 179+ case UploadBase::VERIFICATION_ERROR:
 180+ $this->getResult()->setIndexedTagName( $verification['details'], 'detail' );
 181+ $this->dieUsage( 'This file did not pass file verification', 'verification-error',
 182+ 0, array( 'details' => $verification['details'] ) );
 183+ break;
 184+ case UploadBase::HOOK_ABORTED:
 185+ $this->dieUsage( "The modification you tried to make was aborted by an extension hook",
 186+ 'hookaborted', 0, array( 'error' => $verification['error'] ) );
 187+ break;
 188+ default:
 189+ $this->dieUsage( 'An unknown error occurred', 'unknown-error',
 190+ 0, array( 'code' => $verification['status'] ) );
 191+ break;
183192 }
 193+ }
 194+
 195+ protected function checkForWarnings() {
 196+ $result = array();
 197+
184198 if ( !$this->mParams['ignorewarnings'] ) {
185199 $warnings = $this->mUpload->checkWarnings();
186200 if ( $warnings ) {
@@ -213,19 +227,34 @@
214228 return $result;
215229 }
216230 }
 231+ return;
 232+ }
217233
 234+ protected function performUpload() {
 235+ global $wgUser;
 236+ $permErrors = $this->mUpload->verifyPermissions( $wgUser );
 237+ if ( $permErrors !== true ) {
 238+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 239+ }
 240+
 241+ $this->verifyUpload();
 242+
 243+ $warnings = $this->checkForWarnings();
 244+ if( isset($warnings) ) return $warnings;
 245+
218246 // Use comment as initial page text by default
219247 if ( is_null( $this->mParams['text'] ) ) {
220248 $this->mParams['text'] = $this->mParams['comment'];
221249 }
222 -
223 - $watch = $this->getWatchlistValue( $params['watchlist'] );
224 -
 250+
 251+ $file = $this->mUpload->getLocalFile();
 252+ $watch = $this->getWatchlistValue( $params['watchlist'], $file->getTitle() );
 253+
225254 // Deprecated parameters
226255 if ( $this->mParams['watch'] ) {
227256 $watch = true;
228257 }
229 -
 258+
230259 // No errors, no warnings: do the upload
231260 $status = $this->mUpload->performUpload( $this->mParams['comment'],
232261 $this->mParams['text'], $watch, $wgUser );
@@ -236,9 +265,9 @@
237266
238267 $this->dieUsage( 'An internal error occurred', 'internal-error', 0, $error );
239268 }
240 -
 269+
241270 $file = $this->mUpload->getLocalFile();
242 -
 271+
243272 $result['result'] = 'Success';
244273 $result['filename'] = $file->getName();
245274 $result['imageinfo'] = $this->mUpload->getImageInfo( $this->getResult() );

Follow-up revisions

RevisionCommit summaryAuthorDate
r64413use class constant from r64403mah00:15, 31 March 2010
r64977Fix documentation introduced in r64403ialex20:38, 12 April 2010
r69768re r64403 - remove never-actually-used $flag parameter from verifyUpload()mah00:07, 23 July 2010
r70049Follow-up r70037: Fix ApiUpload by passing a WebRequestUpload to the the init...btongminh21:53, 27 July 2010
r76089Add UploadBase::SESSION_KEYNAME, introduced in r64403, to prevent stuff from ...catrope13:18, 5 November 2010
r76105Add UploadBase::getSessionKeyname() from r64403catrope15:20, 5 November 2010

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r64197Fix bug 22944 in a much better fashion (using watchlist parameter)...reedy22:15, 25 March 2010

Comments

#Comment by Bryan (talk | contribs)   17:00, 31 March 2010
+	static public function getSessionKeyname() {
+		return self::SESSION_KEYNAME;
+	}

This probably isn't as useful as you would expect. PHP <5.3 do not support late static binding.

#Comment by Reedy (talk | contribs)   21:50, 22 July 2010

+ $this->verifyUpload();

but then verifyUpload requires a parameter

public function verifyUpload( $flag ) {

#Comment by MarkAHershberger (talk | contribs)   00:08, 23 July 2010

see r69768

#Comment by Bryan (talk | contribs)   21:29, 27 July 2010

Breaks stashed uploads, working on a fix.

#Comment by Bryan (talk | contribs)   19:49, 29 July 2010
+	protected function getWatchlistValue ( $watchlist, $titleObj = null ) {
...
+				if ( isset($titleObj)

If you know that $titleObj is is defined, is_null is preferred over isset, since isset also suppresses errors, which will cause misspelled variables to go unnoticed.

You are being inconsistent about using $this->getSessionKeyName() and self::SESSION_KEYNAME.

#Comment by Nikerabbit (talk | contribs)   20:46, 29 July 2010

And I prefer === null over is_null. Coding style manual seems to be mixed up which one it prefers.

#Comment by 😂 (talk | contribs)   20:47, 29 July 2010

Because it doesn't really matter?

#Comment by Nikerabbit (talk | contribs)   20:48, 29 July 2010

No less and no more than any other thing which can be done in multiple ways.

#Comment by Bryan (talk | contribs)   20:48, 29 July 2010

Whatever. The point about isset.

#Comment by 😂 (talk | contribs)   20:52, 29 July 2010

isset() doesn't suppress errors on typos. It just returns (correctly) that the misspelled variable name isn't set.

Status & tagging log