MediaHandler.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. <?php
  2. /**
  3. * Media-handling base classes and generic functionality.
  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 Media
  22. */
  23. use MediaWiki\MediaWikiServices;
  24. /**
  25. * Base media handler class
  26. *
  27. * @ingroup Media
  28. */
  29. abstract class MediaHandler {
  30. const TRANSFORM_LATER = 1;
  31. const METADATA_GOOD = true;
  32. const METADATA_BAD = false;
  33. const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
  34. /**
  35. * Max length of error logged by logErrorForExternalProcess()
  36. */
  37. const MAX_ERR_LOG_SIZE = 65535;
  38. /**
  39. * Get a MediaHandler for a given MIME type from the instance cache
  40. *
  41. * @param string $type
  42. * @return MediaHandler|bool
  43. */
  44. static function getHandler( $type ) {
  45. return MediaWikiServices::getInstance()
  46. ->getMediaHandlerFactory()->getHandler( $type );
  47. }
  48. /**
  49. * Get an associative array mapping magic word IDs to parameter names.
  50. * Will be used by the parser to identify parameters.
  51. */
  52. abstract public function getParamMap();
  53. /**
  54. * Validate a thumbnail parameter at parse time.
  55. * Return true to accept the parameter, and false to reject it.
  56. * If you return false, the parser will do something quiet and forgiving.
  57. *
  58. * @param string $name
  59. * @param mixed $value
  60. */
  61. abstract public function validateParam( $name, $value );
  62. /**
  63. * Merge a parameter array into a string appropriate for inclusion in filenames
  64. *
  65. * @param array $params Array of parameters that have been through normaliseParams.
  66. * @return string
  67. */
  68. abstract public function makeParamString( $params );
  69. /**
  70. * Parse a param string made with makeParamString back into an array
  71. *
  72. * @param string $str The parameter string without file name (e.g. 122px)
  73. * @return array|bool Array of parameters or false on failure.
  74. */
  75. abstract public function parseParamString( $str );
  76. /**
  77. * Changes the parameter array as necessary, ready for transformation.
  78. * Should be idempotent.
  79. * Returns false if the parameters are unacceptable and the transform should fail
  80. * @param File $image
  81. * @param array &$params
  82. */
  83. abstract function normaliseParams( $image, &$params );
  84. /**
  85. * Get an image size array like that returned by getimagesize(), or false if it
  86. * can't be determined.
  87. *
  88. * This function is used for determining the width, height and bitdepth directly
  89. * from an image. The results are stored in the database in the img_width,
  90. * img_height, img_bits fields.
  91. *
  92. * @note If this is a multipage file, return the width and height of the
  93. * first page.
  94. *
  95. * @param File|FSFile $image The image object, or false if there isn't one.
  96. * Warning, FSFile::getPropsFromPath might pass an FSFile instead of File (!)
  97. * @param string $path The filename
  98. * @return array|bool Follow the format of PHP getimagesize() internal function.
  99. * See https://secure.php.net/getimagesize. MediaWiki will only ever use the
  100. * first two array keys (the width and height), and the 'bits' associative
  101. * key. All other array keys are ignored. Returning a 'bits' key is optional
  102. * as not all formats have a notion of "bitdepth". Returns false on failure.
  103. */
  104. abstract function getImageSize( $image, $path );
  105. /**
  106. * Get handler-specific metadata which will be saved in the img_metadata field.
  107. *
  108. * @param File|FSFile $image The image object, or false if there isn't one.
  109. * Warning, FSFile::getPropsFromPath might pass an FSFile instead of File (!)
  110. * @param string $path The filename
  111. * @return string A string of metadata in php serialized form (Run through serialize())
  112. */
  113. function getMetadata( $image, $path ) {
  114. return '';
  115. }
  116. /**
  117. * Get metadata version.
  118. *
  119. * This is not used for validating metadata, this is used for the api when returning
  120. * metadata, since api content formats should stay the same over time, and so things
  121. * using ForeignApiRepo can keep backwards compatibility
  122. *
  123. * All core media handlers share a common version number, and extensions can
  124. * use the GetMetadataVersion hook to append to the array (they should append a unique
  125. * string so not to get confusing). If there was a media handler named 'foo' with metadata
  126. * version 3 it might add to the end of the array the element 'foo=3'. if the core metadata
  127. * version is 2, the end version string would look like '2;foo=3'.
  128. *
  129. * @return string Version string
  130. */
  131. static function getMetadataVersion() {
  132. $version = [ '2' ]; // core metadata version
  133. Hooks::run( 'GetMetadataVersion', [ &$version ] );
  134. return implode( ';', $version );
  135. }
  136. /**
  137. * Convert metadata version.
  138. *
  139. * By default just returns $metadata, but can be used to allow
  140. * media handlers to convert between metadata versions.
  141. *
  142. * @param string|array $metadata Metadata array (serialized if string)
  143. * @param int $version Target version
  144. * @return array Serialized metadata in specified version, or $metadata on fail.
  145. */
  146. function convertMetadataVersion( $metadata, $version = 1 ) {
  147. if ( !is_array( $metadata ) ) {
  148. // unserialize to keep return parameter consistent.
  149. Wikimedia\suppressWarnings();
  150. $ret = unserialize( $metadata );
  151. Wikimedia\restoreWarnings();
  152. return $ret;
  153. }
  154. return $metadata;
  155. }
  156. /**
  157. * Get a string describing the type of metadata, for display purposes.
  158. *
  159. * @note This method is currently unused.
  160. * @param File $image
  161. * @return string
  162. */
  163. function getMetadataType( $image ) {
  164. return false;
  165. }
  166. /**
  167. * Check if the metadata string is valid for this handler.
  168. * If it returns MediaHandler::METADATA_BAD (or false), Image
  169. * will reload the metadata from the file and update the database.
  170. * MediaHandler::METADATA_GOOD for if the metadata is a-ok,
  171. * MediaHandler::METADATA_COMPATIBLE if metadata is old but backwards
  172. * compatible (which may or may not trigger a metadata reload).
  173. *
  174. * @note Returning self::METADATA_BAD will trigger a metadata reload from
  175. * file on page view. Always returning this from a broken file, or suddenly
  176. * triggering as bad metadata for a large number of files can cause
  177. * performance problems.
  178. * @param File $image
  179. * @param string $metadata The metadata in serialized form
  180. * @return bool
  181. */
  182. function isMetadataValid( $image, $metadata ) {
  183. return self::METADATA_GOOD;
  184. }
  185. /**
  186. * Get an array of standard (FormatMetadata type) metadata values.
  187. *
  188. * The returned data is largely the same as that from getMetadata(),
  189. * but formatted in a standard, stable, handler-independent way.
  190. * The idea being that some values like ImageDescription or Artist
  191. * are universal and should be retrievable in a handler generic way.
  192. *
  193. * The specific properties are the type of properties that can be
  194. * handled by the FormatMetadata class. These values are exposed to the
  195. * user via the filemetadata parser function.
  196. *
  197. * Details of the response format of this function can be found at
  198. * https://www.mediawiki.org/wiki/Manual:File_metadata_handling
  199. * tl/dr: the response is an associative array of
  200. * properties keyed by name, but the value can be complex. You probably
  201. * want to call one of the FormatMetadata::flatten* functions on the
  202. * property values before using them, or call
  203. * FormatMetadata::getFormattedData() on the full response array, which
  204. * transforms all values into prettified, human-readable text.
  205. *
  206. * Subclasses overriding this function must return a value which is a
  207. * valid API response fragment (all associative array keys are valid
  208. * XML tagnames).
  209. *
  210. * Note, if the file simply has no metadata, but the handler supports
  211. * this interface, it should return an empty array, not false.
  212. *
  213. * @param File $file
  214. * @return array|bool False if interface not supported
  215. * @since 1.23
  216. */
  217. public function getCommonMetaArray( File $file ) {
  218. return false;
  219. }
  220. /**
  221. * Get a MediaTransformOutput object representing an alternate of the transformed
  222. * output which will call an intermediary thumbnail assist script.
  223. *
  224. * Used when the repository has a thumbnailScriptUrl option configured.
  225. *
  226. * Return false to fall back to the regular getTransform().
  227. * @param File $image
  228. * @param string $script
  229. * @param array $params
  230. * @return bool|ThumbnailImage
  231. */
  232. function getScriptedTransform( $image, $script, $params ) {
  233. return false;
  234. }
  235. /**
  236. * Get a MediaTransformOutput object representing the transformed output. Does not
  237. * actually do the transform.
  238. *
  239. * @param File $image
  240. * @param string $dstPath Filesystem destination path
  241. * @param string $dstUrl Destination URL to use in output HTML
  242. * @param array $params Arbitrary set of parameters validated by $this->validateParam()
  243. * @return MediaTransformOutput
  244. */
  245. final function getTransform( $image, $dstPath, $dstUrl, $params ) {
  246. return $this->doTransform( $image, $dstPath, $dstUrl, $params, self::TRANSFORM_LATER );
  247. }
  248. /**
  249. * Get a MediaTransformOutput object representing the transformed output. Does the
  250. * transform unless $flags contains self::TRANSFORM_LATER.
  251. *
  252. * @param File $image
  253. * @param string $dstPath Filesystem destination path
  254. * @param string $dstUrl Destination URL to use in output HTML
  255. * @param array $params Arbitrary set of parameters validated by $this->validateParam()
  256. * Note: These parameters have *not* gone through $this->normaliseParams()
  257. * @param int $flags A bitfield, may contain self::TRANSFORM_LATER
  258. * @return MediaTransformOutput
  259. */
  260. abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
  261. /**
  262. * Get the thumbnail extension and MIME type for a given source MIME type
  263. *
  264. * @param string $ext Extension of original file
  265. * @param string $mime MIME type of original file
  266. * @param array $params Handler specific rendering parameters
  267. * @return array Thumbnail extension and MIME type
  268. */
  269. function getThumbType( $ext, $mime, $params = null ) {
  270. $magic = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
  271. if ( !$ext || $magic->isMatchingExtension( $ext, $mime ) === false ) {
  272. // The extension is not valid for this MIME type and we do
  273. // recognize the MIME type
  274. $extensions = $magic->getExtensionsForType( $mime );
  275. if ( $extensions ) {
  276. return [ strtok( $extensions, ' ' ), $mime ];
  277. }
  278. }
  279. // The extension is correct (true) or the MIME type is unknown to
  280. // MediaWiki (null)
  281. return [ $ext, $mime ];
  282. }
  283. /**
  284. * @deprecated since 1.30, use MediaHandler::getContentHeaders instead
  285. * @param array $metadata
  286. * @return array
  287. */
  288. public function getStreamHeaders( $metadata ) {
  289. wfDeprecated( __METHOD__, '1.30' );
  290. return $this->getContentHeaders( $metadata );
  291. }
  292. /**
  293. * True if the handled types can be transformed
  294. *
  295. * @param File $file
  296. * @return bool
  297. */
  298. public function canRender( $file ) {
  299. return true;
  300. }
  301. /**
  302. * True if handled types cannot be displayed directly in a browser
  303. * but can be rendered
  304. *
  305. * @param File $file
  306. * @return bool
  307. */
  308. public function mustRender( $file ) {
  309. return false;
  310. }
  311. /**
  312. * True if the type has multi-page capabilities
  313. *
  314. * @param File $file
  315. * @return bool
  316. */
  317. public function isMultiPage( $file ) {
  318. return false;
  319. }
  320. /**
  321. * Page count for a multi-page document, false if unsupported or unknown
  322. *
  323. * @param File $file
  324. * @return bool
  325. */
  326. function pageCount( File $file ) {
  327. return false;
  328. }
  329. /**
  330. * The material is vectorized and thus scaling is lossless
  331. *
  332. * @param File $file
  333. * @return bool
  334. */
  335. function isVectorized( $file ) {
  336. return false;
  337. }
  338. /**
  339. * The material is an image, and is animated.
  340. * In particular, video material need not return true.
  341. * @note Before 1.20, this was a method of ImageHandler only
  342. *
  343. * @param File $file
  344. * @return bool
  345. */
  346. function isAnimatedImage( $file ) {
  347. return false;
  348. }
  349. /**
  350. * If the material is animated, we can animate the thumbnail
  351. * @since 1.20
  352. *
  353. * @param File $file
  354. * @return bool If material is not animated, handler may return any value.
  355. */
  356. function canAnimateThumbnail( $file ) {
  357. return true;
  358. }
  359. /**
  360. * False if the handler is disabled for all files
  361. * @return bool
  362. */
  363. function isEnabled() {
  364. return true;
  365. }
  366. /**
  367. * Get an associative array of page dimensions
  368. * Currently "width" and "height" are understood, but this might be
  369. * expanded in the future.
  370. * Returns false if unknown.
  371. *
  372. * It is expected that handlers for paged media (e.g. DjVuHandler)
  373. * will override this method so that it gives the correct results
  374. * for each specific page of the file, using the $page argument.
  375. *
  376. * @note For non-paged media, use getImageSize.
  377. *
  378. * @param File $image
  379. * @param int $page What page to get dimensions of
  380. * @return array|bool
  381. */
  382. function getPageDimensions( File $image, $page ) {
  383. $gis = $this->getImageSize( $image, $image->getLocalRefPath() );
  384. if ( $gis ) {
  385. return [
  386. 'width' => $gis[0],
  387. 'height' => $gis[1]
  388. ];
  389. } else {
  390. return false;
  391. }
  392. }
  393. /**
  394. * Generic getter for text layer.
  395. * Currently overloaded by PDF and DjVu handlers
  396. * @param File $image
  397. * @param int $page Page number to get information for
  398. * @return bool|string Page text or false when no text found or if
  399. * unsupported.
  400. */
  401. function getPageText( File $image, $page ) {
  402. return false;
  403. }
  404. /**
  405. * Get the text of the entire document.
  406. * @param File $file
  407. * @return bool|string The text of the document or false if unsupported.
  408. */
  409. public function getEntireText( File $file ) {
  410. $numPages = $file->pageCount();
  411. if ( !$numPages ) {
  412. // Not a multipage document
  413. return $this->getPageText( $file, 1 );
  414. }
  415. $document = '';
  416. for ( $i = 1; $i <= $numPages; $i++ ) {
  417. $curPage = $this->getPageText( $file, $i );
  418. if ( is_string( $curPage ) ) {
  419. $document .= $curPage . "\n";
  420. }
  421. }
  422. if ( $document !== '' ) {
  423. return $document;
  424. }
  425. return false;
  426. }
  427. /**
  428. * Get an array structure that looks like this:
  429. *
  430. * [
  431. * 'visible' => [
  432. * 'Human-readable name' => 'Human readable value',
  433. * ...
  434. * ],
  435. * 'collapsed' => [
  436. * 'Human-readable name' => 'Human readable value',
  437. * ...
  438. * ]
  439. * ]
  440. * The UI will format this into a table where the visible fields are always
  441. * visible, and the collapsed fields are optionally visible.
  442. *
  443. * The function should return false if there is no metadata to display.
  444. */
  445. /**
  446. * @todo FIXME: This interface is not very flexible. The media handler
  447. * should generate HTML instead. It can do all the formatting according
  448. * to some standard. That makes it possible to do things like visual
  449. * indication of grouped and chained streams in ogg container files.
  450. * @param File $image
  451. * @param bool|IContextSource $context Context to use (optional)
  452. * @return array|bool
  453. */
  454. function formatMetadata( $image, $context = false ) {
  455. return false;
  456. }
  457. /** sorts the visible/invisible field.
  458. * Split off from ImageHandler::formatMetadata, as used by more than
  459. * one type of handler.
  460. *
  461. * This is used by the media handlers that use the FormatMetadata class
  462. *
  463. * @param array $metadataArray
  464. * @param bool|IContextSource $context Context to use (optional)
  465. * @return array Array for use displaying metadata.
  466. */
  467. function formatMetadataHelper( $metadataArray, $context = false ) {
  468. $result = [
  469. 'visible' => [],
  470. 'collapsed' => []
  471. ];
  472. $formatted = FormatMetadata::getFormattedData( $metadataArray, $context );
  473. // Sort fields into visible and collapsed
  474. $visibleFields = $this->visibleMetadataFields();
  475. foreach ( $formatted as $name => $value ) {
  476. $tag = strtolower( $name );
  477. self::addMeta( $result,
  478. in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
  479. 'exif',
  480. $tag,
  481. $value
  482. );
  483. }
  484. return $result;
  485. }
  486. /**
  487. * Get a list of metadata items which should be displayed when
  488. * the metadata table is collapsed.
  489. *
  490. * @return array Array of strings
  491. */
  492. protected function visibleMetadataFields() {
  493. return FormatMetadata::getVisibleFields();
  494. }
  495. /**
  496. * This is used to generate an array element for each metadata value
  497. * That array is then used to generate the table of metadata values
  498. * on the image page
  499. *
  500. * @param array &$array An array containing elements for each type of visibility
  501. * and each of those elements being an array of metadata items. This function adds
  502. * a value to that array.
  503. * @param string $visibility ('visible' or 'collapsed') if this value is hidden
  504. * by default.
  505. * @param string $type Type of metadata tag (currently always 'exif')
  506. * @param string $id The name of the metadata tag (like 'artist' for example).
  507. * its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
  508. * @param string $value Thingy goes into a wikitext table; it used to be escaped but
  509. * that was incompatible with previous practise of customized display
  510. * with wikitext formatting via messages such as 'exif-model-value'.
  511. * So the escaping is taken back out, but generally this seems a confusing
  512. * interface.
  513. * @param bool|string $param Value to pass to the message for the name of the field
  514. * as $1. Currently this parameter doesn't seem to ever be used.
  515. *
  516. * Note, everything here is passed through the parser later on (!)
  517. */
  518. protected static function addMeta( &$array, $visibility, $type, $id, $value, $param = false ) {
  519. $msg = wfMessage( "$type-$id", $param );
  520. if ( $msg->exists() ) {
  521. $name = $msg->text();
  522. } else {
  523. // This is for future compatibility when using instant commons.
  524. // So as to not display as ugly a name if a new metadata
  525. // property is defined that we don't know about
  526. // (not a major issue since such a property would be collapsed
  527. // by default).
  528. wfDebug( __METHOD__ . ' Unknown metadata name: ' . $id . "\n" );
  529. $name = wfEscapeWikiText( $id );
  530. }
  531. $array[$visibility][] = [
  532. 'id' => "$type-$id",
  533. 'name' => $name,
  534. 'value' => $value
  535. ];
  536. }
  537. /**
  538. * Short description. Shown on Special:Search results.
  539. *
  540. * @param File $file
  541. * @return string
  542. */
  543. function getShortDesc( $file ) {
  544. return self::getGeneralShortDesc( $file );
  545. }
  546. /**
  547. * Long description. Shown under image on image description page surounded by ().
  548. *
  549. * @param File $file
  550. * @return string
  551. */
  552. function getLongDesc( $file ) {
  553. return self::getGeneralLongDesc( $file );
  554. }
  555. /**
  556. * Used instead of getShortDesc if there is no handler registered for file.
  557. *
  558. * @param File $file
  559. * @return string
  560. */
  561. static function getGeneralShortDesc( $file ) {
  562. global $wgLang;
  563. return htmlspecialchars( $wgLang->formatSize( $file->getSize() ) );
  564. }
  565. /**
  566. * Used instead of getLongDesc if there is no handler registered for file.
  567. *
  568. * @param File $file
  569. * @return string
  570. */
  571. static function getGeneralLongDesc( $file ) {
  572. return wfMessage( 'file-info' )->sizeParams( $file->getSize() )
  573. ->params( '<span class="mime-type">' . $file->getMimeType() . '</span>' )->parse();
  574. }
  575. /**
  576. * Calculate the largest thumbnail width for a given original file size
  577. * such that the thumbnail's height is at most $maxHeight.
  578. * @param int $boxWidth Width of the thumbnail box.
  579. * @param int $boxHeight Height of the thumbnail box.
  580. * @param int $maxHeight Maximum height expected for the thumbnail.
  581. * @return int
  582. */
  583. public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
  584. $idealWidth = $boxWidth * $maxHeight / $boxHeight;
  585. $roundedUp = ceil( $idealWidth );
  586. if ( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) {
  587. return floor( $idealWidth );
  588. } else {
  589. return $roundedUp;
  590. }
  591. }
  592. /**
  593. * Shown in file history box on image description page.
  594. *
  595. * @param File $file
  596. * @return string Dimensions
  597. */
  598. function getDimensionsString( $file ) {
  599. return '';
  600. }
  601. /**
  602. * Modify the parser object post-transform.
  603. *
  604. * This is often used to do $parser->addOutputHook(),
  605. * in order to add some javascript to render a viewer.
  606. * See TimedMediaHandler or OggHandler for an example.
  607. *
  608. * @param Parser $parser
  609. * @param File $file
  610. */
  611. function parserTransformHook( $parser, $file ) {
  612. }
  613. /**
  614. * File validation hook called on upload.
  615. *
  616. * If the file at the given local path is not valid, or its MIME type does not
  617. * match the handler class, a Status object should be returned containing
  618. * relevant errors.
  619. *
  620. * @param string $fileName The local path to the file.
  621. * @return Status
  622. */
  623. function verifyUpload( $fileName ) {
  624. return Status::newGood();
  625. }
  626. /**
  627. * Check for zero-sized thumbnails. These can be generated when
  628. * no disk space is available or some other error occurs
  629. *
  630. * @param string $dstPath The location of the suspect file
  631. * @param int $retval Return value of some shell process, file will be deleted if this is non-zero
  632. * @return bool True if removed, false otherwise
  633. */
  634. function removeBadFile( $dstPath, $retval = 0 ) {
  635. if ( file_exists( $dstPath ) ) {
  636. $thumbstat = stat( $dstPath );
  637. if ( $thumbstat['size'] == 0 || $retval != 0 ) {
  638. $result = unlink( $dstPath );
  639. if ( $result ) {
  640. wfDebugLog( 'thumbnail',
  641. sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() succeeded',
  642. $thumbstat['size'], $dstPath ) );
  643. } else {
  644. wfDebugLog( 'thumbnail',
  645. sprintf( 'Removing bad %d-byte thumbnail "%s". unlink() failed',
  646. $thumbstat['size'], $dstPath ) );
  647. }
  648. return true;
  649. }
  650. }
  651. return false;
  652. }
  653. /**
  654. * Remove files from the purge list.
  655. *
  656. * This is used by some video handlers to prevent ?action=purge
  657. * from removing a transcoded video, which is expensive to
  658. * regenerate.
  659. *
  660. * @see LocalFile::purgeThumbnails
  661. *
  662. * @param array &$files
  663. * @param array $options Purge options. Currently will always be
  664. * an array with a single key 'forThumbRefresh' set to true.
  665. */
  666. public function filterThumbnailPurgeList( &$files, $options ) {
  667. // Do nothing
  668. }
  669. /**
  670. * True if the handler can rotate the media
  671. * @since 1.24 non-static. From 1.21-1.23 was static
  672. * @return bool
  673. */
  674. public function canRotate() {
  675. return false;
  676. }
  677. /**
  678. * On supporting image formats, try to read out the low-level orientation
  679. * of the file and return the angle that the file needs to be rotated to
  680. * be viewed.
  681. *
  682. * This information is only useful when manipulating the original file;
  683. * the width and height we normally work with is logical, and will match
  684. * any produced output views.
  685. *
  686. * For files we don't know, we return 0.
  687. *
  688. * @param File $file
  689. * @return int 0, 90, 180 or 270
  690. */
  691. public function getRotation( $file ) {
  692. return 0;
  693. }
  694. /**
  695. * Log an error that occurred in an external process
  696. *
  697. * Moved from BitmapHandler to MediaHandler with MediaWiki 1.23
  698. *
  699. * @since 1.23
  700. * @param int $retval
  701. * @param string $err Error reported by command. Anything longer than
  702. * MediaHandler::MAX_ERR_LOG_SIZE is stripped off.
  703. * @param string $cmd
  704. */
  705. protected function logErrorForExternalProcess( $retval, $err, $cmd ) {
  706. # Keep error output limited (T59985)
  707. $errMessage = trim( substr( $err, 0, self::MAX_ERR_LOG_SIZE ) );
  708. wfDebugLog( 'thumbnail',
  709. sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
  710. wfHostname(), $retval, $errMessage, $cmd ) );
  711. }
  712. /**
  713. * Get list of languages file can be viewed in.
  714. *
  715. * @param File $file
  716. * @return string[] Array of language codes, or empty array if unsupported.
  717. * @since 1.23
  718. */
  719. public function getAvailableLanguages( File $file ) {
  720. return [];
  721. }
  722. /**
  723. * On file types that support renderings in multiple languages,
  724. * which language is used by default if unspecified.
  725. *
  726. * If getAvailableLanguages returns a non-empty array, this must return
  727. * a valid language code. Otherwise can return null if files of this
  728. * type do not support alternative language renderings.
  729. *
  730. * @param File $file
  731. * @return string|null Language code or null if multi-language not supported for filetype.
  732. * @since 1.23
  733. */
  734. public function getDefaultRenderLanguage( File $file ) {
  735. return null;
  736. }
  737. /**
  738. * If its an audio file, return the length of the file. Otherwise 0.
  739. *
  740. * File::getLength() existed for a long time, but was calling a method
  741. * that only existed in some subclasses of this class (The TMH ones).
  742. *
  743. * @param File $file
  744. * @return float Length in seconds
  745. * @since 1.23
  746. */
  747. public function getLength( $file ) {
  748. return 0.0;
  749. }
  750. /**
  751. * True if creating thumbnails from the file is large or otherwise resource-intensive.
  752. * @param File $file
  753. * @return bool
  754. */
  755. public function isExpensiveToThumbnail( $file ) {
  756. return false;
  757. }
  758. /**
  759. * Returns whether or not this handler supports the chained generation of thumbnails according
  760. * to buckets
  761. * @return bool
  762. * @since 1.24
  763. */
  764. public function supportsBucketing() {
  765. return false;
  766. }
  767. /**
  768. * Returns a normalised params array for which parameters have been cleaned up for bucketing
  769. * purposes
  770. * @param array $params
  771. * @return array
  772. */
  773. public function sanitizeParamsForBucketing( $params ) {
  774. return $params;
  775. }
  776. /**
  777. * Gets configuration for the file warning message. Return value of
  778. * the following structure:
  779. * [
  780. * // Required, module with messages loaded for the client
  781. * 'module' => 'example.filewarning.messages',
  782. * // Required, array of names of messages
  783. * 'messages' => [
  784. * // Required, main warning message
  785. * 'main' => 'example-filewarning-main',
  786. * // Optional, header for warning dialog
  787. * 'header' => 'example-filewarning-header',
  788. * // Optional, footer for warning dialog
  789. * 'footer' => 'example-filewarning-footer',
  790. * // Optional, text for more-information link (see below)
  791. * 'info' => 'example-filewarning-info',
  792. * ],
  793. * // Optional, link for more information
  794. * 'link' => 'http://example.com',
  795. * ]
  796. *
  797. * Returns null if no warning is necessary.
  798. * @param File $file
  799. * @return array|null
  800. */
  801. public function getWarningConfig( $file ) {
  802. return null;
  803. }
  804. /**
  805. * Converts a dimensions array about a potentially multipage document from an
  806. * exhaustive list of ordered page numbers to a list of page ranges
  807. * @param Array $pagesByDimensions
  808. * @return String
  809. * @since 1.30
  810. */
  811. public static function getPageRangesByDimensions( $pagesByDimensions ) {
  812. $pageRangesByDimensions = [];
  813. foreach ( $pagesByDimensions as $dimensions => $pageList ) {
  814. $ranges = [];
  815. $firstPage = $pageList[0];
  816. $lastPage = $firstPage - 1;
  817. foreach ( $pageList as $page ) {
  818. if ( $page > $lastPage + 1 ) {
  819. if ( $firstPage != $lastPage ) {
  820. $ranges[] = "$firstPage-$lastPage";
  821. } else {
  822. $ranges[] = "$firstPage";
  823. }
  824. $firstPage = $page;
  825. }
  826. $lastPage = $page;
  827. }
  828. if ( $firstPage != $lastPage ) {
  829. $ranges[] = "$firstPage-$lastPage";
  830. } else {
  831. $ranges[] = "$firstPage";
  832. }
  833. $pageRangesByDimensions[ $dimensions ] = $ranges;
  834. }
  835. $dimensionsString = [];
  836. foreach ( $pageRangesByDimensions as $dimensions => $pageRanges ) {
  837. $dimensionsString[] = "$dimensions:" . implode( ',', $pageRanges );
  838. }
  839. return implode( '/', $dimensionsString );
  840. }
  841. /**
  842. * Get useful response headers for GET/HEAD requests for a file with the given metadata
  843. * @param array $metadata Contains this handler's unserialized getMetadata() for a file
  844. * @return array
  845. * @since 1.30
  846. */
  847. public function getContentHeaders( $metadata ) {
  848. return [ 'X-Content-Dimensions' => '' ]; // T175689
  849. }
  850. }