Index: trunk/phase3/includes/upload/UploadBase.php |
— | — | @@ -33,7 +33,12 @@ |
34 | 34 | const HOOK_ABORTED = 11; |
35 | 35 | |
36 | 36 | const SESSION_VERSION = 2; |
| 37 | + const SESSION_KEYNAME = 'wsUploadData'; |
37 | 38 | |
| 39 | + static public function getSessionKeyname() { |
| 40 | + return self::SESSION_KEYNAME; |
| 41 | + } |
| 42 | + |
38 | 43 | /** |
39 | 44 | * Returns true if uploads are enabled. |
40 | 45 | * Can be override by subclasses. |
— | — | @@ -143,13 +148,35 @@ |
144 | 149 | } |
145 | 150 | |
146 | 151 | /** |
147 | | - * Return the file size |
| 152 | + * Return true if the file is empty |
| 153 | + * @return bool |
148 | 154 | */ |
149 | 155 | public function isEmptyFile() { |
150 | 156 | return empty( $this->mFileSize ); |
151 | 157 | } |
152 | 158 | |
153 | 159 | /** |
| 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 | + /** |
154 | 181 | * @param $srcPath String: the source path |
155 | 182 | * @return the real path if it was a virtual URL |
156 | 183 | */ |
— | — | @@ -163,9 +190,9 @@ |
164 | 191 | |
165 | 192 | /** |
166 | 193 | * 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 |
168 | 195 | */ |
169 | | - public function verifyUpload() { |
| 196 | + public function verifyUpload( ) { |
170 | 197 | /** |
171 | 198 | * If there was no filename or a zero size given, give up quick. |
172 | 199 | */ |
— | — | @@ -189,6 +216,31 @@ |
190 | 217 | ); |
191 | 218 | } |
192 | 219 | |
| 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() { |
193 | 245 | $nt = $this->getTitle(); |
194 | 246 | if( is_null( $nt ) ) { |
195 | 247 | $result = array( 'status' => $this->mTitleError ); |
— | — | @@ -212,15 +264,7 @@ |
213 | 265 | 'overwrite' => $overwrite |
214 | 266 | ); |
215 | 267 | } |
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; |
225 | 269 | } |
226 | 270 | |
227 | 271 | /** |
— | — | @@ -511,7 +555,7 @@ |
512 | 556 | } |
513 | 557 | |
514 | 558 | $key = $this->getSessionKey(); |
515 | | - $_SESSION['wsUploadData'][$key] = array( |
| 559 | + $_SESSION[self::SESSION_KEYNAME][$key] = array( |
516 | 560 | 'mTempPath' => $status->value, |
517 | 561 | 'mFileSize' => $this->mFileSize, |
518 | 562 | 'mFileProps' => $this->mFileProps, |
— | — | @@ -525,7 +569,7 @@ |
526 | 570 | */ |
527 | 571 | protected function getSessionKey() { |
528 | 572 | $key = mt_rand( 0, 0x7fffffff ); |
529 | | - $_SESSION['wsUploadData'][$key] = array(); |
| 573 | + $_SESSION[self::SESSION_KEYNAME][$key] = array(); |
530 | 574 | return $key; |
531 | 575 | } |
532 | 576 | |
Index: trunk/phase3/includes/api/ApiBase.php |
— | — | @@ -535,7 +535,7 @@ |
536 | 536 | /** |
537 | 537 | * Handle watchlist settings |
538 | 538 | */ |
539 | | - protected function getWatchlistValue ( $watchlist, $titleObj ) { |
| 539 | + protected function getWatchlistValue ( $watchlist, $titleObj = null ) { |
540 | 540 | switch ( $watchlist ) { |
541 | 541 | case 'watch': |
542 | 542 | return true; |
— | — | @@ -543,7 +543,10 @@ |
544 | 544 | return false; |
545 | 545 | case 'preferences': |
546 | 546 | 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() ) { |
548 | 551 | return true; |
549 | 552 | } |
550 | 553 | return null; |
Index: trunk/phase3/includes/api/ApiUpload.php |
— | — | @@ -60,14 +60,14 @@ |
61 | 61 | * Upload stashed in a previous request |
62 | 62 | */ |
63 | 63 | // Check the session key |
64 | | - if ( !isset( $_SESSION['wsUploadData'][$this->mParams['sessionkey']] ) ) { |
| 64 | + if ( !isset( $_SESSION[UploadBase::getSessionKey()][$this->mParams['sessionkey']] ) ) { |
65 | 65 | $this->dieUsageMsg( array( 'invalid-session-key' ) ); |
66 | 66 | } |
67 | 67 | |
68 | 68 | $this->mUpload = new UploadFromStash(); |
69 | 69 | $this->mUpload->initialize( $this->mParams['filename'], |
70 | 70 | $this->mParams['sessionkey'], |
71 | | - $_SESSION['wsUploadData'][$this->mParams['sessionkey']] ); |
| 71 | + $_SESSION[UploadBase::getSessionKey()][$this->mParams['sessionkey']] ); |
72 | 72 | } elseif ( isset( $this->mParams['filename'] ) ) { |
73 | 73 | /** |
74 | 74 | * Upload from URL, etc. |
— | — | @@ -127,59 +127,73 @@ |
128 | 128 | $this->getResult()->addValue( null, $this->getModuleName(), $result ); |
129 | 129 | } |
130 | 130 | |
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; |
137 | 141 | } |
138 | 142 | |
| 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 ) { |
139 | 153 | // 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; |
183 | 192 | } |
| 193 | + } |
| 194 | + |
| 195 | + protected function checkForWarnings() { |
| 196 | + $result = array(); |
| 197 | + |
184 | 198 | if ( !$this->mParams['ignorewarnings'] ) { |
185 | 199 | $warnings = $this->mUpload->checkWarnings(); |
186 | 200 | if ( $warnings ) { |
— | — | @@ -213,19 +227,34 @@ |
214 | 228 | return $result; |
215 | 229 | } |
216 | 230 | } |
| 231 | + return; |
| 232 | + } |
217 | 233 | |
| 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 | + |
218 | 246 | // Use comment as initial page text by default |
219 | 247 | if ( is_null( $this->mParams['text'] ) ) { |
220 | 248 | $this->mParams['text'] = $this->mParams['comment']; |
221 | 249 | } |
222 | | - |
223 | | - $watch = $this->getWatchlistValue( $params['watchlist'] ); |
224 | | - |
| 250 | + |
| 251 | + $file = $this->mUpload->getLocalFile(); |
| 252 | + $watch = $this->getWatchlistValue( $params['watchlist'], $file->getTitle() ); |
| 253 | + |
225 | 254 | // Deprecated parameters |
226 | 255 | if ( $this->mParams['watch'] ) { |
227 | 256 | $watch = true; |
228 | 257 | } |
229 | | - |
| 258 | + |
230 | 259 | // No errors, no warnings: do the upload |
231 | 260 | $status = $this->mUpload->performUpload( $this->mParams['comment'], |
232 | 261 | $this->mParams['text'], $watch, $wgUser ); |
— | — | @@ -236,9 +265,9 @@ |
237 | 266 | |
238 | 267 | $this->dieUsage( 'An internal error occurred', 'internal-error', 0, $error ); |
239 | 268 | } |
240 | | - |
| 269 | + |
241 | 270 | $file = $this->mUpload->getLocalFile(); |
242 | | - |
| 271 | + |
243 | 272 | $result['result'] = 'Success'; |
244 | 273 | $result['filename'] = $file->getName(); |
245 | 274 | $result['imageinfo'] = $this->mUpload->getImageInfo( $this->getResult() ); |