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