MediaTransformOutput.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /**
  3. * Base class for the output of file transformation methods.
  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. /**
  24. * Base class for the output of MediaHandler::doTransform() and File::transform().
  25. *
  26. * @ingroup Media
  27. */
  28. abstract class MediaTransformOutput {
  29. /** @var array Associative array mapping optional supplementary image files
  30. * from pixel density (eg 1.5 or 2) to additional URLs.
  31. */
  32. public $responsiveUrls = [];
  33. /** @var File */
  34. protected $file;
  35. /** @var int Image width */
  36. protected $width;
  37. /** @var int Image height */
  38. protected $height;
  39. /** @var string URL path to the thumb */
  40. protected $url;
  41. /** @var bool|string */
  42. protected $page;
  43. /** @var bool|string Filesystem path to the thumb */
  44. protected $path;
  45. /** @var bool|string Language code, false if not set */
  46. protected $lang;
  47. /** @var bool|string Permanent storage path */
  48. protected $storagePath = false;
  49. /**
  50. * @return int Width of the output box
  51. */
  52. public function getWidth() {
  53. return $this->width;
  54. }
  55. /**
  56. * @return int Height of the output box
  57. */
  58. public function getHeight() {
  59. return $this->height;
  60. }
  61. /**
  62. * @return File
  63. */
  64. public function getFile() {
  65. return $this->file;
  66. }
  67. /**
  68. * Get the final extension of the thumbnail.
  69. * Returns false for scripted transformations.
  70. * @return string|bool
  71. */
  72. public function getExtension() {
  73. return $this->path ? FileBackend::extensionFromPath( $this->path ) : false;
  74. }
  75. /**
  76. * @return string|bool The thumbnail URL
  77. */
  78. public function getUrl() {
  79. return $this->url;
  80. }
  81. /**
  82. * @return string|bool The permanent thumbnail storage path
  83. */
  84. public function getStoragePath() {
  85. return $this->storagePath;
  86. }
  87. /**
  88. * @param string $storagePath The permanent storage path
  89. * @return void
  90. */
  91. public function setStoragePath( $storagePath ) {
  92. $this->storagePath = $storagePath;
  93. if ( $this->path === false ) {
  94. $this->path = $storagePath;
  95. }
  96. }
  97. /**
  98. * Fetch HTML for this transform output
  99. *
  100. * @param array $options Associative array of options. Boolean options
  101. * should be indicated with a value of true for true, and false or
  102. * absent for false.
  103. *
  104. * alt Alternate text or caption
  105. * desc-link Boolean, show a description link
  106. * file-link Boolean, show a file download link
  107. * custom-url-link Custom URL to link to
  108. * custom-title-link Custom Title object to link to
  109. * valign vertical-align property, if the output is an inline element
  110. * img-class Class applied to the "<img>" tag, if there is such a tag
  111. *
  112. * For images, desc-link and file-link are implemented as a click-through. For
  113. * sounds and videos, they may be displayed in other ways.
  114. *
  115. * @return string
  116. */
  117. abstract public function toHtml( $options = [] );
  118. /**
  119. * This will be overridden to return true in error classes
  120. * @return bool
  121. */
  122. public function isError() {
  123. return false;
  124. }
  125. /**
  126. * Check if an output thumbnail file actually exists.
  127. *
  128. * This will return false if there was an error, the
  129. * thumbnail is to be handled client-side only, or if
  130. * transformation was deferred via TRANSFORM_LATER.
  131. * This file may exist as a new file in /tmp, a file
  132. * in permanent storage, or even refer to the original.
  133. *
  134. * @return bool
  135. */
  136. public function hasFile() {
  137. // If TRANSFORM_LATER, $this->path will be false.
  138. // Note: a null path means "use the source file".
  139. return ( !$this->isError() && ( $this->path || $this->path === null ) );
  140. }
  141. /**
  142. * Check if the output thumbnail is the same as the source.
  143. * This can occur if the requested width was bigger than the source.
  144. *
  145. * @return bool
  146. */
  147. public function fileIsSource() {
  148. return ( !$this->isError() && $this->path === null );
  149. }
  150. /**
  151. * Get the path of a file system copy of the thumbnail.
  152. * Callers should never write to this path.
  153. *
  154. * @return string|bool Returns false if there isn't one
  155. */
  156. public function getLocalCopyPath() {
  157. if ( $this->isError() ) {
  158. return false;
  159. } elseif ( $this->path === null ) {
  160. return $this->file->getLocalRefPath(); // assume thumb was not scaled
  161. } elseif ( FileBackend::isStoragePath( $this->path ) ) {
  162. $be = $this->file->getRepo()->getBackend();
  163. // The temp file will be process cached by FileBackend
  164. $fsFile = $be->getLocalReference( [ 'src' => $this->path ] );
  165. return $fsFile ? $fsFile->getPath() : false;
  166. } else {
  167. return $this->path; // may return false
  168. }
  169. }
  170. /**
  171. * Stream the file if there were no errors
  172. *
  173. * @param array $headers Additional HTTP headers to send on success
  174. * @return Status
  175. * @since 1.27
  176. */
  177. public function streamFileWithStatus( $headers = [] ) {
  178. if ( !$this->path ) {
  179. return Status::newFatal( 'backend-fail-stream', '<no path>' );
  180. } elseif ( FileBackend::isStoragePath( $this->path ) ) {
  181. $be = $this->file->getRepo()->getBackend();
  182. return Status::wrap(
  183. $be->streamFile( [ 'src' => $this->path, 'headers' => $headers ] ) );
  184. } else { // FS-file
  185. $success = StreamFile::stream( $this->getLocalCopyPath(), $headers );
  186. return $success ? Status::newGood() : Status::newFatal( 'backend-fail-stream', $this->path );
  187. }
  188. }
  189. /**
  190. * Stream the file if there were no errors
  191. *
  192. * @deprecated since 1.26, use streamFileWithStatus
  193. * @param array $headers Additional HTTP headers to send on success
  194. * @return bool Success
  195. */
  196. public function streamFile( $headers = [] ) {
  197. return $this->streamFileWithStatus( $headers )->isOK();
  198. }
  199. /**
  200. * Wrap some XHTML text in an anchor tag with the given attributes
  201. *
  202. * @param array $linkAttribs
  203. * @param string $contents
  204. * @return string
  205. */
  206. protected function linkWrap( $linkAttribs, $contents ) {
  207. if ( $linkAttribs ) {
  208. return Xml::tags( 'a', $linkAttribs, $contents );
  209. } else {
  210. return $contents;
  211. }
  212. }
  213. /**
  214. * @param string|null $title
  215. * @param string|array $params Query parameters to add
  216. * @return array
  217. */
  218. public function getDescLinkAttribs( $title = null, $params = [] ) {
  219. if ( is_array( $params ) ) {
  220. $query = $params;
  221. } else {
  222. $query = [];
  223. }
  224. if ( $this->page && $this->page !== 1 ) {
  225. $query['page'] = $this->page;
  226. }
  227. if ( $this->lang ) {
  228. $query['lang'] = $this->lang;
  229. }
  230. if ( is_string( $params ) && $params !== '' ) {
  231. $query = $params . '&' . wfArrayToCgi( $query );
  232. }
  233. $attribs = [
  234. 'href' => $this->file->getTitle()->getLocalURL( $query ),
  235. 'class' => 'image',
  236. ];
  237. if ( $title ) {
  238. $attribs['title'] = $title;
  239. }
  240. return $attribs;
  241. }
  242. }