Index: trunk/phase3/docs/upload.txt |
— | — | @@ -1,41 +1,2 @@ |
2 | | -Special:Upload: |
3 | | - |
4 | | -wfSpecialUpload |
5 | | - new UploadForm |
6 | | - mUpload = new UploadFrom... |
7 | | - execute() |
8 | | - $wgEnableUploads |
9 | | - isAllowed(upload) |
10 | | - isBlocked() |
11 | | - wfReadOnly() |
12 | | - processUpload() |
13 | | - internalProcessUpload() |
14 | | - wfRunHooks(UploadForm:BeforeProcessing) |
15 | | - mUpload->getTitle() |
16 | | - wfStripIllegalFilenameChars |
17 | | - splitExtensions() |
18 | | - checkFileExtension() |
19 | | - Title::makeTitleSafe |
20 | | - getUserPermissionsErrors(edit; upload; create) |
21 | | - mUpload->verifyUpload() |
22 | | - empty(mFileSize) |
23 | | - getTitle() |
24 | | - checkOverwrite() |
25 | | - fetchFile() |
26 | | - verifyFile() |
27 | | - checkMacBinary() |
28 | | - wfRunHooks(UploadVerification) |
29 | | - if(!ignoreWarning) mUpload->checkWarnings() |
30 | | - getInitialPageText() |
31 | | - mUpload->performUpload() |
32 | | - mLocalFile->upload() |
33 | | - if(isGood() && $watch) addWatch() |
34 | | - if(isGood()) wfRunHooks(UploadComplete) |
35 | | - wfRunHooks(SpecialUploadComplete) |
36 | | - |
37 | | -Changes: |
38 | | - * "Your file will be renamed to $1" check now done on the result of |
39 | | - Title::makeTitleSafe instead of filteredName |
40 | | - * getExistWarning only really does existence checks |
41 | | - * Other stuff forgotten to be documented |
42 | | - |
\ No newline at end of file |
| 2 | +This document describes how the current uploading system is build up and how |
| 3 | +custom backends can be built. (At least someday it will). |
Index: trunk/phase3/includes/upload/UploadFromStash.php |
— | — | @@ -1,8 +1,15 @@ |
2 | 2 | <?php |
3 | | - |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup upload |
| 6 | + * |
| 7 | + * Implements uploading from previously stored file. |
| 8 | + * |
| 9 | + * @author Bryan Tong Minh |
| 10 | + */ |
| 11 | + |
4 | 12 | class UploadFromStash extends UploadBase { |
5 | | - |
6 | | - static function isValidSessionKey( $key, $sessionData ) { |
| 13 | + public static function isValidSessionKey( $key, $sessionData ) { |
7 | 14 | return !empty( $key ) && |
8 | 15 | is_array( $sessionData ) && |
9 | 16 | isset( $sessionData[$key] ) && |
— | — | @@ -10,7 +17,7 @@ |
11 | 18 | $sessionData[$key]['version'] == self::SESSION_VERSION; |
12 | 19 | } |
13 | 20 | |
14 | | - static function isValidRequest( $request ) { |
| 21 | + public static function isValidRequest( $request ) { |
15 | 22 | $sessionData = $request->getSessionData( 'wsUploadData' ); |
16 | 23 | return self::isValidSessionKey( |
17 | 24 | $request->getInt( 'wpSessionKey' ), |
— | — | @@ -20,7 +27,7 @@ |
21 | 28 | /* |
22 | 29 | * some $na vars for uploadBase method compatibility. |
23 | 30 | */ |
24 | | - function initialize( $name, $sessionData, $na, $na2=false ) { |
| 31 | + public function initialize( $name, $sessionData, $na, $na2=false ) { |
25 | 32 | /** |
26 | 33 | * Confirming a temporarily stashed upload. |
27 | 34 | * We don't want path names to be forged, so we keep |
— | — | @@ -36,7 +43,7 @@ |
37 | 44 | $this->mFileProps = $sessionData['mFileProps']; |
38 | 45 | } |
39 | 46 | |
40 | | - function initializeFromRequest( &$request ) { |
| 47 | + public function initializeFromRequest( &$request ) { |
41 | 48 | $sessionKey = $request->getInt( 'wpSessionKey' ); |
42 | 49 | $sessionData = $request->getSessionData('wsUploadData'); |
43 | 50 | |
— | — | @@ -56,7 +63,7 @@ |
57 | 64 | /** |
58 | 65 | * We're here from "ignore warnings anyway" so return just OK |
59 | 66 | */ |
60 | | - function checkWarnings() { |
| 67 | + public function checkWarnings() { |
61 | 68 | return array(); |
62 | 69 | } |
63 | 70 | |
Index: trunk/phase3/includes/upload/UploadFromUrl.php |
— | — | @@ -1,5 +1,13 @@ |
2 | 2 | <?php |
3 | | - |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup upload |
| 6 | + * |
| 7 | + * Implements uploading from a HTTP resource. |
| 8 | + * |
| 9 | + * @author Bryan Tong Minh |
| 10 | + * @author Michael Dale |
| 11 | + */ |
4 | 12 | class UploadFromUrl extends UploadBase { |
5 | 13 | protected $mTempDownloadPath; |
6 | 14 | |
— | — | @@ -7,9 +15,10 @@ |
8 | 16 | protected $dl_mode = Http::SYNC_DOWNLOAD; |
9 | 17 | |
10 | 18 | /** |
11 | | - * Checks if the user is allowed to use the upload-by-URL feature |
| 19 | + * Checks if the user is allowed to use the upload-by-URL feature. If the |
| 20 | + * user is allowed, pass on permissions checking to the parent. |
12 | 21 | */ |
13 | | - static function isAllowed( $user ) { |
| 22 | + public static function isAllowed( $user ) { |
14 | 23 | if( !$user->isAllowed( 'upload_by_url' ) ) |
15 | 24 | return 'upload_by_url'; |
16 | 25 | return parent::isAllowed( $user ); |
— | — | @@ -18,13 +27,15 @@ |
19 | 28 | /** |
20 | 29 | * Checks if the upload from URL feature is enabled |
21 | 30 | */ |
22 | | - static function isEnabled() { |
| 31 | + public static function isEnabled() { |
23 | 32 | global $wgAllowCopyUploads; |
24 | 33 | return $wgAllowCopyUploads && parent::isEnabled(); |
25 | 34 | } |
26 | 35 | |
27 | | - /* entry point for API upload:: ASYNC_DOWNLOAD (if possible) */ |
28 | | - function initialize( $name, $url, $asyncdownload, $na = false ) { |
| 36 | + /** |
| 37 | + * Entry point for API upload:: ASYNC_DOWNLOAD (if possible) |
| 38 | + */ |
| 39 | + public function initialize( $name, $url, $asyncdownload, $na = false ) { |
29 | 40 | global $wgTmpDirectory, $wgPhpCli; |
30 | 41 | |
31 | 42 | // check for $asyncdownload request: |
— | — | @@ -36,8 +47,8 @@ |
37 | 48 | } |
38 | 49 | } |
39 | 50 | |
40 | | - $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' ); |
41 | | - parent::initialize( $name, $local_file, 0, true ); |
| 51 | + $localFile = tempnam( $wgTmpDirectory, 'WEBUPLOAD' ); |
| 52 | + parent::initialize( $name, $localFile, 0, true ); |
42 | 53 | |
43 | 54 | $this->mUrl = trim( $url ); |
44 | 55 | } |
— | — | @@ -50,7 +61,7 @@ |
51 | 62 | * Entry point for SpecialUpload no ASYNC_DOWNLOAD possible |
52 | 63 | * @param $request Object: WebRequest object |
53 | 64 | */ |
54 | | - function initializeFromRequest( &$request ) { |
| 65 | + public function initializeFromRequest( &$request ) { |
55 | 66 | |
56 | 67 | // set dl mode if not set: |
57 | 68 | if( !$this->dl_mode ) |
— | — | @@ -69,16 +80,16 @@ |
70 | 81 | /** |
71 | 82 | * Do the real fetching stuff |
72 | 83 | */ |
73 | | - function fetchFile() { |
74 | | - // entry point for SpecialUplaod |
75 | | - if( self::isValidURI( $this->mUrl ) === false ) { |
| 84 | + public function fetchFile() { |
| 85 | + // Entry point for SpecialUpload |
| 86 | + if( Http::isValidURI( $this->mUrl ) === false ) { |
76 | 87 | return Status::newFatal( 'upload-proto-error' ); |
77 | 88 | } |
78 | 89 | |
79 | | - // now do the actual download to the target file: |
| 90 | + // Now do the actual download to the target file: |
80 | 91 | $status = Http::doDownload( $this->mUrl, $this->mTempPath, $this->dl_mode ); |
81 | 92 | |
82 | | - // update the local filesize var: |
| 93 | + // Update the local filesize var: |
83 | 94 | $this->mFileSize = filesize( $this->mTempPath ); |
84 | 95 | |
85 | 96 | return $status; |
— | — | @@ -87,23 +98,13 @@ |
88 | 99 | /** |
89 | 100 | * @param $request Object: WebRequest object |
90 | 101 | */ |
91 | | - static function isValidRequest( $request ){ |
| 102 | + public static function isValidRequest( $request ){ |
92 | 103 | if( !$request->getVal( 'wpUploadFileURL' ) ) |
93 | 104 | return false; |
94 | 105 | // check that is a valid url: |
95 | | - return self::isValidURI( $request->getVal( 'wpUploadFileURL' ) ); |
| 106 | + return Http::isValidURI( $request->getVal( 'wpUploadFileURL' ) ); |
96 | 107 | } |
97 | 108 | |
98 | | - /** |
99 | | - * Checks that the given URI is a valid one |
100 | | - * @param $uri Mixed: URI to check for validity |
101 | | - */ |
102 | | - static function isValidURI( $uri ){ |
103 | | - return preg_match( |
104 | | - '/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/', |
105 | | - $uri, |
106 | | - $matches |
107 | | - ); |
108 | | - } |
109 | 109 | |
| 110 | + |
110 | 111 | } |
\ No newline at end of file |
Index: trunk/phase3/includes/upload/UploadBase.php |
— | — | @@ -1,11 +1,24 @@ |
2 | 2 | <?php |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup upload |
| 6 | + * |
| 7 | + * UploadBase and subclasses are the backend of MediaWiki's file uploads. |
| 8 | + * The frontends are formed by ApiUpload and SpecialUpload. |
| 9 | + * |
| 10 | + * See also includes/docs/upload.txt |
| 11 | + * |
| 12 | + * @author Brion Vibber |
| 13 | + * @author Bryan Tong Minh |
| 14 | + * @author Michael Dale |
| 15 | + */ |
| 16 | + |
| 17 | +abstract class UploadBase { |
| 18 | + protected $mTempPath; |
| 19 | + protected $mDesiredDestName, $mDestName, $mRemoveTempFile, $mSourceType; |
| 20 | + protected $mTitle = false, $mTitleError = 0; |
| 21 | + protected $mFilteredName, $mFinalExtension; |
3 | 22 | |
4 | | -class UploadBase { |
5 | | - var $mTempPath; |
6 | | - var $mDesiredDestName, $mDestName, $mRemoveTempFile, $mSourceType; |
7 | | - var $mTitle = false, $mTitleError = 0; |
8 | | - var $mFilteredName, $mFinalExtension; |
9 | | - |
10 | 23 | const SUCCESS = 0; |
11 | 24 | const OK = 0; |
12 | 25 | const BEFORE_PROCESSING = 1; |
— | — | @@ -29,7 +42,7 @@ |
30 | 43 | * Returns true if uploads are enabled. |
31 | 44 | * Can be override by subclasses. |
32 | 45 | */ |
33 | | - static function isEnabled() { |
| 46 | + public static function isEnabled() { |
34 | 47 | global $wgEnableUploads; |
35 | 48 | if ( !$wgEnableUploads ) |
36 | 49 | return false; |
— | — | @@ -46,7 +59,7 @@ |
47 | 60 | * identifying the missing permission. |
48 | 61 | * Can be overriden by subclasses. |
49 | 62 | */ |
50 | | - static function isAllowed( $user ) { |
| 63 | + public static function isAllowed( $user ) { |
51 | 64 | if( !$user->isAllowed( 'upload' ) ) |
52 | 65 | return 'upload'; |
53 | 66 | return true; |
— | — | @@ -58,21 +71,24 @@ |
59 | 72 | /** |
60 | 73 | * Create a form of UploadBase depending on wpSourceType and initializes it |
61 | 74 | */ |
62 | | - static function createFromRequest( &$request, $type = null ) { |
| 75 | + public static function createFromRequest( &$request, $type = null ) { |
63 | 76 | $type = $type ? $type : $request->getVal( 'wpSourceType' ); |
64 | 77 | |
65 | 78 | if( !$type ) |
66 | 79 | return null; |
67 | 80 | |
| 81 | + // Get the upload class |
68 | 82 | $type = ucfirst( $type ); |
69 | 83 | $className = 'UploadFrom' . $type; |
70 | 84 | wfDebug( __METHOD__ . ": class name: $className\n" ); |
71 | 85 | if( !in_array( $type, self::$uploadHandlers ) ) |
72 | 86 | return null; |
73 | 87 | |
| 88 | + // Check whether this upload class is enabled |
74 | 89 | if( !call_user_func( array( $className, 'isEnabled' ) ) ) |
75 | 90 | return null; |
76 | 91 | |
| 92 | + // Check whether the request is valid |
77 | 93 | if( !call_user_func( array( $className, 'isValidRequest' ), $request ) ) |
78 | 94 | return null; |
79 | 95 | |
— | — | @@ -85,33 +101,38 @@ |
86 | 102 | /** |
87 | 103 | * Check whether a request if valid for this handler |
88 | 104 | */ |
89 | | - static function isValidRequest( $request ) { |
| 105 | + public static function isValidRequest( $request ) { |
90 | 106 | return false; |
91 | 107 | } |
92 | 108 | |
93 | | - function __construct() {} |
| 109 | + public function __construct() {} |
94 | 110 | |
95 | 111 | /** |
96 | 112 | * Do the real variable initialization |
97 | 113 | */ |
98 | | - function initialize( $name, $tempPath, $fileSize, $removeTempFile = false ) { |
| 114 | + public function initialize( $name, $tempPath, $fileSize, $removeTempFile = false ) { |
99 | 115 | $this->mDesiredDestName = $name; |
100 | 116 | $this->mTempPath = $tempPath; |
101 | 117 | $this->mFileSize = $fileSize; |
102 | 118 | $this->mRemoveTempFile = $removeTempFile; |
103 | 119 | } |
| 120 | + |
| 121 | + /** |
| 122 | + * Initialize from a WebRequest. Override this in a subclass. |
| 123 | + */ |
| 124 | + public abstract function initializeFromRequest( &$request ); |
104 | 125 | |
105 | 126 | /** |
106 | 127 | * Fetch the file. Usually a no-op |
107 | 128 | */ |
108 | | - function fetchFile() { |
| 129 | + public function fetchFile() { |
109 | 130 | return Status::newGood(); |
110 | 131 | } |
111 | 132 | |
112 | 133 | /** |
113 | 134 | * Return the file size |
114 | 135 | */ |
115 | | - function isEmptyFile(){ |
| 136 | + public function isEmptyFile(){ |
116 | 137 | return empty( $this->mFileSize ); |
117 | 138 | } |
118 | 139 | |
— | — | @@ -119,7 +140,7 @@ |
120 | 141 | * Verify whether the upload is sane. |
121 | 142 | * Returns self::OK or else an array with error information |
122 | 143 | */ |
123 | | - function verifyUpload() { |
| 144 | + public function verifyUpload() { |
124 | 145 | /** |
125 | 146 | * If there was no filename or a zero size given, give up quick. |
126 | 147 | */ |
— | — | @@ -135,8 +156,7 @@ |
136 | 157 | $result['finalExt'] = $this->mFinalExtension; |
137 | 158 | return $result; |
138 | 159 | } |
139 | | - $this->mLocalFile = wfLocalFile( $nt ); |
140 | | - $this->mDestName = $this->mLocalFile->getName(); |
| 160 | + $this->mDestName = $this->getLocalFile()->getName(); |
141 | 161 | |
142 | 162 | /** |
143 | 163 | * In some cases we may forbid overwriting of existing files. |
— | — | @@ -171,7 +191,7 @@ |
172 | 192 | /** |
173 | 193 | * Verifies that it's ok to include the uploaded file |
174 | 194 | * |
175 | | - * this function seems to intermixes tmpfile and $this->mTempPath .. no idea why this is |
| 195 | + * FIXME: this function seems to intermixes tmpfile and $this->mTempPath .. no idea why this is |
176 | 196 | * |
177 | 197 | * @param string $tmpfile the full path of the temporary file to verify |
178 | 198 | * @return mixed true of the file is verified, a string or array otherwise. |
— | — | @@ -186,7 +206,7 @@ |
187 | 207 | |
188 | 208 | #check mime type, if desired |
189 | 209 | global $wgVerifyMimeType; |
190 | | - if ($wgVerifyMimeType) { |
| 210 | + if ( $wgVerifyMimeType ) { |
191 | 211 | global $wgMimeTypeBlacklist; |
192 | 212 | if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) |
193 | 213 | return array( 'filetype-badmime', $mime ); |
— | — | @@ -205,11 +225,11 @@ |
206 | 226 | } |
207 | 227 | |
208 | 228 | #check for htmlish code and javascript |
209 | | - if( $this->detectScript( $tmpfile, $mime, $this->mFinalExtension ) ) { |
| 229 | + if( self::detectScript( $tmpfile, $mime, $this->mFinalExtension ) ) { |
210 | 230 | return 'uploadscripted'; |
211 | 231 | } |
212 | 232 | if( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) { |
213 | | - if( $this->detectScriptInSvg( $tmpfile ) ) { |
| 233 | + if( self::detectScriptInSvg( $tmpfile ) ) { |
214 | 234 | return 'uploadscripted'; |
215 | 235 | } |
216 | 236 | } |
— | — | @@ -226,9 +246,13 @@ |
227 | 247 | } |
228 | 248 | |
229 | 249 | /** |
230 | | - * Check whether the user can edit, upload and create the image |
| 250 | + * Check whether the user can edit, upload and create the image. |
| 251 | + * |
| 252 | + * @param User $user the user to verify the permissions against |
| 253 | + * @return mixed An array as returned by getUserPermissionsErrors or true |
| 254 | + * in case the user has proper permissions. |
231 | 255 | */ |
232 | | - function verifyPermissions( $user ) { |
| 256 | + public function verifyPermissions( $user ) { |
233 | 257 | /** |
234 | 258 | * If the image is protected, non-sysop users won't be able |
235 | 259 | * to modify it by uploading a new revision. |
— | — | @@ -249,11 +273,14 @@ |
250 | 274 | |
251 | 275 | /** |
252 | 276 | * Check for non fatal problems with the file |
| 277 | + * |
| 278 | + * @return array Array of warnings |
253 | 279 | */ |
254 | | - function checkWarnings() { |
| 280 | + public function checkWarnings() { |
255 | 281 | $warning = array(); |
256 | 282 | |
257 | | - $filename = $this->mLocalFile->getName(); |
| 283 | + $localFile = $this->getLocalFile(); |
| 284 | + $filename = $localFile->getName(); |
258 | 285 | $n = strrpos( $filename, '.' ); |
259 | 286 | $partname = $n ? substr( $filename, 0, $n ) : $filename; |
260 | 287 | |
— | — | @@ -284,14 +311,14 @@ |
285 | 312 | $warning['emptyfile'] = true; |
286 | 313 | |
287 | 314 | |
288 | | - $exists = self::getExistsWarning( $this->mLocalFile ); |
| 315 | + $exists = self::getExistsWarning( $localFile ); |
289 | 316 | if( $exists !== false ) |
290 | 317 | $warning['exists'] = $exists; |
291 | 318 | |
292 | 319 | // Check whether this may be a thumbnail |
293 | 320 | if( $exists !== false && $exists[0] != 'thumb' |
294 | | - && self::isThumbName( $this->mLocalFile->getName() ) ){ |
295 | | - //make the title: |
| 321 | + && self::isThumbName( $filename ) ){ |
| 322 | + // Make the title |
296 | 323 | $nt = $this->getTitle(); |
297 | 324 | $warning['file-thumbnail-no'] = substr( $filename, 0, |
298 | 325 | strpos( $nt->getText() , '-' ) +1 ); |
— | — | @@ -324,22 +351,25 @@ |
325 | 352 | |
326 | 353 | # If the file existed before and was deleted, warn the user of this |
327 | 354 | # Don't bother doing so if the file exists now, however |
328 | | - if( $this->mLocalFile->wasDeleted() && !$this->mLocalFile->exists() ) |
329 | | - $warning['filewasdeleted'] = $this->mLocalFile->getTitle(); |
| 355 | + if( $localFile->wasDeleted() && !$localFile->exists() ) |
| 356 | + $warning['filewasdeleted'] = $localFile->getTitle(); |
330 | 357 | |
331 | 358 | return $warning; |
332 | 359 | } |
333 | 360 | |
334 | 361 | /** |
335 | | - * Really perform the upload. |
| 362 | + * Really perform the upload. Stores the file in the local repo, watches |
| 363 | + * if necessary and runs the UploadComplete hook. |
| 364 | + * |
| 365 | + * @return mixed Status indicating the whether the upload succeeded. |
336 | 366 | */ |
337 | | - function performUpload( $comment, $pageText, $watch, $user ) { |
| 367 | + public function performUpload( $comment, $pageText, $watch, $user ) { |
338 | 368 | wfDebug( "\n\n\performUpload: sum:" . $comment . ' c: ' . $pageText . ' w:' . $watch ); |
339 | | - $status = $this->mLocalFile->upload( $this->mTempPath, $comment, $pageText, |
| 369 | + $status = $this->getLocalFile()->upload( $this->mTempPath, $comment, $pageText, |
340 | 370 | File::DELETE_SOURCE, $this->mFileProps, false, $user ); |
341 | 371 | |
342 | 372 | if( $status->isGood() && $watch ) |
343 | | - $user->addWatch( $this->mLocalFile->getTitle() ); |
| 373 | + $user->addWatch( $this->getLocalFile()->getTitle() ); |
344 | 374 | |
345 | 375 | if( $status->isGood() ) |
346 | 376 | wfRunHooks( 'UploadComplete', array( &$this ) ); |
— | — | @@ -348,9 +378,12 @@ |
349 | 379 | } |
350 | 380 | |
351 | 381 | /** |
352 | | - * Returns a title or null |
| 382 | + * Returns the title of the file to be uploaded. Sets mTitleError in case |
| 383 | + * the name was illegal. |
| 384 | + * |
| 385 | + * @return Title The title of the file or null in case the name was illegal |
353 | 386 | */ |
354 | | - function getTitle() { |
| 387 | + public function getTitle() { |
355 | 388 | if ( $this->mTitle !== false ) |
356 | 389 | return $this->mTitle; |
357 | 390 | |
— | — | @@ -415,7 +448,10 @@ |
416 | 449 | return $this->mTitle = $nt; |
417 | 450 | } |
418 | 451 | |
419 | | - function getLocalFile() { |
| 452 | + /** |
| 453 | + * Return the local file and initializes if necessary. |
| 454 | + */ |
| 455 | + public function getLocalFile() { |
420 | 456 | if( is_null( $this->mLocalFile ) ) { |
421 | 457 | $nt = $this->getTitle(); |
422 | 458 | $this->mLocalFile = is_null( $nt ) ? null : wfLocalFile( $nt ); |
— | — | @@ -435,14 +471,20 @@ |
436 | 472 | * @return string - full path the stashed file, or false on failure |
437 | 473 | * @access private |
438 | 474 | */ |
439 | | - function saveTempUploadedFile( $saveName, $tempName ) { |
| 475 | + protected function saveTempUploadedFile( $saveName, $tempName ) { |
440 | 476 | $repo = RepoGroup::singleton()->getLocalRepo(); |
441 | 477 | $status = $repo->storeTemp( $saveName, $tempName ); |
442 | 478 | return $status; |
443 | 479 | } |
444 | 480 | |
445 | | - /* append to a stashed file */ |
446 | | - function appendToUploadFile( $srcPath, $toAppendPath ){ |
| 481 | + /** |
| 482 | + * Append a file to a stashed file. |
| 483 | + * |
| 484 | + * @param string $srcPath Path to file to append from |
| 485 | + * @param string $toAppendPath Path to file to append to |
| 486 | + * @return Status Status |
| 487 | + */ |
| 488 | + public function appendToUploadFile( $srcPath, $toAppendPath ){ |
447 | 489 | $repo = RepoGroup::singleton()->getLocalRepo(); |
448 | 490 | $status = $repo->append( $srcPath, $toAppendPath ); |
449 | 491 | return $status; |
— | — | @@ -454,21 +496,19 @@ |
455 | 497 | * Returns a key value which will be passed through a form |
456 | 498 | * to pick up the path info on a later invocation. |
457 | 499 | * |
458 | | - * @return int |
459 | | - * @access private |
| 500 | + * @return int Session key |
460 | 501 | */ |
461 | | - function stashSession() { |
| 502 | + public function stashSession() { |
462 | 503 | $status = $this->saveTempUploadedFile( $this->mDestName, $this->mTempPath ); |
463 | 504 | if( !$status->isOK() ) { |
464 | 505 | # Couldn't save the file. |
465 | 506 | return false; |
466 | 507 | } |
467 | | - $mTempPath = $status->value; |
468 | 508 | if(!isset($_SESSION)) |
469 | 509 | session_start(); // start up the session (might have been previously closed to prevent php session locking) |
470 | 510 | $key = $this->getSessionKey(); |
471 | 511 | $_SESSION['wsUploadData'][$key] = array( |
472 | | - 'mTempPath' => $mTempPath, |
| 512 | + 'mTempPath' => $status->value, |
473 | 513 | 'mFileSize' => $this->mFileSize, |
474 | 514 | 'mFileProps' => $this->mFileProps, |
475 | 515 | 'version' => self::SESSION_VERSION, |
— | — | @@ -477,9 +517,9 @@ |
478 | 518 | } |
479 | 519 | |
480 | 520 | /** |
481 | | - * Pull session key gen from stash in cases where we want to start an upload without much information |
| 521 | + * Generate a random session key from stash in cases where we want to start an upload without much information |
482 | 522 | */ |
483 | | - function getSessionKey(){ |
| 523 | + protected function getSessionKey(){ |
484 | 524 | $key = mt_rand( 0, 0x7fffffff ); |
485 | 525 | $_SESSION['wsUploadData'][$key] = array(); |
486 | 526 | return $key; |
— | — | @@ -489,7 +529,7 @@ |
490 | 530 | * Remove a temporarily kept file stashed by saveTempUploadedFile(). |
491 | 531 | * @return success |
492 | 532 | */ |
493 | | - function unsaveUploadedFile() { |
| 533 | + public function unsaveUploadedFile() { |
494 | 534 | $repo = RepoGroup::singleton()->getLocalRepo(); |
495 | 535 | $success = $repo->freeTemp( $this->mTempPath ); |
496 | 536 | return $success; |
— | — | @@ -500,14 +540,14 @@ |
501 | 541 | * on exit to clean up. |
502 | 542 | * @access private |
503 | 543 | */ |
504 | | - function cleanupTempFile() { |
| 544 | + public function cleanupTempFile() { |
505 | 545 | if ( $this->mRemoveTempFile && $this->mTempPath && file_exists( $this->mTempPath ) ) { |
506 | 546 | wfDebug( __METHOD__ . ": Removing temporary file {$this->mTempPath}\n" ); |
507 | 547 | unlink( $this->mTempPath ); |
508 | 548 | } |
509 | 549 | } |
510 | 550 | |
511 | | - function getTempPath() { |
| 551 | + public function getTempPath() { |
512 | 552 | return $this->mTempPath; |
513 | 553 | } |
514 | 554 | |
— | — | @@ -602,7 +642,7 @@ |
603 | 643 | * @param string $extension The extension of the file |
604 | 644 | * @return bool true if the file contains something looking like embedded scripts |
605 | 645 | */ |
606 | | - function detectScript( $file, $mime, $extension ) { |
| 646 | + public static function detectScript( $file, $mime, $extension ) { |
607 | 647 | global $wgAllowTitlesInSVG; |
608 | 648 | |
609 | 649 | #ugly hack: for text files, always look at the entire file. |
— | — | @@ -700,7 +740,7 @@ |
701 | 741 | return false; |
702 | 742 | } |
703 | 743 | |
704 | | - function detectScriptInSvg( $filename ) { |
| 744 | + protected function detectScriptInSvg( $filename ) { |
705 | 745 | $check = new XmlTypeCheck( $filename, array( $this, 'checkSvgScriptCallback' ) ); |
706 | 746 | return $check->filterMatch; |
707 | 747 | } |
— | — | @@ -708,7 +748,7 @@ |
709 | 749 | /** |
710 | 750 | * @todo Replace this with a whitelist filter! |
711 | 751 | */ |
712 | | - function checkSvgScriptCallback( $element, $attribs ) { |
| 752 | + public function checkSvgScriptCallback( $element, $attribs ) { |
713 | 753 | $stripped = $this->stripXmlNamespace( $element ); |
714 | 754 | |
715 | 755 | if( $stripped == 'script' ) { |
— | — | @@ -745,7 +785,7 @@ |
746 | 786 | * or a string containing feedback from the virus scanner if a virus was found. |
747 | 787 | * If textual feedback is missing but a virus was found, this function returns true. |
748 | 788 | */ |
749 | | - function detectVirus( $file ) { |
| 789 | + public static function detectVirus( $file ) { |
750 | 790 | global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut; |
751 | 791 | |
752 | 792 | if ( !$wgAntivirus ) { |
— | — | @@ -843,7 +883,7 @@ |
844 | 884 | * |
845 | 885 | * @access private |
846 | 886 | */ |
847 | | - function checkMacBinary() { |
| 887 | + private function checkMacBinary() { |
848 | 888 | $macbin = new MacBinary( $this->mTempPath ); |
849 | 889 | if( $macbin->isValid() ) { |
850 | 890 | $dataFile = tempnam( wfTempDir(), 'WikiMacBinary' ); |
— | — | @@ -865,18 +905,19 @@ |
866 | 906 | * Check if there's an overwrite conflict and, if so, if restrictions |
867 | 907 | * forbid this user from performing the upload. |
868 | 908 | * |
869 | | - * @return mixed true on success, WikiError on failure |
| 909 | + * @return mixed true on success, error string on failure |
870 | 910 | * @access private |
871 | 911 | */ |
872 | | - function checkOverwrite() { |
| 912 | + private function checkOverwrite() { |
873 | 913 | global $wgUser; |
874 | 914 | // First check whether the local file can be overwritten |
875 | | - if( $this->mLocalFile->exists() ) |
876 | | - if( !self::userCanReUpload( $wgUser, $this->mLocalFile ) ) |
| 915 | + $file = $this->getLocalFile(); |
| 916 | + if( $file->exists() ) |
| 917 | + if( !self::userCanReUpload( $wgUser, $file ) ) |
877 | 918 | return 'fileexists-forbidden'; |
878 | 919 | |
879 | 920 | // Check shared conflicts |
880 | | - $file = wfFindFile( $this->mLocalFile->getName() ); |
| 921 | + $file = wfFindFile( $file->getName() ); |
881 | 922 | if ( $file && ( !$wgUser->isAllowed( 'reupload' ) || |
882 | 923 | !$wgUser->isAllowed( 'reupload-shared' ) ) ) |
883 | 924 | return 'fileexists-shared-forbidden'; |
— | — | @@ -904,6 +945,17 @@ |
905 | 946 | return $user->getId() == $img->getUser( 'id' ); |
906 | 947 | } |
907 | 948 | |
| 949 | + /** |
| 950 | + * Helper function that does various existence checks for a file. |
| 951 | + * The following checks are performed: |
| 952 | + * - The file exists |
| 953 | + * - Article with the same name as the file exists |
| 954 | + * - File exists with normalized extension |
| 955 | + * - The file looks like a thumbnail and the original exists |
| 956 | + * |
| 957 | + * @param File $file The file to check |
| 958 | + * @return mixed False if the file does not exists, else an array |
| 959 | + */ |
908 | 960 | public static function getExistsWarning( $file ) { |
909 | 961 | if( $file->exists() ) |
910 | 962 | return array( 'exists', $file ); |
— | — | @@ -944,6 +996,9 @@ |
945 | 997 | return false; |
946 | 998 | } |
947 | 999 | |
| 1000 | + /** |
| 1001 | + * Helper function that checks whether the filename looks like a thumbnail |
| 1002 | + */ |
948 | 1003 | public static function isThumbName( $filename ) { |
949 | 1004 | $n = strrpos( $filename, '.' ); |
950 | 1005 | $partname = $n ? substr( $filename, 0, $n ) : $filename; |
Index: trunk/phase3/includes/upload/UploadFromChunks.php |
— | — | @@ -1,5 +1,10 @@ |
2 | 2 | <?php |
3 | 3 | /** |
| 4 | + * @file |
| 5 | + * @ingroup upload |
| 6 | + * |
| 7 | + * @author Michael Dale |
| 8 | + * |
4 | 9 | * first destination checks are made (if ignorewarnings is not checked) errors / warning is returned. |
5 | 10 | * |
6 | 11 | * we return the uploadUrl |
Index: trunk/phase3/includes/upload/UploadFromFile.php |
— | — | @@ -1,7 +1,15 @@ |
2 | 2 | <?php |
3 | | - |
| 3 | +/** |
| 4 | + * @file |
| 5 | + * @ingroup upload |
| 6 | + * |
| 7 | + * @author Bryan Tong Minh |
| 8 | + * |
| 9 | + * Implements regular file uploads |
| 10 | + */ |
4 | 11 | class UploadFromFile extends UploadBase { |
5 | 12 | |
| 13 | + |
6 | 14 | function initializeFromRequest( &$request ) { |
7 | 15 | $desiredDestName = $request->getText( 'wpDestFile' ); |
8 | 16 | if( !$desiredDestName ) |
Index: trunk/phase3/includes/HttpFunctions.php |
— | — | @@ -54,7 +54,7 @@ |
55 | 55 | // check for redirects: |
56 | 56 | if( isset( $head['Location'] ) && strrpos( $head[0], '302' ) !== false ){ |
57 | 57 | if( $redirectCount < $wgMaxRedirects ){ |
58 | | - if( UploadFromUrl::isValidURI( $head['Location'] ) ){ |
| 58 | + if( self::isValidURI( $head['Location'] ) ){ |
59 | 59 | return self::doDownload( $head['Location'], $target_file_path, $dl_mode, $redirectCount++ ); |
60 | 60 | } else { |
61 | 61 | return Status::newFatal( 'upload-proto-error' ); |
— | — | @@ -272,6 +272,18 @@ |
273 | 273 | global $wgVersion; |
274 | 274 | return "MediaWiki/$wgVersion"; |
275 | 275 | } |
| 276 | + |
| 277 | + /** |
| 278 | + * Checks that the given URI is a valid one |
| 279 | + * @param $uri Mixed: URI to check for validity |
| 280 | + */ |
| 281 | + public static function isValidURI( $uri ){ |
| 282 | + return preg_match( |
| 283 | + '/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/', |
| 284 | + $uri, |
| 285 | + $matches |
| 286 | + ); |
| 287 | + } |
276 | 288 | } |
277 | 289 | |
278 | 290 | class HttpRequest { |
— | — | @@ -322,7 +334,7 @@ |
323 | 335 | */ |
324 | 336 | public function doRequest() { |
325 | 337 | # Make sure we have a valid url |
326 | | - if( !UploadFromUrl::isValidURI( $this->url ) ) |
| 338 | + if( !Http::isValidURI( $this->url ) ) |
327 | 339 | return Status::newFatal('bad-url'); |
328 | 340 | |
329 | 341 | # Use curl if available |