]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/filerepo/file/ForeignAPIFile.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / includes / filerepo / file / ForeignAPIFile.php
1 <?php
2 /**
3  * Foreign file accessible through api.php requests.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup FileAbstraction
22  */
23
24 /**
25  * Foreign file accessible through api.php requests.
26  * Very hacky and inefficient, do not use :D
27  *
28  * @ingroup FileAbstraction
29  */
30 class ForeignAPIFile extends File {
31         /** @var bool */
32         private $mExists;
33         /** @var array */
34         private $mInfo = [];
35
36         protected $repoClass = 'ForeignApiRepo';
37
38         /**
39          * @param Title|string|bool $title
40          * @param ForeignApiRepo $repo
41          * @param array $info
42          * @param bool $exists
43          */
44         function __construct( $title, $repo, $info, $exists = false ) {
45                 parent::__construct( $title, $repo );
46
47                 $this->mInfo = $info;
48                 $this->mExists = $exists;
49
50                 $this->assertRepoDefined();
51         }
52
53         /**
54          * @param Title $title
55          * @param ForeignApiRepo $repo
56          * @return ForeignAPIFile|null
57          */
58         static function newFromTitle( Title $title, $repo ) {
59                 $data = $repo->fetchImageQuery( [
60                         'titles' => 'File:' . $title->getDBkey(),
61                         'iiprop' => self::getProps(),
62                         'prop' => 'imageinfo',
63                         'iimetadataversion' => MediaHandler::getMetadataVersion(),
64                         // extmetadata is language-dependant, accessing the current language here
65                         // would be problematic, so we just get them all
66                         'iiextmetadatamultilang' => 1,
67                 ] );
68
69                 $info = $repo->getImageInfo( $data );
70
71                 if ( $info ) {
72                         $lastRedirect = isset( $data['query']['redirects'] )
73                                 ? count( $data['query']['redirects'] ) - 1
74                                 : -1;
75                         if ( $lastRedirect >= 0 ) {
76                                 $newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to'] );
77                                 $img = new self( $newtitle, $repo, $info, true );
78                                 if ( $img ) {
79                                         $img->redirectedFrom( $title->getDBkey() );
80                                 }
81                         } else {
82                                 $img = new self( $title, $repo, $info, true );
83                         }
84
85                         return $img;
86                 } else {
87                         return null;
88                 }
89         }
90
91         /**
92          * Get the property string for iiprop and aiprop
93          * @return string
94          */
95         static function getProps() {
96                 return 'timestamp|user|comment|url|size|sha1|metadata|mime|mediatype|extmetadata';
97         }
98
99         // Dummy functions...
100
101         /**
102          * @return bool
103          */
104         public function exists() {
105                 return $this->mExists;
106         }
107
108         /**
109          * @return bool
110          */
111         public function getPath() {
112                 return false;
113         }
114
115         /**
116          * @param array $params
117          * @param int $flags
118          * @return bool|MediaTransformOutput
119          */
120         function transform( $params, $flags = 0 ) {
121                 if ( !$this->canRender() ) {
122                         // show icon
123                         return parent::transform( $params, $flags );
124                 }
125
126                 // Note, the this->canRender() check above implies
127                 // that we have a handler, and it can do makeParamString.
128                 $otherParams = $this->handler->makeParamString( $params );
129                 $width = isset( $params['width'] ) ? $params['width'] : -1;
130                 $height = isset( $params['height'] ) ? $params['height'] : -1;
131
132                 $thumbUrl = $this->repo->getThumbUrlFromCache(
133                         $this->getName(),
134                         $width,
135                         $height,
136                         $otherParams
137                 );
138                 if ( $thumbUrl === false ) {
139                         global $wgLang;
140
141                         return $this->repo->getThumbError(
142                                 $this->getName(),
143                                 $width,
144                                 $height,
145                                 $otherParams,
146                                 $wgLang->getCode()
147                         );
148                 }
149
150                 return $this->handler->getTransform( $this, 'bogus', $thumbUrl, $params );
151         }
152
153         // Info we can get from API...
154
155         /**
156          * @param int $page
157          * @return int|number
158          */
159         public function getWidth( $page = 1 ) {
160                 return isset( $this->mInfo['width'] ) ? intval( $this->mInfo['width'] ) : 0;
161         }
162
163         /**
164          * @param int $page
165          * @return int
166          */
167         public function getHeight( $page = 1 ) {
168                 return isset( $this->mInfo['height'] ) ? intval( $this->mInfo['height'] ) : 0;
169         }
170
171         /**
172          * @return bool|null|string
173          */
174         public function getMetadata() {
175                 if ( isset( $this->mInfo['metadata'] ) ) {
176                         return serialize( self::parseMetadata( $this->mInfo['metadata'] ) );
177                 }
178
179                 return null;
180         }
181
182         /**
183          * @return array|null Extended metadata (see imageinfo API for format) or
184          *   null on error
185          */
186         public function getExtendedMetadata() {
187                 if ( isset( $this->mInfo['extmetadata'] ) ) {
188                         return $this->mInfo['extmetadata'];
189                 }
190
191                 return null;
192         }
193
194         /**
195          * @param array $metadata
196          * @return array
197          */
198         public static function parseMetadata( $metadata ) {
199                 if ( !is_array( $metadata ) ) {
200                         return $metadata;
201                 }
202                 $ret = [];
203                 foreach ( $metadata as $meta ) {
204                         $ret[$meta['name']] = self::parseMetadata( $meta['value'] );
205                 }
206
207                 return $ret;
208         }
209
210         /**
211          * @return bool|int|null
212          */
213         public function getSize() {
214                 return isset( $this->mInfo['size'] ) ? intval( $this->mInfo['size'] ) : null;
215         }
216
217         /**
218          * @return null|string
219          */
220         public function getUrl() {
221                 return isset( $this->mInfo['url'] ) ? strval( $this->mInfo['url'] ) : null;
222         }
223
224         /**
225          * Get short description URL for a file based on the foreign API response,
226          * or if unavailable, the short URL is constructed from the foreign page ID.
227          *
228          * @return null|string
229          * @since 1.27
230          */
231         public function getDescriptionShortUrl() {
232                 if ( isset( $this->mInfo['descriptionshorturl'] ) ) {
233                         return $this->mInfo['descriptionshorturl'];
234                 } elseif ( isset( $this->mInfo['pageid'] ) ) {
235                         $url = $this->repo->makeUrl( [ 'curid' => $this->mInfo['pageid'] ] );
236                         if ( $url !== false ) {
237                                 return $url;
238                         }
239                 }
240                 return null;
241         }
242
243         /**
244          * @param string $type
245          * @return int|null|string
246          */
247         public function getUser( $type = 'text' ) {
248                 if ( $type == 'text' ) {
249                         return isset( $this->mInfo['user'] ) ? strval( $this->mInfo['user'] ) : null;
250                 } else {
251                         return 0; // What makes sense here, for a remote user?
252                 }
253         }
254
255         /**
256          * @param int $audience
257          * @param User $user
258          * @return null|string
259          */
260         public function getDescription( $audience = self::FOR_PUBLIC, User $user = null ) {
261                 return isset( $this->mInfo['comment'] ) ? strval( $this->mInfo['comment'] ) : null;
262         }
263
264         /**
265          * @return null|string
266          */
267         function getSha1() {
268                 return isset( $this->mInfo['sha1'] )
269                         ? Wikimedia\base_convert( strval( $this->mInfo['sha1'] ), 16, 36, 31 )
270                         : null;
271         }
272
273         /**
274          * @return bool|string
275          */
276         function getTimestamp() {
277                 return wfTimestamp( TS_MW,
278                         isset( $this->mInfo['timestamp'] )
279                                 ? strval( $this->mInfo['timestamp'] )
280                                 : null
281                 );
282         }
283
284         /**
285          * @return string
286          */
287         function getMimeType() {
288                 if ( !isset( $this->mInfo['mime'] ) ) {
289                         $magic = MimeMagic::singleton();
290                         $this->mInfo['mime'] = $magic->guessTypesForExtension( $this->getExtension() );
291                 }
292
293                 return $this->mInfo['mime'];
294         }
295
296         /**
297          * @return int|string
298          */
299         function getMediaType() {
300                 if ( isset( $this->mInfo['mediatype'] ) ) {
301                         return $this->mInfo['mediatype'];
302                 }
303                 $magic = MimeMagic::singleton();
304
305                 return $magic->getMediaType( null, $this->getMimeType() );
306         }
307
308         /**
309          * @return bool|string
310          */
311         function getDescriptionUrl() {
312                 return isset( $this->mInfo['descriptionurl'] )
313                         ? $this->mInfo['descriptionurl']
314                         : false;
315         }
316
317         /**
318          * Only useful if we're locally caching thumbs anyway...
319          * @param string $suffix
320          * @return null|string
321          */
322         function getThumbPath( $suffix = '' ) {
323                 if ( $this->repo->canCacheThumbs() ) {
324                         $path = $this->repo->getZonePath( 'thumb' ) . '/' . $this->getHashPath( $this->getName() );
325                         if ( $suffix ) {
326                                 $path = $path . $suffix . '/';
327                         }
328
329                         return $path;
330                 } else {
331                         return null;
332                 }
333         }
334
335         /**
336          * @return array
337          */
338         function getThumbnails() {
339                 $dir = $this->getThumbPath( $this->getName() );
340                 $iter = $this->repo->getBackend()->getFileList( [ 'dir' => $dir ] );
341
342                 $files = [];
343                 foreach ( $iter as $file ) {
344                         $files[] = $file;
345                 }
346
347                 return $files;
348         }
349
350         function purgeCache( $options = [] ) {
351                 $this->purgeThumbnails( $options );
352                 $this->purgeDescriptionPage();
353         }
354
355         function purgeDescriptionPage() {
356                 global $wgContLang;
357
358                 $url = $this->repo->getDescriptionRenderUrl( $this->getName(), $wgContLang->getCode() );
359                 $key = $this->repo->getLocalCacheKey( 'RemoteFileDescription', 'url', md5( $url ) );
360
361                 ObjectCache::getMainWANInstance()->delete( $key );
362         }
363
364         /**
365          * @param array $options
366          */
367         function purgeThumbnails( $options = [] ) {
368                 $key = $this->repo->getLocalCacheKey( 'ForeignAPIRepo', 'ThumbUrl', $this->getName() );
369                 ObjectCache::getMainWANInstance()->delete( $key );
370
371                 $files = $this->getThumbnails();
372                 // Give media handler a chance to filter the purge list
373                 $handler = $this->getHandler();
374                 if ( $handler ) {
375                         $handler->filterThumbnailPurgeList( $files, $options );
376                 }
377
378                 $dir = $this->getThumbPath( $this->getName() );
379                 $purgeList = [];
380                 foreach ( $files as $file ) {
381                         $purgeList[] = "{$dir}{$file}";
382                 }
383
384                 # Delete the thumbnails
385                 $this->repo->quickPurgeBatch( $purgeList );
386                 # Clear out the thumbnail directory if empty
387                 $this->repo->quickCleanDir( $dir );
388         }
389
390         /**
391          * The thumbnail is created on the foreign server and fetched over internet
392          * @since 1.25
393          * @return bool
394          */
395         public function isTransformedLocally() {
396                 return false;
397         }
398 }