MediaWiki  master
ForeignAPIFile.php
Go to the documentation of this file.
1 <?php
25 
31 class ForeignAPIFile extends File {
33  private $mExists;
35  private $mInfo;
36 
37  protected $repoClass = ForeignAPIRepo::class;
38 
45  public function __construct( $title, $repo, $info, $exists = false ) {
46  parent::__construct( $title, $repo );
47 
48  $this->mInfo = $info;
49  $this->mExists = $exists;
50 
51  $this->assertRepoDefined();
52  }
53 
59  public static function newFromTitle( Title $title, $repo ) {
60  $data = $repo->fetchImageQuery( [
61  'titles' => 'File:' . $title->getDBkey(),
62  'iiprop' => self::getProps(),
63  'prop' => 'imageinfo',
64  'iimetadataversion' => MediaHandler::getMetadataVersion(),
65  // extmetadata is language-dependent, accessing the current language here
66  // would be problematic, so we just get them all
67  'iiextmetadatamultilang' => 1,
68  ] );
69 
70  $info = $repo->getImageInfo( $data );
71 
72  if ( $info ) {
73  $lastRedirect = count( $data['query']['redirects'] ?? [] ) - 1;
74  if ( $lastRedirect >= 0 ) {
75  // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
76  $newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to'] );
77  $img = new self( $newtitle, $repo, $info, true );
78  $img->redirectedFrom( $title->getDBkey() );
79  } else {
80  $img = new self( $title, $repo, $info, true );
81  }
82 
83  return $img;
84  } else {
85  return null;
86  }
87  }
88 
93  public static function getProps() {
94  return 'timestamp|user|comment|url|size|sha1|metadata|mime|mediatype|extmetadata';
95  }
96 
100  public function getRepo() {
101  return $this->repo;
102  }
103 
104  // Dummy functions...
105 
109  public function exists() {
110  return $this->mExists;
111  }
112 
116  public function getPath() {
117  return false;
118  }
119 
125  public function transform( $params, $flags = 0 ) {
126  if ( !$this->canRender() ) {
127  // show icon
128  return parent::transform( $params, $flags );
129  }
130 
131  // Note, the this->canRender() check above implies
132  // that we have a handler, and it can do makeParamString.
133  $otherParams = $this->handler->makeParamString( $params );
134  $width = $params['width'] ?? -1;
135  $height = $params['height'] ?? -1;
136  $thumbUrl = false;
137 
138  if ( $width > 0 || $height > 0 ) {
139  // Only query the remote if there are dimensions
140  $thumbUrl = $this->repo->getThumbUrlFromCache(
141  $this->getName(),
142  $width,
143  $height,
144  $otherParams
145  );
146  } elseif ( $this->getMediaType() === MEDIATYPE_AUDIO ) {
147  // This has no dimensions, but we still need to pass a value to getTransform()
148  $thumbUrl = '/';
149  }
150  if ( $thumbUrl === false ) {
151  global $wgLang;
152 
153  return $this->repo->getThumbError(
154  $this->getName(),
155  $width,
156  $height,
157  $otherParams,
158  $wgLang->getCode()
159  );
160  }
161 
162  return $this->handler->getTransform( $this, 'bogus', $thumbUrl, $params );
163  }
164 
165  // Info we can get from API...
166 
171  public function getWidth( $page = 1 ) {
172  return (int)( $this->mInfo['width'] ?? 0 );
173  }
174 
179  public function getHeight( $page = 1 ) {
180  return (int)( $this->mInfo['height'] ?? 0 );
181  }
182 
186  public function getMetadata() {
187  if ( isset( $this->mInfo['metadata'] ) ) {
188  return serialize( self::parseMetadata( $this->mInfo['metadata'] ) );
189  }
190 
191  return false;
192  }
193 
197  public function getMetadataArray(): array {
198  if ( isset( $this->mInfo['metadata'] ) ) {
199  return self::parseMetadata( $this->mInfo['metadata'] );
200  }
201 
202  return [];
203  }
204 
209  public function getExtendedMetadata() {
210  return $this->mInfo['extmetadata'] ?? null;
211  }
212 
217  public static function parseMetadata( $metadata ) {
218  if ( !is_array( $metadata ) ) {
219  return [ '_error' => $metadata ];
220  }
221  '@phan-var array[] $metadata';
222  $ret = [];
223  foreach ( $metadata as $meta ) {
224  $ret[$meta['name']] = self::parseMetadataValue( $meta['value'] );
225  }
226 
227  return $ret;
228  }
229 
234  private static function parseMetadataValue( $metadata ) {
235  if ( !is_array( $metadata ) ) {
236  return $metadata;
237  }
238  '@phan-var array[] $metadata';
239  $ret = [];
240  foreach ( $metadata as $meta ) {
241  $ret[$meta['name']] = self::parseMetadataValue( $meta['value'] );
242  }
243 
244  return $ret;
245  }
246 
250  public function getSize() {
251  return isset( $this->mInfo['size'] ) ? intval( $this->mInfo['size'] ) : null;
252  }
253 
257  public function getUrl() {
258  return isset( $this->mInfo['url'] ) ? strval( $this->mInfo['url'] ) : null;
259  }
260 
268  public function getDescriptionShortUrl() {
269  if ( isset( $this->mInfo['descriptionshorturl'] ) ) {
270  return $this->mInfo['descriptionshorturl'];
271  } elseif ( isset( $this->mInfo['pageid'] ) ) {
272  $url = $this->repo->makeUrl( [ 'curid' => $this->mInfo['pageid'] ] );
273  if ( $url !== false ) {
274  return $url;
275  }
276  }
277  return null;
278  }
279 
280  public function getUploader( int $audience = self::FOR_PUBLIC, Authority $performer = null ): ?UserIdentity {
281  if ( isset( $this->mInfo['user'] ) ) {
282  // We don't know if the foreign repo will have a real interwiki prefix,
283  // treat this user as a foreign imported user. Maybe we can do better?
284  return UserIdentityValue::newExternal( $this->getRepoName(), $this->mInfo['user'] );
285  }
286  return null;
287  }
288 
294  public function getDescription( $audience = self::FOR_PUBLIC, Authority $performer = null ) {
295  return isset( $this->mInfo['comment'] ) ? strval( $this->mInfo['comment'] ) : null;
296  }
297 
301  public function getSha1() {
302  return isset( $this->mInfo['sha1'] )
303  ? Wikimedia\base_convert( strval( $this->mInfo['sha1'] ), 16, 36, 31 )
304  : null;
305  }
306 
310  public function getTimestamp() {
311  return wfTimestamp( TS_MW,
312  isset( $this->mInfo['timestamp'] )
313  ? strval( $this->mInfo['timestamp'] )
314  : null
315  );
316  }
317 
321  public function getMimeType() {
322  if ( !isset( $this->mInfo['mime'] ) ) {
323  $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
324  $this->mInfo['mime'] = $magic->getMimeTypeFromExtensionOrNull( $this->getExtension() );
325  }
326 
327  return $this->mInfo['mime'];
328  }
329 
333  public function getMediaType() {
334  if ( isset( $this->mInfo['mediatype'] ) ) {
335  return $this->mInfo['mediatype'];
336  }
337  $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
338 
339  return $magic->getMediaType( null, $this->getMimeType() );
340  }
341 
345  public function getDescriptionUrl() {
346  return $this->mInfo['descriptionurl'] ?? false;
347  }
348 
354  public function getThumbPath( $suffix = '' ) {
355  if ( !$this->repo->canCacheThumbs() ) {
356  return null;
357  }
358 
359  $path = $this->repo->getZonePath( 'thumb' ) . '/' . $this->getHashPath();
360  if ( $suffix ) {
361  $path .= $suffix . '/';
362  }
363  return $path;
364  }
365 
369  protected function getThumbnails() {
370  $dir = $this->getThumbPath( $this->getName() );
371  $iter = $this->repo->getBackend()->getFileList( [ 'dir' => $dir ] );
372 
373  $files = [];
374  if ( $iter ) {
375  foreach ( $iter as $file ) {
376  $files[] = $file;
377  }
378  }
379 
380  return $files;
381  }
382 
383  public function purgeCache( $options = [] ) {
384  $this->purgeThumbnails( $options );
385  $this->purgeDescriptionPage();
386  }
387 
388  private function purgeDescriptionPage() {
389  $services = MediaWikiServices::getInstance();
390  $langCode = $services->getContentLanguage()->getCode();
391 
392  // Key must match File::getDescriptionText
393  $key = $this->repo->getLocalCacheKey( 'file-remote-description', $langCode, md5( $this->getName() ) );
394  $services->getMainWANObjectCache()->delete( $key );
395  }
396 
400  public function purgeThumbnails( $options = [] ) {
401  $key = $this->repo->getLocalCacheKey( 'file-thumb-url', sha1( $this->getName() ) );
402  MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
403 
404  $files = $this->getThumbnails();
405  // Give media handler a chance to filter the purge list
406  $handler = $this->getHandler();
407  if ( $handler ) {
408  $handler->filterThumbnailPurgeList( $files, $options );
409  }
410 
411  $dir = $this->getThumbPath( $this->getName() );
412  $purgeList = [];
413  foreach ( $files as $file ) {
414  $purgeList[] = "{$dir}{$file}";
415  }
416 
417  # Delete the thumbnails
418  $this->repo->quickPurgeBatch( $purgeList );
419  # Clear out the thumbnail directory if empty
420  $this->repo->quickCleanDir( $dir );
421  }
422 
428  public function isTransformedLocally() {
429  return false;
430  }
431 }
serialize()
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgLang
Definition: Setup.php:497
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:82
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:68
assertRepoDefined()
Assert that $this->repo is set to a valid FileRepo instance.
Definition: File.php:2462
getName()
Return the name of this file.
Definition: File.php:332
canRender()
Checks if the output of transform() for this file is likely to be valid.
Definition: File.php:866
FileRepo LocalRepo ForeignAPIRepo bool $repo
Some member variables can be lazy-initialised using __get().
Definition: File.php:115
Title string bool $title
Definition: File.php:118
Foreign file accessible through api.php requests.
getThumbPath( $suffix='')
Only useful if we're locally caching thumbs anyway...
getDescription( $audience=self::FOR_PUBLIC, Authority $performer=null)
__construct( $title, $repo, $info, $exists=false)
getUploader(int $audience=self::FOR_PUBLIC, Authority $performer=null)
Get the identity of the file uploader.
purgeCache( $options=[])
Purge shared caches such as thumbnails and DB data caching STUB Overridden by LocalFile.
isTransformedLocally()
The thumbnail is created on the foreign server and fetched over internet.
static parseMetadata( $metadata)
getHeight( $page=1)
static newFromTitle(Title $title, $repo)
getWidth( $page=1)
purgeThumbnails( $options=[])
transform( $params, $flags=0)
getDescriptionShortUrl()
Get short description URL for a file based on the foreign API response, or if unavailable,...
static getProps()
Get the property string for iiprop and aiprop.
static getMetadataVersion()
Get metadata version.
Service locator for MediaWiki core services.
Value object representing a user's identity.
Represents a title within MediaWiki.
Definition: Title.php:49
getDBkey()
Get the main part with underscores.
Definition: Title.php:1057
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:370
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
Interface for objects representing user identity.
const MEDIATYPE_AUDIO
Definition: defines.php:32
return true
Definition: router.php:90
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42