MediaWiki  master
ForeignAPIFile.php
Go to the documentation of this file.
1 <?php
26 
32 class ForeignAPIFile extends File {
34  private $mExists;
36  private $mInfo;
37 
38  protected $repoClass = ForeignAPIRepo::class;
39 
46  public function __construct( $title, $repo, $info, $exists = false ) {
47  parent::__construct( $title, $repo );
48 
49  $this->mInfo = $info;
50  $this->mExists = $exists;
51 
52  $this->assertRepoDefined();
53  }
54 
60  public static function newFromTitle( Title $title, $repo ) {
61  $data = $repo->fetchImageQuery( [
62  'titles' => 'File:' . $title->getDBkey(),
63  'iiprop' => self::getProps(),
64  'prop' => 'imageinfo',
65  'iimetadataversion' => MediaHandler::getMetadataVersion(),
66  // extmetadata is language-dependent, accessing the current language here
67  // would be problematic, so we just get them all
68  'iiextmetadatamultilang' => 1,
69  ] );
70 
71  $info = $repo->getImageInfo( $data );
72 
73  if ( $info ) {
74  $lastRedirect = count( $data['query']['redirects'] ?? [] ) - 1;
75  if ( $lastRedirect >= 0 ) {
76  // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
77  $newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to'] );
78  $img = new self( $newtitle, $repo, $info, true );
79  $img->redirectedFrom( $title->getDBkey() );
80  } else {
81  $img = new self( $title, $repo, $info, true );
82  }
83 
84  return $img;
85  } else {
86  return null;
87  }
88  }
89 
94  public static function getProps() {
95  return 'timestamp|user|comment|url|size|sha1|metadata|mime|mediatype|extmetadata';
96  }
97 
101  public function getRepo() {
102  return $this->repo;
103  }
104 
105  // Dummy functions...
106 
110  public function exists() {
111  return $this->mExists;
112  }
113 
117  public function getPath() {
118  return false;
119  }
120 
126  public function transform( $params, $flags = 0 ) {
127  if ( !$this->canRender() ) {
128  // show icon
129  return parent::transform( $params, $flags );
130  }
131 
132  // Note, the this->canRender() check above implies
133  // that we have a handler, and it can do makeParamString.
134  $otherParams = $this->handler->makeParamString( $params );
135  $width = $params['width'] ?? -1;
136  $height = $params['height'] ?? -1;
137  $thumbUrl = false;
138 
139  if ( $width > 0 || $height > 0 ) {
140  // Only query the remote if there are dimensions
141  $thumbUrl = $this->repo->getThumbUrlFromCache(
142  $this->getName(),
143  $width,
144  $height,
145  $otherParams
146  );
147  } elseif ( $this->getMediaType() === MEDIATYPE_AUDIO ) {
148  // This has no dimensions, but we still need to pass a value to getTransform()
149  $thumbUrl = '/';
150  }
151  if ( $thumbUrl === false ) {
152  global $wgLang;
153 
154  return $this->repo->getThumbError(
155  $this->getName(),
156  $width,
157  $height,
158  $otherParams,
159  $wgLang->getCode()
160  );
161  }
162 
163  return $this->handler->getTransform( $this, 'bogus', $thumbUrl, $params );
164  }
165 
166  // Info we can get from API...
167 
172  public function getWidth( $page = 1 ) {
173  return (int)( $this->mInfo['width'] ?? 0 );
174  }
175 
180  public function getHeight( $page = 1 ) {
181  return (int)( $this->mInfo['height'] ?? 0 );
182  }
183 
187  public function getMetadata() {
188  if ( isset( $this->mInfo['metadata'] ) ) {
189  return serialize( self::parseMetadata( $this->mInfo['metadata'] ) );
190  }
191 
192  return false;
193  }
194 
198  public function getMetadataArray(): array {
199  if ( isset( $this->mInfo['metadata'] ) ) {
200  return self::parseMetadata( $this->mInfo['metadata'] );
201  }
202 
203  return [];
204  }
205 
210  public function getExtendedMetadata() {
211  return $this->mInfo['extmetadata'] ?? null;
212  }
213 
218  public static function parseMetadata( $metadata ) {
219  if ( !is_array( $metadata ) ) {
220  return [ '_error' => $metadata ];
221  }
222  '@phan-var array[] $metadata';
223  $ret = [];
224  foreach ( $metadata as $meta ) {
225  $ret[$meta['name']] = self::parseMetadataValue( $meta['value'] );
226  }
227 
228  return $ret;
229  }
230 
235  private static function parseMetadataValue( $metadata ) {
236  if ( !is_array( $metadata ) ) {
237  return $metadata;
238  }
239  '@phan-var array[] $metadata';
240  $ret = [];
241  foreach ( $metadata as $meta ) {
242  $ret[$meta['name']] = self::parseMetadataValue( $meta['value'] );
243  }
244 
245  return $ret;
246  }
247 
251  public function getSize() {
252  return isset( $this->mInfo['size'] ) ? intval( $this->mInfo['size'] ) : null;
253  }
254 
258  public function getUrl() {
259  return isset( $this->mInfo['url'] ) ? strval( $this->mInfo['url'] ) : null;
260  }
261 
269  public function getDescriptionShortUrl() {
270  if ( isset( $this->mInfo['descriptionshorturl'] ) ) {
271  return $this->mInfo['descriptionshorturl'];
272  } elseif ( isset( $this->mInfo['pageid'] ) ) {
273  $url = $this->repo->makeUrl( [ 'curid' => $this->mInfo['pageid'] ] );
274  if ( $url !== false ) {
275  return $url;
276  }
277  }
278  return null;
279  }
280 
281  public function getUploader( int $audience = self::FOR_PUBLIC, Authority $performer = null ): ?UserIdentity {
282  if ( isset( $this->mInfo['user'] ) ) {
283  // We don't know if the foreign repo will have a real interwiki prefix,
284  // treat this user as a foreign imported user. Maybe we can do better?
285  return UserIdentityValue::newExternal( $this->getRepoName(), $this->mInfo['user'] );
286  }
287  return null;
288  }
289 
295  public function getDescription( $audience = self::FOR_PUBLIC, Authority $performer = null ) {
296  return isset( $this->mInfo['comment'] ) ? strval( $this->mInfo['comment'] ) : null;
297  }
298 
302  public function getSha1() {
303  return isset( $this->mInfo['sha1'] )
304  ? Wikimedia\base_convert( strval( $this->mInfo['sha1'] ), 16, 36, 31 )
305  : null;
306  }
307 
311  public function getTimestamp() {
312  return wfTimestamp( TS_MW,
313  isset( $this->mInfo['timestamp'] )
314  ? strval( $this->mInfo['timestamp'] )
315  : null
316  );
317  }
318 
322  public function getMimeType() {
323  if ( !isset( $this->mInfo['mime'] ) ) {
324  $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
325  $this->mInfo['mime'] = $magic->getMimeTypeFromExtensionOrNull( $this->getExtension() );
326  }
327 
328  return $this->mInfo['mime'];
329  }
330 
334  public function getMediaType() {
335  if ( isset( $this->mInfo['mediatype'] ) ) {
336  return $this->mInfo['mediatype'];
337  }
338  $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
339 
340  return $magic->getMediaType( null, $this->getMimeType() );
341  }
342 
346  public function getDescriptionUrl() {
347  return $this->mInfo['descriptionurl'] ?? false;
348  }
349 
355  public function getThumbPath( $suffix = '' ) {
356  if ( !$this->repo->canCacheThumbs() ) {
357  return null;
358  }
359 
360  $path = $this->repo->getZonePath( 'thumb' ) . '/' . $this->getHashPath();
361  if ( $suffix ) {
362  $path .= $suffix . '/';
363  }
364  return $path;
365  }
366 
370  protected function getThumbnails() {
371  $dir = $this->getThumbPath( $this->getName() );
372  $iter = $this->repo->getBackend()->getFileList( [ 'dir' => $dir ] );
373 
374  $files = [];
375  if ( $iter ) {
376  foreach ( $iter as $file ) {
377  $files[] = $file;
378  }
379  }
380 
381  return $files;
382  }
383 
384  public function purgeCache( $options = [] ) {
385  $this->purgeThumbnails( $options );
386  $this->purgeDescriptionPage();
387  }
388 
389  private function purgeDescriptionPage() {
390  $services = MediaWikiServices::getInstance();
391  $langCode = $services->getContentLanguage()->getCode();
392 
393  // Key must match File::getDescriptionText
394  $key = $this->repo->getLocalCacheKey( 'file-remote-description', $langCode, md5( $this->getName() ) );
395  $services->getMainWANObjectCache()->delete( $key );
396  }
397 
401  public function purgeThumbnails( $options = [] ) {
402  $key = $this->repo->getLocalCacheKey( 'file-thumb-url', sha1( $this->getName() ) );
403  MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
404 
405  $files = $this->getThumbnails();
406  // Give media handler a chance to filter the purge list
407  $handler = $this->getHandler();
408  if ( $handler ) {
409  $handler->filterThumbnailPurgeList( $files, $options );
410  }
411 
412  $dir = $this->getThumbPath( $this->getName() );
413  $purgeList = [];
414  foreach ( $files as $file ) {
415  $purgeList[] = "{$dir}{$file}";
416  }
417 
418  # Delete the thumbnails
419  $this->repo->quickPurgeBatch( $purgeList );
420  # Clear out the thumbnail directory if empty
421  $this->repo->quickCleanDir( $dir );
422  }
423 
429  public function isTransformedLocally() {
430  return false;
431  }
432 }
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:535
if(!defined('MW_SETUP_CALLBACK'))
Definition: WebStart.php:88
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:70
assertRepoDefined()
Assert that $this->repo is set to a valid FileRepo instance.
Definition: File.php:2460
getName()
Return the name of this file.
Definition: File.php:336
FileRepo LocalRepo ForeignAPIRepo false $repo
Some member variables can be lazy-initialised using __get().
Definition: File.php:117
canRender()
Checks if the output of transform() for this file is likely to be valid.
Definition: File.php:866
Title string false $title
Definition: File.php:120
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.
Represents a title within MediaWiki.
Definition: Title.php:76
getDBkey()
Get the main part with underscores.
Definition: Title.php:1049
Value object representing a user's identity.
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