Index: trunk/phase3/includes/upload/UploadFromStash.php |
— | — | @@ -130,4 +130,36 @@ |
131 | 131 | return $rv; |
132 | 132 | } |
133 | 133 | |
134 | | -} |
\ No newline at end of file |
| 134 | + /** |
| 135 | + * Append a chunk to the temporary file. |
| 136 | + * |
| 137 | + * @return void |
| 138 | + */ |
| 139 | + public function appendChunk($chunk, $chunkSize, $offset) { |
| 140 | + //to use $this->getFileSize() here, db needs to be updated |
| 141 | + //in appendToUploadFile for that |
| 142 | + $fileSize = $this->stash->getFile( $this->mFileKey )->getSize(); |
| 143 | + if ( $fileSize + $chunkSize > $this->getMaxUploadSize()) { |
| 144 | + $status = Status::newFatal( 'file-too-large' ); |
| 145 | + } else { |
| 146 | + //append chunk |
| 147 | + if ( $fileSize == $offset ) { |
| 148 | + $status = $this->appendToUploadFile( $chunk, |
| 149 | + $this->mVirtualTempPath ); |
| 150 | + } else { |
| 151 | + $status = Status::newFatal( 'invalid-chunk-offset' ); |
| 152 | + } |
| 153 | + } |
| 154 | + return $status; |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * Append the final chunk and ready file for parent::performUpload() |
| 159 | + * @return void |
| 160 | + */ |
| 161 | + public function finalizeFile() { |
| 162 | + $this->appendFinish ( $this->mVirtualTempPath ); |
| 163 | + $this->cleanupTempFile(); |
| 164 | + $this->mTempPath = $this->getRealPath( $this->mVirtualTempPath ); |
| 165 | + } |
| 166 | +} |
Index: trunk/phase3/includes/api/ApiUpload.php |
— | — | @@ -58,6 +58,7 @@ |
59 | 59 | $request = $this->getMain()->getRequest(); |
60 | 60 | // Add the uploaded file to the params array |
61 | 61 | $this->mParams['file'] = $request->getFileName( 'file' ); |
| 62 | + $this->mParams['chunk'] = $request->getFileName( 'chunk' ); |
62 | 63 | |
63 | 64 | // Copy the session key to the file key, for backward compatibility. |
64 | 65 | if( !$this->mParams['filekey'] && $this->mParams['sessionkey'] ) { |
— | — | @@ -85,7 +86,14 @@ |
86 | 87 | } |
87 | 88 | |
88 | 89 | // Check if the uploaded file is sane |
89 | | - $this->verifyUpload(); |
| 90 | + if ( $this->mParams['chunk'] ) { |
| 91 | + $maxSize = $this->mUpload->getMaxUploadSize( ); |
| 92 | + if( $this->mParams['filesize'] > $maxSize ) { |
| 93 | + $this->dieUsage( 'The file you submitted was too large', 'file-too-large' ); |
| 94 | + } |
| 95 | + } else { |
| 96 | + $this->verifyUpload(); |
| 97 | + } |
90 | 98 | |
91 | 99 | |
92 | 100 | // Check if the user has the rights to modify or overwrite the requested title |
— | — | @@ -113,6 +121,26 @@ |
114 | 122 | } catch ( MWException $e ) { |
115 | 123 | $result['warnings']['stashfailed'] = $e->getMessage(); |
116 | 124 | } |
| 125 | + } elseif ( $this->mParams['chunk'] ) { |
| 126 | + $result['result'] = 'Continue'; |
| 127 | + $chunk = $request->getFileTempName( 'chunk' ); |
| 128 | + $chunkSize = $request->getFileSize( 'chunk' ); |
| 129 | + if ($this->mParams['offset'] == 0) { |
| 130 | + $result['filekey'] = $this->performStash(); |
| 131 | + } else { |
| 132 | + $status = $this->mUpload->appendChunk($chunk, $chunkSize, |
| 133 | + $this->mParams['offset']); |
| 134 | + if ( !$status->isGood() ) { |
| 135 | + $this->dieUsage( $status->getWikiText(), 'stashfailed' ); |
| 136 | + } else { |
| 137 | + $result['filekey'] = $this->mParams['filekey']; |
| 138 | + if($this->mParams['offset'] + $chunkSize == $this->mParams['filesize']) { |
| 139 | + $this->mUpload->finalizeFile(); |
| 140 | + $result['result'] = 'Done'; |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + $result['offset'] = $this->mParams['offset'] + $chunkSize; |
117 | 145 | } elseif ( $this->mParams['stash'] ) { |
118 | 146 | // Some uploads can request they be stashed, so as not to publish them immediately. |
119 | 147 | // In this case, a failure to stash ought to be fatal |
— | — | @@ -188,9 +216,10 @@ |
189 | 217 | protected function selectUploadModule() { |
190 | 218 | $request = $this->getMain()->getRequest(); |
191 | 219 | |
192 | | - // One and only one of the following parameters is needed |
193 | | - $this->requireOnlyOneParameter( $this->mParams, |
194 | | - 'filekey', 'file', 'url', 'statuskey' ); |
| 220 | + // chunk or one and only one of the following parameters is needed |
| 221 | + if(!$this->mParams['chunk']) |
| 222 | + $this->requireOnlyOneParameter( $this->mParams, |
| 223 | + 'filekey', 'file', 'url', 'statuskey' ); |
195 | 224 | |
196 | 225 | if ( $this->mParams['statuskey'] ) { |
197 | 226 | $this->checkAsyncDownloadEnabled(); |
— | — | @@ -234,6 +263,13 @@ |
235 | 264 | |
236 | 265 | $this->mUpload->initialize( $this->mParams['filekey'], $this->mParams['filename'] ); |
237 | 266 | |
| 267 | + } elseif ( isset( $this->mParams['chunk'] ) ) { |
| 268 | + // Start new Chunk upload |
| 269 | + $this->mUpload = new UploadFromFile(); |
| 270 | + $this->mUpload->initialize( |
| 271 | + $this->mParams['filename'], |
| 272 | + $request->getUpload( 'chunk' ) |
| 273 | + ); |
238 | 274 | } elseif ( isset( $this->mParams['file'] ) ) { |
239 | 275 | $this->mUpload = new UploadFromFile(); |
240 | 276 | $this->mUpload->initialize( |
— | — | @@ -488,6 +524,10 @@ |
489 | 525 | ), |
490 | 526 | 'stash' => false, |
491 | 527 | |
| 528 | + 'filesize' => null, |
| 529 | + 'offset' => null, |
| 530 | + 'chunk' => null, |
| 531 | + |
492 | 532 | 'asyncdownload' => false, |
493 | 533 | 'leavemessage' => false, |
494 | 534 | 'statuskey' => null, |
— | — | @@ -511,6 +551,10 @@ |
512 | 552 | 'sessionkey' => 'Same as filekey, maintained for backward compatibility.', |
513 | 553 | 'stash' => 'If set, the server will not add the file to the repository and stash it temporarily.', |
514 | 554 | |
| 555 | + 'chunk' => 'Chunk contents', |
| 556 | + 'offset' => 'Offset of chunk in bytes', |
| 557 | + 'filesize' => 'Filesize of entire upload', |
| 558 | + |
515 | 559 | 'asyncdownload' => 'Make fetching a URL asynchronous', |
516 | 560 | 'leavemessage' => 'If asyncdownload is used, leave a message on the user talk page if finished', |
517 | 561 | 'statuskey' => 'Fetch the upload status for this file key', |