From 9adfe72e98164ec216e62aa352e1170de5fbcb29 Mon Sep 17 00:00:00 2001 From: Magnus Manske Date: Tue, 22 Aug 2006 12:37:16 +0000 Subject: [PATCH] Switched URL upload function to CURL 10 sec timeout, 0.5KB/sec minimum transfer rate Default URL upload permission for sysops only --- RELEASE-NOTES | 2 +- includes/DefaultSettings.php | 5 ++- includes/SpecialUpload.php | 78 +++++++++++++++++++++++++++++++----- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index df3f729911..8f8d863ba6 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -148,7 +148,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * Pass page title as parameters to "linkshere" and "nolinkshere" and update default message text * Allows to upload from publicy accessible URL. Set $wgAllowCopyUploads = true ; in LocalSettings.php - Limited to $wgMaxUploadSize (default:100MB) + Limited to $wgMaxUploadSize (default:100MB); URL upload is limited to sysops by default == Languages updated == diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 9d6a3926e7..43f00ab94c 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -908,7 +908,7 @@ $wgGroupPermissions['bot' ]['autoconfirmed'] = true; $wgGroupPermissions['sysop']['block'] = true; $wgGroupPermissions['sysop']['createaccount'] = true; $wgGroupPermissions['sysop']['delete'] = true; -$wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text +$wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text $wgGroupPermissions['sysop']['editinterface'] = true; $wgGroupPermissions['sysop']['import'] = true; $wgGroupPermissions['sysop']['importupload'] = true; @@ -921,8 +921,9 @@ $wgGroupPermissions['sysop']['trackback'] = true; $wgGroupPermissions['sysop']['upload'] = true; $wgGroupPermissions['sysop']['reupload'] = true; $wgGroupPermissions['sysop']['reupload-shared'] = true; -$wgGroupPermissions['sysop']['unwatchedpages'] = true; +$wgGroupPermissions['sysop']['unwatchedpages'] = true; $wgGroupPermissions['sysop']['autoconfirmed'] = true; +$wgGroupPermissions['sysop']['upload_by_url'] = true; // Permission to change users' group assignments $wgGroupPermissions['bureaucrat']['userrights'] = true; diff --git a/includes/SpecialUpload.php b/includes/SpecialUpload.php index 7f567f911a..8ee353cf36 100644 --- a/includes/SpecialUpload.php +++ b/includes/SpecialUpload.php @@ -108,20 +108,57 @@ class UploadForm { * @access private */ function initialize_web_file( &$request ) { - global $wgTmpDirectory, $wgMaxUploadSize; + global $wgTmpDirectory, $wgMaxUploadSize, $wgUploadTempFileSize; $url = $request->getText( 'wpUploadFile' ); $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' ); - if ( $wgMaxUploadSize < @filesize ( $url ) ) $error = true ; - else $error = !@copy( $url, $local_file ); - $this->mUploadTempName = $local_file; - $this->mUploadSize = filesize( $local_file ); + $this->mUploadError = $this->curl_copy( $url, $local_file ); + $this->mUploadSize = $wgUploadTempFileSize ; $this->mOname = array_pop( explode( '/', $url ) ); - $this->mUploadError = $error; $this->mSessionKey = false; $this->mStashed = false; - $this->mRemoveTempFile = false; // PHP will *not* handle this + $this->mRemoveTempFile = file_exists( $local_file ) ; // PHP will *not* handle this + } + + /** + * Safe copy from URL + * Returns true if there was an error, false otherwise + * @access private + */ + function curl_copy ( $url , $dest ) { + global $wgMaxUploadSize, $wgUploadTempFile, $wgUploadTempFileSize, $wgUser; + + if( !$wgUser->isAllowed( 'upload_by_url' ) ) { + $wgOut->permissionRequired( 'upload_by_url' ); + return true; + } + + $url = trim ( $url ) ; # Maybe remove some pasting blanks :-) + $u = strtolower ( $url ) ; + if( substr( $u, 0, 7 ) != 'http://' AND substr( $u, 0, 6 ) != 'ftp://' ) return true ; # Only HTTP or FTP URLs + + # Open temporary file + $wgUploadTempFileSize = 0 ; + $wgUploadTempFile = @fopen ( $this->mUploadTempName , "wb" ) ; + if ( $wgUploadTempFile === false ) return true ; # Could not open temporary file to write in + + $ch = curl_init(); + curl_setopt ($ch, CURLOPT_HTTP_VERSION, 1.0); # Probably not needed, but apparently can work around some bug + curl_setopt ($ch, CURLOPT_TIMEOUT, 10); # 10 seconds timeout + curl_setopt ($ch, CURLOPT_LOW_SPEED_LIMIT, 512); # 0.5KB per second minimum transfer speed + curl_setopt ($ch, CURLOPT_URL, $url); + curl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'wfUploadCurlCallback' ) ; + curl_exec ( $ch ) ; + $error = curl_errno ( $ch ) ? true : false ; +# if ( $error ) print curl_error ( $ch ) ; # Debugging output + curl_close ($ch); + + fclose ( $wgUploadTempFile ) ; + unset ( $wgUploadTempFile ) ; + if ( $error ) unlink ( $dest ) ; + + return $error ; } /** @@ -458,12 +495,15 @@ class UploadForm { * @access private */ function saveTempUploadedFile( $saveName, $tempName ) { - global $wgOut; + global $wgOut, $wgAllowCopyUploads; $archive = wfImageArchiveDir( $saveName, 'temp' ); if ( !is_dir ( $archive ) ) wfMkdirParents( $archive ); $stash = $archive . '/' . gmdate( "YmdHis" ) . '!' . $saveName; - $success = $this->mRemoveTempFile + $remove_file = $this->mRemoveTempFile ; + if ( !$remove_file AND $wgAllowCopyUploads AND $this->mSourceType == 'web' ) $remove_file = true; + + $success = $remove_file ? rename( $tempName, $stash ) : move_uploaded_file( $tempName, $stash ); if ( !$success ) { @@ -661,8 +701,8 @@ class UploadForm { $watchChecked = $wgUser->getOption( 'watchdefault' ) ? 'checked="checked"' : ''; - - if ( $wgAllowCopyUploads AND $wgRequest->getText('source') == 'web' ) { + + if ( $wgAllowCopyUploads AND $wgRequest->getText('source') == 'web' AND $wgUser->isAllowed( 'upload_by_url' ) ) { $sourcetype = 'text'; $source_comment = '' . wfMsgHtml( 'upload_source_url' ); } else { @@ -1152,4 +1192,20 @@ class UploadForm { } } + +/** + * Callback function for CURL-based web transfer + * Apparently needs to be global + * @access private + */ +function wfUploadCurlCallback ($ch, $data) { + global $wgUploadTempFile, $wgMaxUploadSize, $wgUploadTempFileSize; + $length = strlen($data); + $wgUploadTempFileSize += $length; + if( $wgUploadTempFileSize > $wgMaxUploadSize ) return 0; + fwrite( $wgUploadTempFile , $data ); + return $length; +} + + ?> -- 2.20.1