]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/upload/UploadFromUrl.php
MediaWiki 1.17.0
[autoinstalls/mediawiki.git] / includes / upload / UploadFromUrl.php
1 <?php
2 /**
3  * Implements uploading from a HTTP resource.
4  *
5  * @file
6  * @ingroup upload
7  * @author Bryan Tong Minh
8  * @author Michael Dale
9  */
10
11 class UploadFromUrl extends UploadBase {
12         protected $mAsync, $mUrl;
13         protected $mIgnoreWarnings = true;
14
15         /**
16          * Checks if the user is allowed to use the upload-by-URL feature. If the
17          * user is allowed, pass on permissions checking to the parent.
18          */
19         public static function isAllowed( $user ) {
20                 if ( !$user->isAllowed( 'upload_by_url' ) )
21                         return 'upload_by_url';
22                 return parent::isAllowed( $user );
23         }
24
25         /**
26          * Checks if the upload from URL feature is enabled
27          * @return bool
28          */
29         public static function isEnabled() {
30                 global $wgAllowCopyUploads;
31                 return $wgAllowCopyUploads && parent::isEnabled();
32         }
33
34         /**
35          * Entry point for API upload
36          *
37          * @param $name string
38          * @param $url string
39          * @param $async mixed Whether the download should be performed
40          * asynchronous. False for synchronous, async or async-leavemessage for
41          * asynchronous download.
42          */
43         public function initialize( $name, $url, $async = false ) {
44                 global $wgAllowAsyncCopyUploads;
45
46                 $this->mUrl = $url;
47                 $this->mAsync = $wgAllowAsyncCopyUploads ? $async : false;
48
49                 $tempPath = $this->mAsync ? null : $this->makeTemporaryFile();
50                 # File size and removeTempFile will be filled in later
51                 $this->initializePathInfo( $name, $tempPath, 0, false );
52         }
53
54         /**
55          * Entry point for SpecialUpload
56          * @param $request Object: WebRequest object
57          */
58         public function initializeFromRequest( &$request ) {
59                 $desiredDestName = $request->getText( 'wpDestFile' );
60                 if ( !$desiredDestName )
61                         $desiredDestName = $request->getText( 'wpUploadFileURL' );
62                 return $this->initialize(
63                         $desiredDestName,
64                         $request->getVal( 'wpUploadFileURL' ),
65                         false
66                 );
67         }
68
69         /**
70          * @param $request Object: WebRequest object
71          */
72         public static function isValidRequest( $request ) {
73                 global $wgUser;
74
75                 $url = $request->getVal( 'wpUploadFileURL' );
76                 return !empty( $url )
77                         && Http::isValidURI( $url )
78                         && $wgUser->isAllowed( 'upload_by_url' );
79         }
80
81
82         public function fetchFile() {
83                 if ( !Http::isValidURI( $this->mUrl ) ) {
84                         return Status::newFatal( 'http-invalid-url' );
85                 }
86
87                 if ( !$this->mAsync ) {
88                         return $this->reallyFetchFile();
89                 }
90                 return Status::newGood();
91         }
92         /**
93          * Create a new temporary file in the URL subdirectory of wfTempDir().
94          *
95          * @return string Path to the file
96          */
97         protected function makeTemporaryFile() {
98                 return tempnam( wfTempDir(), 'URL' );
99         }
100
101         /**
102          * Callback: save a chunk of the result of a HTTP request to the temporary file
103          *
104          * @param $req mixed
105          * @param $buffer string
106          * @return int number of bytes handled
107          */
108         public function saveTempFileChunk( $req, $buffer ) {
109                 $nbytes = fwrite( $this->mTmpHandle, $buffer );
110
111                 if ( $nbytes == strlen( $buffer ) ) {
112                         $this->mFileSize += $nbytes;
113                 } else {
114                         // Well... that's not good!
115                         fclose( $this->mTmpHandle );
116                         $this->mTmpHandle = false;
117                 }
118
119                 return $nbytes;
120         }
121
122         /**
123          * Download the file, save it to the temporary file and update the file
124          * size and set $mRemoveTempFile to true.
125          */
126         protected function reallyFetchFile() {
127                 if ( $this->mTempPath === false ) {
128                         return Status::newFatal( 'tmp-create-error' );
129                 }
130
131                 // Note the temporary file should already be created by makeTemporaryFile()
132                 $this->mTmpHandle = fopen( $this->mTempPath, 'wb' );
133                 if ( !$this->mTmpHandle ) {
134                         return Status::newFatal( 'tmp-create-error' );
135                 }
136
137                 $this->mRemoveTempFile = true;
138                 $this->mFileSize = 0;
139
140                 $req = MWHttpRequest::factory( $this->mUrl );
141                 $req->setCallback( array( $this, 'saveTempFileChunk' ) );
142                 $status = $req->execute();
143
144                 if ( $this->mTmpHandle ) {
145                         // File got written ok...
146                         fclose( $this->mTmpHandle );
147                         $this->mTmpHandle = null;
148                 } else {
149                         // We encountered a write error during the download...
150                         return Status::newFatal( 'tmp-write-error' );
151                 }
152
153                 if ( !$status->isOk() ) {
154                         return $status;
155                 }
156
157                 return $status;
158         }
159
160         /**
161          * Wrapper around the parent function in order to defer verifying the
162          * upload until the file really has been fetched.
163          */
164         public function verifyUpload() {
165                 if ( $this->mAsync ) {
166                         return array( 'status' => UploadBase::OK );
167                 }
168                 return parent::verifyUpload();
169         }
170
171         /**
172          * Wrapper around the parent function in order to defer checking warnings
173          * until the file really has been fetched.
174          */
175         public function checkWarnings() {
176                 if ( $this->mAsync ) {
177                         $this->mIgnoreWarnings = false;
178                         return array();
179                 }
180                 return parent::checkWarnings();
181         }
182
183         /**
184          * Wrapper around the parent function in order to defer checking protection
185          * until we are sure that the file can actually be uploaded
186          */
187         public function verifyPermissions( $user ) {
188                 if ( $this->mAsync ) {
189                         return true;
190                 }
191                 return parent::verifyPermissions( $user );
192         }
193
194         /**
195          * Wrapper around the parent function in order to defer uploading to the
196          * job queue for asynchronous uploads
197          */
198         public function performUpload( $comment, $pageText, $watch, $user ) {
199                 if ( $this->mAsync ) {
200                         $sessionKey = $this->insertJob( $comment, $pageText, $watch, $user );
201
202                         $status = new Status;
203                         $status->error( 'async', $sessionKey );
204                         return $status;
205                 }
206
207                 return parent::performUpload( $comment, $pageText, $watch, $user );
208         }
209
210
211         protected function insertJob( $comment, $pageText, $watch, $user ) {
212                 $sessionKey = $this->stashSession();
213                 $job = new UploadFromUrlJob( $this->getTitle(), array(
214                         'url' => $this->mUrl,
215                         'comment' => $comment,
216                         'pageText' => $pageText,
217                         'watch' => $watch,
218                         'userName' => $user->getName(),
219                         'leaveMessage' => $this->mAsync == 'async-leavemessage',
220                         'ignoreWarnings' => $this->mIgnoreWarnings,
221                         'sessionId' => session_id(),
222                         'sessionKey' => $sessionKey,
223                 ) );
224                 $job->initializeSessionData();
225                 $job->insert();
226                 return $sessionKey;
227         }
228
229
230 }