Index: trunk/phase3/includes/upload/UploadFromChunks.php |
— | — | @@ -1,254 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * @file |
5 | | - * @ingroup upload |
6 | | - * |
7 | | - * First, destination checks are made, and, if ignorewarnings is not |
8 | | - * checked, errors / warning is returned. |
9 | | - * |
10 | | - * 1. We return the uploadUrl. |
11 | | - * 2. We then accept chunk uploads from the client. |
12 | | - * 3. Return chunk id on each POSTED chunk. |
13 | | - * 4. Once the client posts "done=1", the files are concatenated together. |
14 | | - * |
15 | | - * (More info at: http://firefogg.org/dev/chunk_post.html) |
16 | | - */ |
17 | | -class UploadFromChunks extends UploadBase { |
18 | | - |
19 | | - const INIT = 1; |
20 | | - const CHUNK = 2; |
21 | | - const DONE = 3; |
22 | | - |
23 | | - protected $chunkMode; // INIT, CHUNK, DONE |
24 | | - protected $sessionKey; |
25 | | - protected $comment; |
26 | | - protected $repoPath; |
27 | | - protected $pageText; |
28 | | - protected $watch; |
29 | | - |
30 | | - public $status; |
31 | | - |
32 | | - // Parent class requires this function even though it is only |
33 | | - // used from SpecialUpload.php and we don't do chunked uploading |
34 | | - // from SpecialUpload -- best to raise an exception for |
35 | | - // now. |
36 | | - public function initializeFromRequest( &$request ) { |
37 | | - throw new MWException( 'not implemented' ); |
38 | | - } |
39 | | - |
40 | | - public function initialize( $done, $filename, $sessionKey, $path, $fileSize, $sessionData ) { |
41 | | - $this->status = Status::newGood(); |
42 | | - |
43 | | - $this->initializePathInfo( $filename, $path, 0, true ); |
44 | | - if ( $sessionKey !== null ) { |
45 | | - $this->initFromSessionKey( $sessionKey, $sessionData, $fileSize ); |
46 | | - |
47 | | - if ( $done ) { |
48 | | - $this->chunkMode = self::DONE; |
49 | | - } else { |
50 | | - $this->mTempPath = $path; |
51 | | - $this->chunkMode = self::CHUNK; |
52 | | - } |
53 | | - } else { |
54 | | - // session key not set, init the chunk upload system: |
55 | | - $this->chunkMode = self::INIT; |
56 | | - } |
57 | | - |
58 | | - if ( $this->status->isOk() |
59 | | - && ( $this->mDesiredDestName === null || $this->mFileSize === null ) ) { |
60 | | - $this->status = Status::newFatal( 'chunk-init-error' ); |
61 | | - } |
62 | | - } |
63 | | - |
64 | | - /** |
65 | | - * Set session information for chunked uploads and allocate a unique key. |
66 | | - * @param $comment string |
67 | | - * @param $pageText string |
68 | | - * @param $watch boolean |
69 | | - * |
70 | | - * @returns string the session key for this chunked upload |
71 | | - */ |
72 | | - protected function setupChunkSession( $comment, $pageText, $watch ) { |
73 | | - if ( !isset( $this->sessionKey ) ) { |
74 | | - $this->sessionKey = $this->getSessionKey(); |
75 | | - } |
76 | | - foreach ( array( 'mFilteredName', 'repoPath', 'mFileSize', 'mDesiredDestName' ) |
77 | | - as $key ) { |
78 | | - if ( isset( $this->$key ) ) { |
79 | | - $_SESSION['wsUploadData'][$this->sessionKey][$key] = $this->$key; |
80 | | - } |
81 | | - } |
82 | | - if ( isset( $comment ) ) { |
83 | | - $_SESSION['wsUploadData'][$this->sessionKey]['commment'] = $comment; |
84 | | - } |
85 | | - if ( isset( $pageText ) ) { |
86 | | - $_SESSION['wsUploadData'][$this->sessionKey]['pageText'] = $pageText; |
87 | | - } |
88 | | - if ( isset( $watch ) ) { |
89 | | - $_SESSION['wsUploadData'][$this->sessionKey]['watch'] = $watch; |
90 | | - } |
91 | | - $_SESSION['wsUploadData'][$this->sessionKey]['version'] = self::SESSION_VERSION; |
92 | | - |
93 | | - return $this->sessionKey; |
94 | | - } |
95 | | - |
96 | | - /** |
97 | | - * Initialize a continuation of a chunked upload from a session key |
98 | | - * @param $sessionKey string |
99 | | - * @param $request WebRequest |
100 | | - * @param $fileSize int Size of this chunk |
101 | | - * |
102 | | - * @returns void |
103 | | - */ |
104 | | - protected function initFromSessionKey( $sessionKey, $sessionData, $fileSize ) { |
105 | | - // testing against null because we don't want to cause obscure |
106 | | - // bugs when $sessionKey is full of "0" |
107 | | - $this->sessionKey = $sessionKey; |
108 | | - |
109 | | - if ( isset( $sessionData[$this->sessionKey]['version'] ) |
110 | | - && $sessionData[$this->sessionKey]['version'] == self::SESSION_VERSION ) |
111 | | - { |
112 | | - foreach ( array( 'comment', 'pageText', 'watch', 'mFilteredName', 'repoPath', 'mFileSize', 'mDesiredDestName' ) |
113 | | - as $key ) { |
114 | | - if ( isset( $sessionData[$this->sessionKey][$key] ) ) { |
115 | | - $this->$key = $sessionData[$this->sessionKey][$key]; |
116 | | - } |
117 | | - } |
118 | | - |
119 | | - $this->mFileSize += $fileSize; |
120 | | - } else { |
121 | | - $this->status = Status::newFatal( 'invalid-session-key' ); |
122 | | - } |
123 | | - } |
124 | | - |
125 | | - /** |
126 | | - * Handle a chunk of the upload. Overrides the parent method |
127 | | - * because Chunked Uploading clients (i.e. Firefogg) require |
128 | | - * specific API responses. |
129 | | - * @see UploadBase::performUpload |
130 | | - */ |
131 | | - public function performUpload( $comment, $pageText, $watch, $user ) { |
132 | | - wfDebug( "\n\n\performUpload(chunked): comment:" . $comment . ' pageText: ' . $pageText . ' watch:' . $watch ); |
133 | | - global $wgUser, $wgOut; |
134 | | - |
135 | | - if ( $this->chunkMode == self::INIT ) { |
136 | | - // firefogg expects a specific result per: |
137 | | - // http://www.firefogg.org/dev/chunk_post.html |
138 | | - |
139 | | - // it's okay to return the token here because |
140 | | - // a) the user must have requested the token to get here and |
141 | | - // b) should only happen over POST |
142 | | - // c) we need the token to validate chunks are coming from a non-xss request |
143 | | - return Status::newGood( |
144 | | - array( 'uploadUrl' => wfExpandUrl( wfScript( 'api' ) ) . "?" . |
145 | | - wfArrayToCGI( array( |
146 | | - 'action' => 'upload', |
147 | | - 'token' => $wgUser->editToken(), |
148 | | - 'format' => 'json', |
149 | | - 'filename' => $this->mDesiredDestName, |
150 | | - 'enablechunks' => 'true', |
151 | | - 'chunksession' => |
152 | | - $this->setupChunkSession( $comment, $pageText, $watch ) ) ) ) ); |
153 | | - } else if ( $this->chunkMode == self::CHUNK ) { |
154 | | - $this->setupChunkSession(); |
155 | | - $this->appendChunk(); |
156 | | - if ( !$this->status->isOK() ) { |
157 | | - return $this->status; |
158 | | - } |
159 | | - // return success: |
160 | | - // firefogg expects a specific result |
161 | | - // http://www.firefogg.org/dev/chunk_post.html |
162 | | - return Status::newGood( |
163 | | - array( 'result' => 1, 'filesize' => $this->mFileSize ) |
164 | | - ); |
165 | | - } else if ( $this->chunkMode == self::DONE ) { |
166 | | - $this->finalizeFile(); |
167 | | - // We ignore the passed-in parameters because these were set on the first contact. |
168 | | - $status = parent::performUpload( $this->comment, $this->pageText, $this->watch, $user ); |
169 | | - |
170 | | - if ( !$status->isGood() ) { |
171 | | - return $status; |
172 | | - } |
173 | | - $file = $this->getLocalFile(); |
174 | | - |
175 | | - // firefogg expects a specific result |
176 | | - // http://www.firefogg.org/dev/chunk_post.html |
177 | | - return Status::newGood( |
178 | | - array( 'result' => 1, 'done' => 1, 'resultUrl' => wfExpandUrl( $file->getDescriptionUrl() ) ) |
179 | | - ); |
180 | | - } |
181 | | - |
182 | | - return Status::newGood(); |
183 | | - } |
184 | | - |
185 | | - /** |
186 | | - * Append a chunk to the Repo file |
187 | | - * |
188 | | - * @param string $srcPath Path to file to append from |
189 | | - * @param string $toAppendPath Path to file to append to |
190 | | - * @return Status Status |
191 | | - */ |
192 | | - protected function appendToUploadFile( $srcPath, $toAppendPath ) { |
193 | | - $repo = RepoGroup::singleton()->getLocalRepo(); |
194 | | - $status = $repo->append( $srcPath, $toAppendPath ); |
195 | | - return $status; |
196 | | - } |
197 | | - |
198 | | - /** |
199 | | - * Append a chunk to the temporary file. |
200 | | - * |
201 | | - * @return void |
202 | | - */ |
203 | | - protected function appendChunk() { |
204 | | - global $wgMaxUploadSize; |
205 | | - |
206 | | - if ( !$this->repoPath ) { |
207 | | - $this->status = $this->saveTempUploadedFile( $this->mDesiredDestName, $this->mTempPath ); |
208 | | - |
209 | | - if ( $this->status->isOK() ) { |
210 | | - $this->repoPath = $this->status->value; |
211 | | - $_SESSION['wsUploadData'][$this->sessionKey]['repoPath'] = $this->repoPath; |
212 | | - } |
213 | | - return; |
214 | | - } |
215 | | - if ( $this->getRealPath( $this->repoPath ) ) { |
216 | | - $this->status = $this->appendToUploadFile( $this->repoPath, $this->mTempPath ); |
217 | | - |
218 | | - if ( $this->mFileSize > $wgMaxUploadSize ) |
219 | | - $this->status = Status::newFatal( 'largefileserver' ); |
220 | | - |
221 | | - } else { |
222 | | - $this->status = Status::newFatal( 'filenotfound', $this->repoPath ); |
223 | | - } |
224 | | - } |
225 | | - |
226 | | - /** |
227 | | - * Append the final chunk and ready file for parent::performUpload() |
228 | | - * @return void |
229 | | - */ |
230 | | - protected function finalizeFile() { |
231 | | - $this->appendChunk(); |
232 | | - $this->mTempPath = $this->getRealPath( $this->repoPath ); |
233 | | - } |
234 | | - |
235 | | - public function verifyUpload() { |
236 | | - if ( $this->chunkMode != self::DONE ) { |
237 | | - return array( 'status' => UploadBase::OK ); |
238 | | - } |
239 | | - return parent::verifyUpload(); |
240 | | - } |
241 | | - |
242 | | - public function checkWarnings() { |
243 | | - if ( $this->chunkMode != self::DONE ) { |
244 | | - return null; |
245 | | - } |
246 | | - return parent::checkWarnings(); |
247 | | - } |
248 | | - |
249 | | - public function getImageInfo( $result ) { |
250 | | - if ( $this->chunkMode != self::DONE ) { |
251 | | - return null; |
252 | | - } |
253 | | - return parent::getImageInfo( $result ); |
254 | | - } |
255 | | -} |
Index: trunk/phase3/includes/upload/UploadFromStash.php |
— | — | @@ -24,10 +24,8 @@ |
25 | 25 | $sessionData |
26 | 26 | ); |
27 | 27 | } |
28 | | - /* |
29 | | - * some $na vars for uploadBase method compatibility. |
30 | | - */ |
31 | | - public function initialize( $name, $sessionData, $na=false, $na2=false ) { |
| 28 | + |
| 29 | + public function initialize( $name, $sessionKey, $sessionData ) { |
32 | 30 | /** |
33 | 31 | * Confirming a temporarily stashed upload. |
34 | 32 | * We don't want path names to be forged, so we keep |
— | — | @@ -40,19 +38,20 @@ |
41 | 39 | $sessionData['mFileSize'], |
42 | 40 | false |
43 | 41 | ); |
44 | | - |
| 42 | + |
| 43 | + $this->mSessionKey = $sessionKey; |
45 | 44 | $this->mVirtualTempPath = $sessionData['mTempPath']; |
46 | 45 | $this->mFileProps = $sessionData['mFileProps']; |
47 | 46 | } |
48 | 47 | |
49 | 48 | public function initializeFromRequest( &$request ) { |
50 | | - $this->mSessionKey = $request->getInt( 'wpSessionKey' ); |
| 49 | + $sessionKey = $request->getInt( 'wpSessionKey' ); |
51 | 50 | $sessionData = $request->getSessionData('wsUploadData'); |
52 | 51 | |
53 | 52 | $desiredDestName = $request->getText( 'wpDestFile' ); |
54 | 53 | if( !$desiredDestName ) |
55 | 54 | $desiredDestName = $request->getText( 'wpUploadFile' ); |
56 | | - return $this->initialize( $desiredDestName, $sessionData[$this->mSessionKey], false ); |
| 55 | + return $this->initialize( $desiredDestName, $sessionKey, $sessionData[$sessionKey] ); |
57 | 56 | } |
58 | 57 | |
59 | 58 | /** |
Index: trunk/phase3/includes/api/ApiBase.php |
— | — | @@ -927,8 +927,6 @@ |
928 | 928 | 'invalid-session-key' => array( 'code' => 'invalid-session-key', 'info' => 'Not a valid session key' ), |
929 | 929 | 'nouploadmodule' => array( 'code' => 'nouploadmodule', 'info' => 'No upload module set' ), |
930 | 930 | 'uploaddisabled' => array( 'code' => 'uploaddisabled', 'info' => 'Uploads are not enabled. Make sure $wgEnableUploads is set to true in LocalSettings.php and the PHP ini setting file_uploads is true' ), |
931 | | - 'chunked-error' => array( 'code' => 'chunked-error', 'info' => 'There was a problem initializing the chunked upload.' ), |
932 | | - 'chunk-init-error' => array( 'code' => 'chunk-init-error', 'info' => 'Insufficient information for initialization.' ), |
933 | 931 | ); |
934 | 932 | |
935 | 933 | /** |
Index: trunk/phase3/includes/api/ApiUpload.php |
— | — | @@ -53,25 +53,9 @@ |
54 | 54 | |
55 | 55 | // One and only one of the following parameters is needed |
56 | 56 | $this->requireOnlyOneParameter( $this->mParams, |
57 | | - 'sessionkey', 'file', 'url', 'enablechunks' ); |
| 57 | + 'sessionkey', 'file', 'url' ); |
58 | 58 | |
59 | | - // Initialize $this->mUpload |
60 | | - if ( $this->mParams['enablechunks'] ) { |
61 | | - $this->mUpload = new UploadFromChunks(); |
62 | | - |
63 | | - $this->mUpload->initialize( |
64 | | - $request->getVal( 'done', null ), |
65 | | - $request->getVal( 'filename', null ), |
66 | | - $request->getVal( 'chunksession', null ), |
67 | | - $request->getFileTempName( 'chunk' ), |
68 | | - $request->getFileSize( 'chunk' ), |
69 | | - $request->getSessionData( 'wsUploadData' ) |
70 | | - ); |
71 | | - |
72 | | - if ( !$this->mUpload->status->isOK() ) { |
73 | | - $this->dieUsageMsg( $this->mUpload->status->getErrorsArray() ); |
74 | | - } |
75 | | - } elseif ( $this->mParams['sessionkey'] ) { |
| 59 | + if ( $this->mParams['sessionkey'] ) { |
76 | 60 | /** |
77 | 61 | * Upload stashed in a previous request |
78 | 62 | */ |
— | — | @@ -82,6 +66,7 @@ |
83 | 67 | |
84 | 68 | $this->mUpload = new UploadFromStash(); |
85 | 69 | $this->mUpload->initialize( $this->mParams['filename'], |
| 70 | + $this->mParams['sessionkey'], |
86 | 71 | $_SESSION['wsUploadData'][$this->mParams['sessionkey']] ); |
87 | 72 | } elseif ( isset( $this->mParams['filename'] ) ) { |
88 | 73 | /** |
— | — | @@ -139,16 +124,7 @@ |
140 | 125 | // Cleanup any temporary mess |
141 | 126 | $this->mUpload->cleanupTempFile(); |
142 | 127 | |
143 | | - if ( isset( $result['chunked-output'] ) ) { |
144 | | - foreach ( $result['chunked-output'] as $key => $value ) { |
145 | | - if ( $value === null ) { |
146 | | - $value = ''; |
147 | | - } |
148 | | - $this->getResult()->addValue( null, $key, $value ); |
149 | | - } |
150 | | - } else { |
151 | | - $this->getResult()->addValue( null, $this->getModuleName(), $result ); |
152 | | - } |
| 128 | + $this->getResult()->addValue( null, $this->getModuleName(), $result ); |
153 | 129 | } |
154 | 130 | |
155 | 131 | protected function performUpload() { |
— | — | @@ -252,8 +228,6 @@ |
253 | 229 | $this->getResult()->setIndexedTagName( $result['details'], 'error' ); |
254 | 230 | |
255 | 231 | $this->dieUsage( 'An internal error occurred', 'internal-error', 0, $error ); |
256 | | - } elseif ( $this->mParams['enablechunks'] ) { |
257 | | - return array( 'chunked-output' => $status->value ); |
258 | 232 | } |
259 | 233 | |
260 | 234 | $file = $this->mUpload->getLocalFile(); |
— | — | @@ -283,10 +257,6 @@ |
284 | 258 | 'watch' => false, |
285 | 259 | 'ignorewarnings' => false, |
286 | 260 | 'file' => null, |
287 | | - 'enablechunks' => false, |
288 | | - 'chunksession' => null, |
289 | | - 'chunk' => null, |
290 | | - 'done' => false, |
291 | 261 | 'url' => null, |
292 | 262 | 'sessionkey' => null, |
293 | 263 | ); |
— | — | @@ -306,10 +276,6 @@ |
307 | 277 | 'watch' => 'Watch the page', |
308 | 278 | 'ignorewarnings' => 'Ignore any warnings', |
309 | 279 | 'file' => 'File contents', |
310 | | - 'enablechunks' => 'Set to use chunk mode; see http://firefogg.org/dev/chunk_post.html for protocol', |
311 | | - 'chunksession' => 'The session key, established on the first contact during the chunked upload', |
312 | | - 'chunk' => 'The data in this chunk of a chunked upload', |
313 | | - 'done' => 'Set to 1 on the last chunk of a chunked upload', |
314 | 280 | 'url' => 'Url to fetch the file from', |
315 | 281 | 'sessionkey' => array( |
316 | 282 | 'Session key returned by a previous upload that failed due to warnings', |
— | — | @@ -321,11 +287,10 @@ |
322 | 288 | return array( |
323 | 289 | 'Upload a file, or get the status of pending uploads. Several methods are available:', |
324 | 290 | ' * Upload file contents directly, using the "file" parameter', |
325 | | - ' * Upload a file in chunks, using the "enablechunks",', |
326 | 291 | ' * Have the MediaWiki server fetch a file from a URL, using the "url" parameter', |
327 | 292 | ' * Complete an earlier upload that failed due to warnings, using the "sessionkey" parameter', |
328 | 293 | 'Note that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when', |
329 | | - 'sending the "file" or "chunk" parameters. Note also that queries using session keys must be', |
| 294 | + 'sending the "file". Note also that queries using session keys must be', |
330 | 295 | 'done in the same login session as the query that originally returned the key (i.e. do not', |
331 | 296 | 'log out and then log back in). Also you must get and send an edit token before doing any upload stuff.' |
332 | 297 | ); |
— | — | @@ -362,8 +327,6 @@ |
363 | 328 | ' api.php?action=upload&filename=Wiki.png&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png', |
364 | 329 | 'Complete an upload that failed due to warnings:', |
365 | 330 | ' api.php?action=upload&filename=Wiki.png&sessionkey=sessionkey&ignorewarnings=1', |
366 | | - 'Begin a chunked upload:', |
367 | | - ' api.php?action=upload&filename=Wiki.png&enablechunks=1' |
368 | 331 | ); |
369 | 332 | } |
370 | 333 | |
Property changes on: trunk/phase3/includes/api |
___________________________________________________________________ |
Name: svn:mergeinfo |
371 | 334 | - /branches/REL1_15/phase3/includes/api:51646 |
/branches/sqlite/includes/api:58211-58321 |
/branches/wmf-deployment/includes/api:53381,59952 |
372 | 335 | + /branches/REL1_15/phase3/includes/api:51646 |
/branches/REL1_16/phase3/includes/api:63621-63636 |
/branches/sqlite/includes/api:58211-58321 |
/branches/wmf-deployment/includes/api:53381,59952 |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -236,7 +236,6 @@ |
237 | 237 | 'UploadFromStash' => 'includes/upload/UploadFromStash.php', |
238 | 238 | 'UploadFromFile' => 'includes/upload/UploadFromFile.php', |
239 | 239 | 'UploadFromUrl' => 'includes/upload/UploadFromUrl.php', |
240 | | - 'UploadFromChunks' => 'includes/upload/UploadFromChunks.php', |
241 | 240 | 'User' => 'includes/User.php', |
242 | 241 | 'UserArray' => 'includes/UserArray.php', |
243 | 242 | 'UserArrayFromResult' => 'includes/UserArray.php', |