MediaWiki  REL1_20
UploadFromUrl.php
Go to the documentation of this file.
00001 <?php
00031 class UploadFromUrl extends UploadBase {
00032         protected $mAsync, $mUrl;
00033         protected $mIgnoreWarnings = true;
00034 
00035         protected $mTempPath, $mTmpHandle;
00036 
00046         public static function isAllowed( $user ) {
00047                 if ( !$user->isAllowed( 'upload_by_url' ) ) {
00048                         return 'upload_by_url';
00049                 }
00050                 return parent::isAllowed( $user );
00051         }
00052 
00057         public static function isEnabled() {
00058                 global $wgAllowCopyUploads;
00059                 return $wgAllowCopyUploads && parent::isEnabled();
00060         }
00061 
00068         public static function isAllowedHost( $url ) {
00069                 global $wgCopyUploadsDomains;
00070                 if ( !count( $wgCopyUploadsDomains ) ) {
00071                         return true;
00072                 }
00073                 $parsedUrl = wfParseUrl( $url );
00074                 if ( !$parsedUrl ) {
00075                         return false;
00076                 }
00077                 $valid = false;
00078                 foreach( $wgCopyUploadsDomains as $domain ) {
00079                         if ( $parsedUrl['host'] === $domain ) {
00080                                 $valid = true;
00081                                 break;
00082                         }
00083                 }
00084                 return $valid;
00085         }
00086 
00097         public function initialize( $name, $url, $async = false ) {
00098                 global $wgAllowAsyncCopyUploads;
00099 
00100                 $this->mUrl = $url;
00101                 $this->mAsync = $wgAllowAsyncCopyUploads ? $async : false;
00102                 if ( $async ) {
00103                         throw new MWException( 'Asynchronous copy uploads are no longer possible as of r81612.' );
00104                 }
00105 
00106                 $tempPath = $this->mAsync ? null : $this->makeTemporaryFile();
00107                 # File size and removeTempFile will be filled in later
00108                 $this->initializePathInfo( $name, $tempPath, 0, false );
00109         }
00110 
00115         public function initializeFromRequest( &$request ) {
00116                 $desiredDestName = $request->getText( 'wpDestFile' );
00117                 if ( !$desiredDestName ) {
00118                         $desiredDestName = $request->getText( 'wpUploadFileURL' );
00119                 }
00120                 $this->initialize(
00121                         $desiredDestName,
00122                         trim( $request->getVal( 'wpUploadFileURL' ) ),
00123                         false
00124                 );
00125         }
00126 
00131         public static function isValidRequest( $request ) {
00132                 global $wgUser;
00133 
00134                 $url = $request->getVal( 'wpUploadFileURL' );
00135                 return !empty( $url )
00136                         && Http::isValidURI( $url )
00137                         && $wgUser->isAllowed( 'upload_by_url' );
00138         }
00139 
00143         public function getSourceType() { return 'url'; }
00144 
00148         public function fetchFile() {
00149                 if ( !Http::isValidURI( $this->mUrl ) ) {
00150                         return Status::newFatal( 'http-invalid-url' );
00151                 }
00152 
00153                 if( !self::isAllowedHost( $this->mUrl ) ) {
00154                         return Status::newFatal( 'upload-copy-upload-invalid-domain' );
00155                 }
00156                 if ( !$this->mAsync ) {
00157                         return $this->reallyFetchFile();
00158                 }
00159                 return Status::newGood();
00160         }
00166         protected function makeTemporaryFile() {
00167                 return tempnam( wfTempDir(), 'URL' );
00168         }
00169 
00177         public function saveTempFileChunk( $req, $buffer ) {
00178                 $nbytes = fwrite( $this->mTmpHandle, $buffer );
00179 
00180                 if ( $nbytes == strlen( $buffer ) ) {
00181                         $this->mFileSize += $nbytes;
00182                 } else {
00183                         // Well... that's not good!
00184                         fclose( $this->mTmpHandle );
00185                         $this->mTmpHandle = false;
00186                 }
00187 
00188                 return $nbytes;
00189         }
00190 
00196         protected function reallyFetchFile() {
00197                 if ( $this->mTempPath === false ) {
00198                         return Status::newFatal( 'tmp-create-error' );
00199                 }
00200 
00201                 // Note the temporary file should already be created by makeTemporaryFile()
00202                 $this->mTmpHandle = fopen( $this->mTempPath, 'wb' );
00203                 if ( !$this->mTmpHandle ) {
00204                         return Status::newFatal( 'tmp-create-error' );
00205                 }
00206 
00207                 $this->mRemoveTempFile = true;
00208                 $this->mFileSize = 0;
00209 
00210                 $options = array(
00211                         'followRedirects' => true
00212                 );
00213                 global $wgCopyUploadProxy;
00214                 if ( $wgCopyUploadProxy !== false ) {
00215                         $options['proxy'] = $wgCopyUploadProxy;
00216                 }
00217                 $req = MWHttpRequest::factory( $this->mUrl, $options );
00218                 $req->setCallback( array( $this, 'saveTempFileChunk' ) );
00219                 $status = $req->execute();
00220 
00221                 if ( $this->mTmpHandle ) {
00222                         // File got written ok...
00223                         fclose( $this->mTmpHandle );
00224                         $this->mTmpHandle = null;
00225                 } else {
00226                         // We encountered a write error during the download...
00227                         return Status::newFatal( 'tmp-write-error' );
00228                 }
00229 
00230                 if ( !$status->isOk() ) {
00231                         return $status;
00232                 }
00233 
00234                 return $status;
00235         }
00236 
00242         public function verifyUpload() {
00243                 if ( $this->mAsync ) {
00244                         return array( 'status' => UploadBase::OK );
00245                 }
00246                 return parent::verifyUpload();
00247         }
00248 
00254         public function checkWarnings() {
00255                 if ( $this->mAsync ) {
00256                         $this->mIgnoreWarnings = false;
00257                         return array();
00258                 }
00259                 return parent::checkWarnings();
00260         }
00261 
00268         public function verifyTitlePermissions( $user ) {
00269                 if ( $this->mAsync ) {
00270                         return true;
00271                 }
00272                 return parent::verifyTitlePermissions( $user );
00273         }
00274 
00284         public function performUpload( $comment, $pageText, $watch, $user ) {
00285                 if ( $this->mAsync ) {
00286                         $sessionKey = $this->insertJob( $comment, $pageText, $watch, $user );
00287 
00288                         return Status::newFatal( 'async', $sessionKey );
00289                 }
00290 
00291                 return parent::performUpload( $comment, $pageText, $watch, $user );
00292         }
00293 
00301         protected function insertJob( $comment, $pageText, $watch, $user ) {
00302                 $sessionKey = $this->stashSession();
00303                 $job = new UploadFromUrlJob( $this->getTitle(), array(
00304                         'url' => $this->mUrl,
00305                         'comment' => $comment,
00306                         'pageText' => $pageText,
00307                         'watch' => $watch,
00308                         'userName' => $user->getName(),
00309                         'leaveMessage' => $this->mAsync == 'async-leavemessage',
00310                         'ignoreWarnings' => $this->mIgnoreWarnings,
00311                         'sessionId' => session_id(),
00312                         'sessionKey' => $sessionKey,
00313                 ) );
00314                 $job->initializeSessionData();
00315                 $job->insert();
00316                 return $sessionKey;
00317         }
00318 
00319 }