14afc62fb15aee6938dfd09523c8a135fb314e60
[lhc/web/wiklou.git] / includes / api / ApiUpload.php
1 <?php
2
3 /*
4 * Created on Aug 21, 2008
5 * API for MediaWiki 1.8+
6 *
7 * Copyright (C) 2008 - 2009 Bryan Tong Minh <Bryan.TongMinh@Gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 */
24
25 if (!defined('MEDIAWIKI')) {
26 // Eclipse helper - will be ignored in production
27 require_once ("ApiBase.php");
28 }
29
30
31 /**
32 * @ingroup API
33 */
34 class ApiUpload extends ApiBase {
35 var $mUpload = null;
36
37 public function __construct($main, $action) {
38 parent :: __construct($main, $action);
39 }
40
41 public function execute() {
42 global $wgUser;
43
44
45 $this->getMain()->isWriteMode();
46 $this->mParams = $this->extractRequestParams();
47 $request = $this->getMain()->getRequest();
48
49 //do token checks:
50 if(is_null($this->mParams['token']))
51 $this->dieUsageMsg(array('missingparam', 'token'));
52 if(!$wgUser->matchEditToken($this->mParams['token']))
53 $this->dieUsageMsg(array('sessionfailure'));
54
55
56 // Add the uploaded file to the params array
57 $this->mParams['file'] = $request->getFileName( 'file' );
58
59 // Check whether upload is enabled
60 if( !UploadBase::isEnabled() )
61 $this->dieUsageMsg( array( 'uploaddisabled' ) );
62
63 wfDebug("running require param\n");
64 // One and only one of the following parameters is needed
65 $this->requireOnlyOneParameter( $this->mParams,
66 'sessionkey', 'file', 'url', 'enablechunks' );
67
68 if( $this->mParams['enablechunks'] ){
69 //chunks upload enabled
70 $this->mUpload = new UploadFromChunks();
71 $this->mUpload->initializeFromParams( $this->mParams, $request );
72
73 //if getAPIresult did not exit report the status error:
74 if( isset( $this->mUpload->status[ 'error' ] ) )
75 $this->dieUsageMsg( $this->mUpload->status[ 'error' ] );
76
77 }else if( $this->mParams['internalhttpsession'] ){
78 $sd = & $_SESSION['wsDownload'][ $this->mParams['internalhttpsession'] ];
79
80 //get the params from the init session:
81 $this->mUpload = new UploadFromFile();
82
83 $this->mUpload->initialize( $this->mParams['filename'],
84 $sd['target_file_path'],
85 filesize( $sd['target_file_path'] )
86 );
87
88 if( !isset( $this->mUpload ) )
89 $this->dieUsage( 'No upload module set', 'nomodule' );
90
91 }else if( $this->mParams['httpstatus'] && $this->mParams['sessionkey']){
92 //return the status of the given upload session_key:
93 if(!isset($_SESSION['wsDownload'][ $this->mParams['sessionkey'] ])){
94 return $this->getResult()->addValue( null, $this->getModuleName(),
95 array( 'error' => 'invalid-session-key'
96 ));
97 }
98 $sd = & $_SESSION['wsDownload'][ $this->mParams['sessionkey'] ];
99 //keep passing down the upload sessionkey
100 $statusResult = array(
101 'upload_session_key' => $this->mParams['sessionkey']
102 );
103
104 //put values into the final apiResult if available
105 if( isset($sd['apiUploadResult'])) $statusResult['apiUploadResult'] = $sd['apiUploadResult'];
106 if( isset($sd['loaded']) ) $statusResult['loaded'] = $sd['loaded'];
107 if( isset($sd['content_length']) ) $statusResult['content_length'] = $sd['content_length'];
108
109 return $this->getResult()->addValue( null, $this->getModuleName(),
110 $statusResult
111 );
112 }else if( $this->mParams['sessionkey'] ) {
113 // Stashed upload
114 $this->mUpload = new UploadFromStash();
115 $this->mUpload->initialize( $this->mParams['filename'], $_SESSION['wsUploadData'][$this->mParams['sessionkey']] );
116 }else{
117 // Upload from url or file
118 // Parameter filename is required
119 if( !isset( $this->mParams['filename'] ) )
120 $this->dieUsageMsg( array( 'missingparam', 'filename' ) );
121
122 // Initialize $this->mUpload
123 if( isset( $this->mParams['file'] ) ) {
124 $this->mUpload = new UploadFromFile();
125 $this->mUpload->initialize(
126 $request->getFileName( 'file' ),
127 $request->getFileTempName( 'file' ),
128 $request->getFileSize( 'file' )
129 );
130 } elseif( isset( $this->mParams['url'] ) ) {
131
132 $this->mUpload = new UploadFromUrl();
133 $this->mUpload->initialize( $this->mParams['filename'], $this->mParams['url'], $this->mParams['asyncdownload']);
134
135 $status = $this->mUpload->fetchFile();
136 if( !$status->isOK() ){
137 return $this->dieUsage( 'fetchfileerror', $status->getWikiText() );
138 }
139 //check if we doing a async request set session info and return the upload_session_key)
140 if( $this->mUpload->isAsync() ){
141 $upload_session_key = $status->value;
142 //update the session with anything with the params we will need to finish up the upload later on:
143 if(!isset($_SESSION['wsDownload'][$upload_session_key]))
144 $_SESSION['wsDownload'][$upload_session_key] = array();
145
146 $sd =& $_SESSION['wsDownload'][$upload_session_key];
147
148 //copy mParams for finishing up after:
149 $sd['mParams'] = $this->mParams;
150
151 return $this->getResult()->addValue( null, $this->getModuleName(),
152 array( 'upload_session_key' => $upload_session_key
153 ));
154 }
155 //else the file downloaded in place continue with validation:
156 }
157 }
158
159 if( !isset( $this->mUpload ) )
160 $this->dieUsage( 'No upload module set', 'nomodule' );
161
162 //finish up the exec command:
163 $this->doExecUpload();
164 }
165 function doExecUpload(){
166 global $wgUser;
167 //Check whether the user has the appropriate permissions to upload anyway
168 $permission = $this->mUpload->isAllowed( $wgUser );
169
170
171 if( $permission !== true ) {
172 if( !$wgUser->isLoggedIn() )
173 $this->dieUsageMsg( array( 'mustbeloggedin', 'upload' ) );
174 else
175 $this->dieUsageMsg( array( 'badaccess-groups' ) );
176 }
177 // Perform the upload
178 $result = $this->performUpload();
179 // Cleanup any temporary mess
180 $this->mUpload->cleanupTempFile();
181 $this->getResult()->addValue( null, $this->getModuleName(), $result );
182 }
183 private function performUpload() {
184 global $wgUser;
185 $result = array();
186 $resultDetails = null;
187 $permErrors = $this->mUpload->verifyPermissions( $wgUser );
188 if( $permErrors !== true ) {
189 $result['result'] = 'Failure';
190 $result['error'] = 'permission-denied';
191 return $result;
192 }
193 $verification = $this->mUpload->verifyUpload( $resultDetails );
194 if( $verification != UploadBase::OK ) {
195 $result['result'] = 'Failure';
196 switch( $verification ) {
197 case UploadBase::EMPTY_FILE:
198 $result['error'] = 'empty-file';
199 break;
200 case UploadBase::FILETYPE_MISSING:
201 $result['error'] = 'filetype-missing';
202 break;
203 case UploadBase::FILETYPE_BADTYPE:
204 global $wgFileExtensions;
205 $result['error'] = 'filetype-banned';
206 $result['filetype'] = $resultDetails['finalExt'];
207 $result['allowed-filetypes'] = $wgFileExtensions;
208 break;
209 case UploadBase::MIN_LENGHT_PARTNAME:
210 $result['error'] = 'filename-tooshort';
211 break;
212 case UploadBase::ILLEGAL_FILENAME:
213 $result['error'] = 'illegal-filename';
214 $result['filename'] = $resultDetails['filtered'];
215 break;
216 case UploadBase::OVERWRITE_EXISTING_FILE:
217 $result['error'] = 'overwrite';
218 break;
219 case UploadBase::VERIFICATION_ERROR:
220 $result['error'] = 'verification-error';
221 $args = $resultDetails['veri'];
222 $code = array_shift( $args );
223 $result['verification-error'] = $code;
224 $result['args'] = $args;
225 $this->getResult()->setIndexedTagName( $result['args'], 'arg' );
226 break;
227 case UploadBase::UPLOAD_VERIFICATION_ERROR:
228 $result['error'] = 'upload-verification-error';
229 $result['upload-verification-error'] = $resultDetails['error'];
230 break;
231 default:
232 $result['error'] = 'unknown-error';
233 $result['code'] = $verification;
234 break;
235 }
236 return $result;
237 }
238 if( !$this->mParams['ignorewarnings'] ) {
239 $warnings = $this->mUpload->checkWarnings();
240 if( $warnings ) {
241 $this->getResult()->setIndexedTagName( $warnings, 'warning' );
242
243 $result['result'] = 'Warning';
244 $result['warnings'] = $warnings;
245 if( isset( $result['filewasdeleted'] ) )
246 $result['filewasdeleted'] = $result['filewasdeleted']->getDBkey();
247
248 $sessionKey = $this->mUpload->stashSession();
249 if( $sessionKey )
250 $result['sessionkey'] = $sessionKey;
251 return $result;
252 }
253 }
254 //do the upload
255 $status = $this->mUpload->performUpload( $this->mParams['comment'],
256 $this->mParams['comment'], $this->mParams['watch'], $wgUser );
257
258 if( !$status->isGood() ) {
259 $result['result'] = 'Failure';
260 $result['error'] = 'internal-error';
261 $result['details'] = $status->getErrorsArray();
262 $this->getResult()->setIndexedTagName( $result['details'], 'error' );
263 return $result;
264 }
265
266 $file = $this->mUpload->getLocalFile();
267 $result['result'] = 'Success';
268 $result['filename'] = $file->getName();
269
270
271 // Append imageinfo to the result
272
273 //might be a cleaner way to call this:
274 $imParam = ApiQueryImageInfo::getAllowedParams();
275 $imProp = $imParam['prop'][ApiBase :: PARAM_TYPE];
276 $result['imageinfo'] = ApiQueryImageInfo::getInfo( $file,
277 array_flip( $imProp ),
278 $this->getResult() );
279
280 wfDebug("\n\n return result: " . print_r($result, true));
281
282 return $result;
283 }
284
285 public function mustBePosted() {
286 return true;
287 }
288
289 public function getAllowedParams() {
290 return array (
291 'filename' => null,
292 'file' => null,
293 'chunk' => null,
294 'url' => null,
295 'token' => null,
296 'enablechunks' => null,
297 'comment' => array(
298 ApiBase :: PARAM_DFLT => ''
299 ),
300 'asyncdownload'=>false,
301 'watch' => false,
302 'ignorewarnings' => false,
303 'done' => false,
304 'sessionkey' => null,
305 'httpstatus' => null,
306 'chunksessionkey'=> null,
307 'internalhttpsession'=> null,
308 );
309 }
310
311 public function getParamDescription() {
312 return array (
313 'filename' => 'Target filename',
314 'file' => 'File contents',
315 'chunk'=> 'Chunk File Contents',
316 'url' => 'Url to upload from',
317 'comment' => 'Upload comment or initial page text',
318 'token' => 'Edit token. You can get one of these through prop=info (this helps avoid remote ajax upload requests with your credentials)',
319 'enablechunks' => 'Boolean If we are in chunk mode; accepts many small file POSTs',
320 'asyncdownload' => 'If we should download the url asyncrously usefull for large http downloads (returns a upload session key to get status updates in subquent calls)',
321 'watch' => 'Watch the page',
322 'ignorewarnings' => 'Ignore any warnings',
323 'done' => 'When used with "chunks", Is sent to notify the api The last chunk is being uploaded.',
324 'sessionkey' => 'Session key in case there were any warnings.',
325 'httpstatus' => 'When set to true, will return the status of a given sessionKey (used for progress meters)',
326 'chunksessionkey' => 'Used to sync uploading of chunks',
327 'internalhttpsession' => 'Used internally for http session downloads',
328 );
329 }
330
331 public function getDescription() {
332 return array(
333 'Upload an File'
334 );
335 }
336
337 protected function getExamples() {
338 return array (
339 'api.php?action=upload&filename=Wiki.png&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png&ignorewarnings'
340 );
341 }
342
343 public function getVersion() {
344 return __CLASS__ . ': $Id: ApiUpload.php 51812 2009-06-12 23:45:20Z dale $';
345 }
346 }
347