MediaWiki
REL1_20
|
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 }