summaryrefslogtreecommitdiff
path: root/includes/upload/UploadFromUrl.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/upload/UploadFromUrl.php')
-rw-r--r--includes/upload/UploadFromUrl.php137
1 files changed, 137 insertions, 0 deletions
diff --git a/includes/upload/UploadFromUrl.php b/includes/upload/UploadFromUrl.php
new file mode 100644
index 00000000..763dae38
--- /dev/null
+++ b/includes/upload/UploadFromUrl.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * @file
+ * @ingroup upload
+ *
+ * Implements uploading from a HTTP resource.
+ *
+ * @author Bryan Tong Minh
+ * @author Michael Dale
+ */
+class UploadFromUrl extends UploadBase {
+ protected $mTempDownloadPath;
+
+ /**
+ * Checks if the user is allowed to use the upload-by-URL feature. If the
+ * user is allowed, pass on permissions checking to the parent.
+ */
+ public static function isAllowed( $user ) {
+ if( !$user->isAllowed( 'upload_by_url' ) )
+ return 'upload_by_url';
+ return parent::isAllowed( $user );
+ }
+
+ /**
+ * Checks if the upload from URL feature is enabled
+ */
+ public static function isEnabled() {
+ global $wgAllowCopyUploads;
+ return $wgAllowCopyUploads && parent::isEnabled();
+ }
+
+ /**
+ * Entry point for API upload
+ */
+ public function initialize( $name, $url, $na, $nb = false ) {
+ global $wgTmpDirectory;
+
+ $localFile = tempnam( $wgTmpDirectory, 'WEBUPLOAD' );
+ $this->initializePathInfo( $name, $localFile, 0, true );
+
+ $this->mUrl = trim( $url );
+ }
+
+ /**
+ * Entry point for SpecialUpload
+ * @param $request Object: WebRequest object
+ */
+ public function initializeFromRequest( &$request ) {
+ $desiredDestName = $request->getText( 'wpDestFile' );
+ if( !$desiredDestName )
+ $desiredDestName = $request->getText( 'wpUploadFileURL' );
+ return $this->initialize(
+ $desiredDestName,
+ $request->getVal( 'wpUploadFileURL' ),
+ false
+ );
+ }
+
+ /**
+ * @param $request Object: WebRequest object
+ */
+ public static function isValidRequest( $request ){
+ if( !$request->getVal( 'wpUploadFileURL' ) )
+ return false;
+ // check that is a valid url:
+ return self::isValidUrl( $request->getVal( 'wpUploadFileURL' ) );
+ }
+
+ public static function isValidUrl( $url ) {
+ // Only allow HTTP or FTP for now
+ return (bool)preg_match( '!^(http://|ftp://)!', $url );
+ }
+
+ /**
+ * Do the real fetching stuff
+ */
+ function fetchFile() {
+ if( !self::isValidUrl( $this->mUrl ) ) {
+ return Status::newFatal( 'upload-proto-error' );
+ }
+ $res = $this->curlCopy();
+ if( $res !== true ) {
+ return Status::newFatal( $res );
+ }
+ return Status::newGood();
+ }
+
+ /**
+ * Safe copy from URL
+ * Returns true if there was an error, false otherwise
+ */
+ private function curlCopy() {
+ global $wgOut;
+
+ # Open temporary file
+ $this->mCurlDestHandle = @fopen( $this->mTempPath, "wb" );
+ if( $this->mCurlDestHandle === false ) {
+ # Could not open temporary file to write in
+ return 'upload-file-error';
+ }
+
+ $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, $this->mUrl);
+ curl_setopt( $ch, CURLOPT_WRITEFUNCTION, array( $this, 'uploadCurlCallback' ) );
+ curl_exec( $ch );
+ $error = curl_errno( $ch );
+ curl_close( $ch );
+
+ fclose( $this->mCurlDestHandle );
+ unset( $this->mCurlDestHandle );
+
+ if( $error )
+ return "upload-curl-error$errornum";
+
+ return true;
+ }
+
+ /**
+ * Callback function for CURL-based web transfer
+ * Write data to file unless we've passed the length limit;
+ * if so, abort immediately.
+ * @access private
+ */
+ function uploadCurlCallback( $ch, $data ) {
+ global $wgMaxUploadSize;
+ $length = strlen( $data );
+ $this->mFileSize += $length;
+ if( $this->mFileSize > $wgMaxUploadSize ) {
+ return 0;
+ }
+ fwrite( $this->mCurlDestHandle, $data );
+ return $length;
+ }
+}