| Index: trunk/phase3/includes/SpecialUpload.php |
| — | — | @@ -108,23 +108,60 @@ |
| 109 | 109 | * @access private |
| 110 | 110 | */ |
| 111 | 111 | function initialize_web_file( &$request ) { |
| 112 | | - global $wgTmpDirectory, $wgMaxUploadSize; |
| | 112 | + global $wgTmpDirectory, $wgMaxUploadSize, $wgUploadTempFileSize; |
| 113 | 113 | $url = $request->getText( 'wpUploadFile' ); |
| 114 | 114 | $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' ); |
| 115 | 115 | |
| 116 | | - if ( $wgMaxUploadSize < @filesize ( $url ) ) $error = true ; |
| 117 | | - else $error = !@copy( $url, $local_file ); |
| 118 | | - |
| 119 | 116 | $this->mUploadTempName = $local_file; |
| 120 | | - $this->mUploadSize = filesize( $local_file ); |
| | 117 | + $this->mUploadError = $this->curl_copy( $url, $local_file ); |
| | 118 | + $this->mUploadSize = $wgUploadTempFileSize ; |
| 121 | 119 | $this->mOname = array_pop( explode( '/', $url ) ); |
| 122 | | - $this->mUploadError = $error; |
| 123 | 120 | $this->mSessionKey = false; |
| 124 | 121 | $this->mStashed = false; |
| 125 | | - $this->mRemoveTempFile = false; // PHP will *not* handle this |
| | 122 | + $this->mRemoveTempFile = file_exists( $local_file ) ; // PHP will *not* handle this |
| 126 | 123 | } |
| 127 | 124 | |
| 128 | 125 | /** |
| | 126 | + * Safe copy from URL |
| | 127 | + * Returns true if there was an error, false otherwise |
| | 128 | + * @access private |
| | 129 | + */ |
| | 130 | + function curl_copy ( $url , $dest ) { |
| | 131 | + global $wgMaxUploadSize, $wgUploadTempFile, $wgUploadTempFileSize, $wgUser; |
| | 132 | + |
| | 133 | + if( !$wgUser->isAllowed( 'upload_by_url' ) ) { |
| | 134 | + $wgOut->permissionRequired( 'upload_by_url' ); |
| | 135 | + return true; |
| | 136 | + } |
| | 137 | + |
| | 138 | + $url = trim ( $url ) ; # Maybe remove some pasting blanks :-) |
| | 139 | + $u = strtolower ( $url ) ; |
| | 140 | + if( substr( $u, 0, 7 ) != 'http://' AND substr( $u, 0, 6 ) != 'ftp://' ) return true ; # Only HTTP or FTP URLs |
| | 141 | + |
| | 142 | + # Open temporary file |
| | 143 | + $wgUploadTempFileSize = 0 ; |
| | 144 | + $wgUploadTempFile = @fopen ( $this->mUploadTempName , "wb" ) ; |
| | 145 | + if ( $wgUploadTempFile === false ) return true ; # Could not open temporary file to write in |
| | 146 | + |
| | 147 | + $ch = curl_init(); |
| | 148 | + curl_setopt ($ch, CURLOPT_HTTP_VERSION, 1.0); # Probably not needed, but apparently can work around some bug |
| | 149 | + curl_setopt ($ch, CURLOPT_TIMEOUT, 10); # 10 seconds timeout |
| | 150 | + curl_setopt ($ch, CURLOPT_LOW_SPEED_LIMIT, 512); # 0.5KB per second minimum transfer speed |
| | 151 | + curl_setopt ($ch, CURLOPT_URL, $url); |
| | 152 | + curl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'wfUploadCurlCallback' ) ; |
| | 153 | + curl_exec ( $ch ) ; |
| | 154 | + $error = curl_errno ( $ch ) ? true : false ; |
| | 155 | +# if ( $error ) print curl_error ( $ch ) ; # Debugging output |
| | 156 | + curl_close ($ch); |
| | 157 | + |
| | 158 | + fclose ( $wgUploadTempFile ) ; |
| | 159 | + unset ( $wgUploadTempFile ) ; |
| | 160 | + if ( $error ) unlink ( $dest ) ; |
| | 161 | + |
| | 162 | + return $error ; |
| | 163 | + } |
| | 164 | + |
| | 165 | + /** |
| 129 | 166 | * Start doing stuff |
| 130 | 167 | * @access public |
| 131 | 168 | */ |
| — | — | @@ -458,12 +495,15 @@ |
| 459 | 496 | * @access private |
| 460 | 497 | */ |
| 461 | 498 | function saveTempUploadedFile( $saveName, $tempName ) { |
| 462 | | - global $wgOut; |
| | 499 | + global $wgOut, $wgAllowCopyUploads; |
| 463 | 500 | $archive = wfImageArchiveDir( $saveName, 'temp' ); |
| 464 | 501 | if ( !is_dir ( $archive ) ) wfMkdirParents( $archive ); |
| 465 | 502 | $stash = $archive . '/' . gmdate( "YmdHis" ) . '!' . $saveName; |
| 466 | 503 | |
| 467 | | - $success = $this->mRemoveTempFile |
| | 504 | + $remove_file = $this->mRemoveTempFile ; |
| | 505 | + if ( !$remove_file AND $wgAllowCopyUploads AND $this->mSourceType == 'web' ) $remove_file = true; |
| | 506 | + |
| | 507 | + $success = $remove_file |
| 468 | 508 | ? rename( $tempName, $stash ) |
| 469 | 509 | : move_uploaded_file( $tempName, $stash ); |
| 470 | 510 | if ( !$success ) { |
| — | — | @@ -661,8 +701,8 @@ |
| 662 | 702 | $watchChecked = $wgUser->getOption( 'watchdefault' ) |
| 663 | 703 | ? 'checked="checked"' |
| 664 | 704 | : ''; |
| 665 | | - |
| 666 | | - if ( $wgAllowCopyUploads AND $wgRequest->getText('source') == 'web' ) { |
| | 705 | + |
| | 706 | + if ( $wgAllowCopyUploads AND $wgRequest->getText('source') == 'web' AND $wgUser->isAllowed( 'upload_by_url' ) ) { |
| 667 | 707 | $sourcetype = 'text'; |
| 668 | 708 | $source_comment = '<input type="hidden" name="wpSourceType" value="web"/>' . wfMsgHtml( 'upload_source_url' ); |
| 669 | 709 | } else { |
| — | — | @@ -1152,4 +1192,20 @@ |
| 1153 | 1193 | } |
| 1154 | 1194 | |
| 1155 | 1195 | } |
| | 1196 | + |
| | 1197 | +/** |
| | 1198 | + * Callback function for CURL-based web transfer |
| | 1199 | + * Apparently needs to be global |
| | 1200 | + * @access private |
| | 1201 | + */ |
| | 1202 | +function wfUploadCurlCallback ($ch, $data) { |
| | 1203 | + global $wgUploadTempFile, $wgMaxUploadSize, $wgUploadTempFileSize; |
| | 1204 | + $length = strlen($data); |
| | 1205 | + $wgUploadTempFileSize += $length; |
| | 1206 | + if( $wgUploadTempFileSize > $wgMaxUploadSize ) return 0; |
| | 1207 | + fwrite( $wgUploadTempFile , $data ); |
| | 1208 | + return $length; |
| | 1209 | +} |
| | 1210 | + |
| | 1211 | + |
| 1156 | 1212 | ?> |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -908,7 +908,7 @@ |
| 909 | 909 | $wgGroupPermissions['sysop']['block'] = true; |
| 910 | 910 | $wgGroupPermissions['sysop']['createaccount'] = true; |
| 911 | 911 | $wgGroupPermissions['sysop']['delete'] = true; |
| 912 | | -$wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text |
| | 912 | +$wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text |
| 913 | 913 | $wgGroupPermissions['sysop']['editinterface'] = true; |
| 914 | 914 | $wgGroupPermissions['sysop']['import'] = true; |
| 915 | 915 | $wgGroupPermissions['sysop']['importupload'] = true; |
| — | — | @@ -921,8 +921,9 @@ |
| 922 | 922 | $wgGroupPermissions['sysop']['upload'] = true; |
| 923 | 923 | $wgGroupPermissions['sysop']['reupload'] = true; |
| 924 | 924 | $wgGroupPermissions['sysop']['reupload-shared'] = true; |
| 925 | | -$wgGroupPermissions['sysop']['unwatchedpages'] = true; |
| | 925 | +$wgGroupPermissions['sysop']['unwatchedpages'] = true; |
| 926 | 926 | $wgGroupPermissions['sysop']['autoconfirmed'] = true; |
| | 927 | +$wgGroupPermissions['sysop']['upload_by_url'] = true; |
| 927 | 928 | |
| 928 | 929 | // Permission to change users' group assignments |
| 929 | 930 | $wgGroupPermissions['bureaucrat']['userrights'] = true; |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -148,7 +148,7 @@ |
| 149 | 149 | * Pass page title as parameters to "linkshere" and "nolinkshere" and update |
| 150 | 150 | default message text |
| 151 | 151 | * Allows to upload from publicy accessible URL. Set $wgAllowCopyUploads = true ; in LocalSettings.php |
| 152 | | - Limited to $wgMaxUploadSize (default:100MB) |
| | 152 | + Limited to $wgMaxUploadSize (default:100MB); URL upload is limited to sysops by default |
| 153 | 153 | |
| 154 | 154 | == Languages updated == |
| 155 | 155 | |