MediaWiki  REL1_21
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 
00070         public static function isAllowedHost( $url ) {
00071                 global $wgCopyUploadsDomains;
00072                 if ( !count( $wgCopyUploadsDomains ) ) {
00073                         return true;
00074                 }
00075                 $parsedUrl = wfParseUrl( $url );
00076                 if ( !$parsedUrl ) {
00077                         return false;
00078                 }
00079                 $valid = false;
00080                 foreach( $wgCopyUploadsDomains as $domain ) {
00081                         // See if the domain for the upload matches this whitelisted domain
00082                         $whitelistedDomainPieces = explode( '.', $domain );
00083                         $uploadDomainPieces = explode( '.', $parsedUrl['host'] );
00084                         if ( count( $whitelistedDomainPieces ) === count( $uploadDomainPieces ) ) {
00085                                 $valid = true;
00086                                 // See if all the pieces match or not (excluding wildcards)
00087                                 foreach ( $whitelistedDomainPieces as $index => $piece ) {
00088                                         if ( $piece !== '*' && $piece !== $uploadDomainPieces[$index] ) {
00089                                                 $valid = false;
00090                                         }
00091                                 }
00092                                 if ( $valid ) {
00093                                         // We found a match, so quit comparing against the list
00094                                         break;
00095                                 }
00096                         }
00097                         /* Non-wildcard test
00098                         if ( $parsedUrl['host'] === $domain ) {
00099                                 $valid = true;
00100                                 break;
00101                         }
00102                         */
00103                 }
00104                 return $valid;
00105         }
00106 
00117         public function initialize( $name, $url, $async = false ) {
00118                 global $wgAllowAsyncCopyUploads;
00119 
00120                 $this->mUrl = $url;
00121                 $this->mAsync = $wgAllowAsyncCopyUploads ? $async : false;
00122                 if ( $async ) {
00123                         throw new MWException( 'Asynchronous copy uploads are no longer possible as of r81612.' );
00124                 }
00125 
00126                 $tempPath = $this->mAsync ? null : $this->makeTemporaryFile();
00127                 # File size and removeTempFile will be filled in later
00128                 $this->initializePathInfo( $name, $tempPath, 0, false );
00129         }
00130 
00135         public function initializeFromRequest( &$request ) {
00136                 $desiredDestName = $request->getText( 'wpDestFile' );
00137                 if ( !$desiredDestName ) {
00138                         $desiredDestName = $request->getText( 'wpUploadFileURL' );
00139                 }
00140                 $this->initialize(
00141                         $desiredDestName,
00142                         trim( $request->getVal( 'wpUploadFileURL' ) ),
00143                         false
00144                 );
00145         }
00146 
00151         public static function isValidRequest( $request ) {
00152                 global $wgUser;
00153 
00154                 $url = $request->getVal( 'wpUploadFileURL' );
00155                 return !empty( $url )
00156                         && Http::isValidURI( $url )
00157                         && $wgUser->isAllowed( 'upload_by_url' );
00158         }
00159 
00163         public function getSourceType() { return 'url'; }
00164 
00168         public function fetchFile() {
00169                 if ( !Http::isValidURI( $this->mUrl ) ) {
00170                         return Status::newFatal( 'http-invalid-url' );
00171                 }
00172 
00173                 if( !self::isAllowedHost( $this->mUrl ) ) {
00174                         return Status::newFatal( 'upload-copy-upload-invalid-domain' );
00175                 }
00176                 if ( !$this->mAsync ) {
00177                         return $this->reallyFetchFile();
00178                 }
00179                 return Status::newGood();
00180         }
00186         protected function makeTemporaryFile() {
00187                 return tempnam( wfTempDir(), 'URL' );
00188         }
00189 
00197         public function saveTempFileChunk( $req, $buffer ) {
00198                 $nbytes = fwrite( $this->mTmpHandle, $buffer );
00199 
00200                 if ( $nbytes == strlen( $buffer ) ) {
00201                         $this->mFileSize += $nbytes;
00202                 } else {
00203                         // Well... that's not good!
00204                         fclose( $this->mTmpHandle );
00205                         $this->mTmpHandle = false;
00206                 }
00207 
00208                 return $nbytes;
00209         }
00210 
00216         protected function reallyFetchFile() {
00217                 if ( $this->mTempPath === false ) {
00218                         return Status::newFatal( 'tmp-create-error' );
00219                 }
00220 
00221                 // Note the temporary file should already be created by makeTemporaryFile()
00222                 $this->mTmpHandle = fopen( $this->mTempPath, 'wb' );
00223                 if ( !$this->mTmpHandle ) {
00224                         return Status::newFatal( 'tmp-create-error' );
00225                 }
00226 
00227                 $this->mRemoveTempFile = true;
00228                 $this->mFileSize = 0;
00229 
00230                 $options = array(
00231                         'followRedirects' => true
00232                 );
00233                 global $wgCopyUploadProxy;
00234                 if ( $wgCopyUploadProxy !== false ) {
00235                         $options['proxy'] = $wgCopyUploadProxy;
00236                 }
00237                 $req = MWHttpRequest::factory( $this->mUrl, $options );
00238                 $req->setCallback( array( $this, 'saveTempFileChunk' ) );
00239                 $status = $req->execute();
00240 
00241                 if ( $this->mTmpHandle ) {
00242                         // File got written ok...
00243                         fclose( $this->mTmpHandle );
00244                         $this->mTmpHandle = null;
00245                 } else {
00246                         // We encountered a write error during the download...
00247                         return Status::newFatal( 'tmp-write-error' );
00248                 }
00249 
00250                 if ( !$status->isOk() ) {
00251                         return $status;
00252                 }
00253 
00254                 return $status;
00255         }
00256 
00262         public function verifyUpload() {
00263                 if ( $this->mAsync ) {
00264                         return array( 'status' => UploadBase::OK );
00265                 }
00266                 return parent::verifyUpload();
00267         }
00268 
00274         public function checkWarnings() {
00275                 if ( $this->mAsync ) {
00276                         $this->mIgnoreWarnings = false;
00277                         return array();
00278                 }
00279                 return parent::checkWarnings();
00280         }
00281 
00288         public function verifyTitlePermissions( $user ) {
00289                 if ( $this->mAsync ) {
00290                         return true;
00291                 }
00292                 return parent::verifyTitlePermissions( $user );
00293         }
00294 
00304         public function performUpload( $comment, $pageText, $watch, $user ) {
00305                 if ( $this->mAsync ) {
00306                         $sessionKey = $this->insertJob( $comment, $pageText, $watch, $user );
00307 
00308                         return Status::newFatal( 'async', $sessionKey );
00309                 }
00310 
00311                 return parent::performUpload( $comment, $pageText, $watch, $user );
00312         }
00313 
00321         protected function insertJob( $comment, $pageText, $watch, $user ) {
00322                 $sessionKey = $this->stashSession();
00323                 $job = new UploadFromUrlJob( $this->getTitle(), array(
00324                         'url' => $this->mUrl,
00325                         'comment' => $comment,
00326                         'pageText' => $pageText,
00327                         'watch' => $watch,
00328                         'userName' => $user->getName(),
00329                         'leaveMessage' => $this->mAsync == 'async-leavemessage',
00330                         'ignoreWarnings' => $this->mIgnoreWarnings,
00331                         'sessionId' => session_id(),
00332                         'sessionKey' => $sessionKey,
00333                 ) );
00334                 $job->initializeSessionData();
00335                 JobQueueGroup::singleton()->push( $job );
00336                 return $sessionKey;
00337         }
00338 
00339 }