[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/media/ -> MediaTransformOutput.php (source)

   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  /**
  25   * Base class for the output of MediaHandler::doTransform() and File::transform().
  26   *
  27   * @ingroup Media
  28   */
  29  abstract class MediaTransformOutput {
  30      /** @var array Associative array mapping optional supplementary image files
  31       *  from pixel density (eg 1.5 or 2) to additional URLs.
  32       */
  33      public $responsiveUrls = array();
  34  
  35      /** @var File */
  36      protected $file;
  37  
  38      /** @var int Image width */
  39      protected $width;
  40  
  41      /** @var int Image height */
  42      protected $height;
  43  
  44      /** @var string URL path to the thumb */
  45      protected $url;
  46  
  47      /** @var bool|string */
  48      protected $page;
  49  
  50      /** @var bool|string Filesystem path to the thumb  */
  51      protected $path;
  52  
  53      /** @var bool|string Language code, false if not set */
  54      protected $lang;
  55  
  56      /** @var bool|string Permanent storage path  */
  57      protected $storagePath = false;
  58  
  59      /**
  60       * @return int Width of the output box
  61       */
  62  	public function getWidth() {
  63          return $this->width;
  64      }
  65  
  66      /**
  67       * @return int Height of the output box
  68       */
  69  	public function getHeight() {
  70          return $this->height;
  71      }
  72  
  73      /**
  74       * @return File
  75       */
  76  	public function getFile() {
  77          return $this->file;
  78      }
  79  
  80      /**
  81       * Get the final extension of the thumbnail.
  82       * Returns false for scripted transformations.
  83       * @return string|bool
  84       */
  85  	public function getExtension() {
  86          return $this->path ? FileBackend::extensionFromPath( $this->path ) : false;
  87      }
  88  
  89      /**
  90       * @return string|bool The thumbnail URL
  91       */
  92  	public function getUrl() {
  93          return $this->url;
  94      }
  95  
  96      /**
  97       * @return string|bool The permanent thumbnail storage path
  98       */
  99  	public function getStoragePath() {
 100          return $this->storagePath;
 101      }
 102  
 103      /**
 104       * @param string $storagePath The permanent storage path
 105       * @return void
 106       */
 107  	public function setStoragePath( $storagePath ) {
 108          $this->storagePath = $storagePath;
 109          if ( $this->path === false ) {
 110              $this->path = $storagePath;
 111          }
 112      }
 113  
 114      /**
 115       * Fetch HTML for this transform output
 116       *
 117       * @param array $options Associative array of options. Boolean options
 118       *     should be indicated with a value of true for true, and false or
 119       *     absent for false.
 120       *
 121       *     alt          Alternate text or caption
 122       *     desc-link    Boolean, show a description link
 123       *     file-link    Boolean, show a file download link
 124       *     custom-url-link    Custom URL to link to
 125       *     custom-title-link  Custom Title object to link to
 126       *     valign       vertical-align property, if the output is an inline element
 127       *     img-class    Class applied to the "<img>" tag, if there is such a tag
 128       *
 129       * For images, desc-link and file-link are implemented as a click-through. For
 130       * sounds and videos, they may be displayed in other ways.
 131       *
 132       * @return string
 133       */
 134      abstract public function toHtml( $options = array() );
 135  
 136      /**
 137       * This will be overridden to return true in error classes
 138       * @return bool
 139       */
 140  	public function isError() {
 141          return false;
 142      }
 143  
 144      /**
 145       * Check if an output thumbnail file actually exists.
 146       *
 147       * This will return false if there was an error, the
 148       * thumbnail is to be handled client-side only, or if
 149       * transformation was deferred via TRANSFORM_LATER.
 150       * This file may exist as a new file in /tmp, a file
 151       * in permanent storage, or even refer to the original.
 152       *
 153       * @return bool
 154       */
 155  	public function hasFile() {
 156          // If TRANSFORM_LATER, $this->path will be false.
 157          // Note: a null path means "use the source file".
 158          return ( !$this->isError() && ( $this->path || $this->path === null ) );
 159      }
 160  
 161      /**
 162       * Check if the output thumbnail is the same as the source.
 163       * This can occur if the requested width was bigger than the source.
 164       *
 165       * @return bool
 166       */
 167  	public function fileIsSource() {
 168          return ( !$this->isError() && $this->path === null );
 169      }
 170  
 171      /**
 172       * Get the path of a file system copy of the thumbnail.
 173       * Callers should never write to this path.
 174       *
 175       * @return string|bool Returns false if there isn't one
 176       */
 177  	public function getLocalCopyPath() {
 178          if ( $this->isError() ) {
 179              return false;
 180          } elseif ( $this->path === null ) {
 181              return $this->file->getLocalRefPath(); // assume thumb was not scaled
 182          } elseif ( FileBackend::isStoragePath( $this->path ) ) {
 183              $be = $this->file->getRepo()->getBackend();
 184              // The temp file will be process cached by FileBackend
 185              $fsFile = $be->getLocalReference( array( 'src' => $this->path ) );
 186  
 187              return $fsFile ? $fsFile->getPath() : false;
 188          } else {
 189              return $this->path; // may return false
 190          }
 191      }
 192  
 193      /**
 194       * Stream the file if there were no errors
 195       *
 196       * @param array $headers Additional HTTP headers to send on success
 197       * @return bool Success
 198       */
 199  	public function streamFile( $headers = array() ) {
 200          if ( !$this->path ) {
 201              return false;
 202          } elseif ( FileBackend::isStoragePath( $this->path ) ) {
 203              $be = $this->file->getRepo()->getBackend();
 204  
 205              return $be->streamFile( array( 'src' => $this->path, 'headers' => $headers ) )->isOK();
 206          } else { // FS-file
 207              return StreamFile::stream( $this->getLocalCopyPath(), $headers );
 208          }
 209      }
 210  
 211      /**
 212       * Wrap some XHTML text in an anchor tag with the given attributes
 213       *
 214       * @param array $linkAttribs
 215       * @param string $contents
 216       * @return string
 217       */
 218  	protected function linkWrap( $linkAttribs, $contents ) {
 219          if ( $linkAttribs ) {
 220              return Xml::tags( 'a', $linkAttribs, $contents );
 221          } else {
 222              return $contents;
 223          }
 224      }
 225  
 226      /**
 227       * @param string $title
 228       * @param string|array $params Query parameters to add
 229       * @return array
 230       */
 231  	public function getDescLinkAttribs( $title = null, $params = array() ) {
 232          if ( is_array( $params ) ) {
 233              $query = $params;
 234          } else {
 235              $query = array();
 236          }
 237          if ( $this->page && $this->page !== 1 ) {
 238              $query['page'] = $this->page;
 239          }
 240          if ( $this->lang ) {
 241              $query['lang'] = $this->lang;
 242          }
 243  
 244          if ( is_string( $params ) && $params !== '' ) {
 245              $query = $params . '&' . wfArrayToCgi( $query );
 246          }
 247  
 248          $attribs = array(
 249              'href' => $this->file->getTitle()->getLocalURL( $query ),
 250              'class' => 'image',
 251          );
 252          if ( $title ) {
 253              $attribs['title'] = $title;
 254          }
 255  
 256          return $attribs;
 257      }
 258  }
 259  
 260  /**
 261   * Media transform output for images
 262   *
 263   * @ingroup Media
 264   */
 265  class ThumbnailImage extends MediaTransformOutput {
 266      /**
 267       * Get a thumbnail object from a file and parameters.
 268       * If $path is set to null, the output file is treated as a source copy.
 269       * If $path is set to false, no output file will be created.
 270       * $parameters should include, as a minimum, (file) 'width' and 'height'.
 271       * It may also include a 'page' parameter for multipage files.
 272       *
 273       * @param File $file
 274       * @param string $url URL path to the thumb
 275       * @param string|bool $path Filesystem path to the thumb
 276       * @param array $parameters Associative array of parameters
 277       */
 278  	function __construct( $file, $url, $path = false, $parameters = array() ) {
 279          # Previous parameters:
 280          #   $file, $url, $width, $height, $path = false, $page = false
 281  
 282          $defaults = array(
 283              'page' => false,
 284              'lang' => false
 285          );
 286  
 287          if ( is_array( $parameters ) ) {
 288              $actualParams = $parameters + $defaults;
 289          } else {
 290              # Using old format, should convert. Later a warning could be added here.
 291              $numArgs = func_num_args();
 292              $actualParams = array(
 293                  'width' => $path,
 294                  'height' => $parameters,
 295                  'page' => ( $numArgs > 5 ) ? func_get_arg( 5 ) : false
 296              ) + $defaults;
 297              $path = ( $numArgs > 4 ) ? func_get_arg( 4 ) : false;
 298          }
 299  
 300          $this->file = $file;
 301          $this->url = $url;
 302          $this->path = $path;
 303  
 304          # These should be integers when they get here.
 305          # If not, there's a bug somewhere.  But let's at
 306          # least produce valid HTML code regardless.
 307          $this->width = round( $actualParams['width'] );
 308          $this->height = round( $actualParams['height'] );
 309  
 310          $this->page = $actualParams['page'];
 311          $this->lang = $actualParams['lang'];
 312      }
 313  
 314      /**
 315       * Return HTML <img ... /> tag for the thumbnail, will include
 316       * width and height attributes and a blank alt text (as required).
 317       *
 318       * @param array $options Associative array of options. Boolean options
 319       *     should be indicated with a value of true for true, and false or
 320       *     absent for false.
 321       *
 322       *     alt          HTML alt attribute
 323       *     title        HTML title attribute
 324       *     desc-link    Boolean, show a description link
 325       *     file-link    Boolean, show a file download link
 326       *     valign       vertical-align property, if the output is an inline element
 327       *     img-class    Class applied to the \<img\> tag, if there is such a tag
 328       *     desc-query   String, description link query params
 329       *     override-width     Override width attribute. Should generally not set
 330       *     override-height    Override height attribute. Should generally not set
 331       *     no-dimensions      Boolean, skip width and height attributes (useful if
 332       *                        set in CSS)
 333       *     custom-url-link    Custom URL to link to
 334       *     custom-title-link  Custom Title object to link to
 335       *     custom target-link Value of the target attribute, for custom-target-link
 336       *     parser-extlink-*   Attributes added by parser for external links:
 337       *          parser-extlink-rel: add rel="nofollow"
 338       *          parser-extlink-target: link target, but overridden by custom-target-link
 339       *
 340       * For images, desc-link and file-link are implemented as a click-through. For
 341       * sounds and videos, they may be displayed in other ways.
 342       *
 343       * @throws MWException
 344       * @return string
 345       */
 346  	function toHtml( $options = array() ) {
 347          if ( count( func_get_args() ) == 2 ) {
 348              throw new MWException( __METHOD__ . ' called in the old style' );
 349          }
 350  
 351          $alt = empty( $options['alt'] ) ? '' : $options['alt'];
 352  
 353          $query = empty( $options['desc-query'] ) ? '' : $options['desc-query'];
 354  
 355          if ( !empty( $options['custom-url-link'] ) ) {
 356              $linkAttribs = array( 'href' => $options['custom-url-link'] );
 357              if ( !empty( $options['title'] ) ) {
 358                  $linkAttribs['title'] = $options['title'];
 359              }
 360              if ( !empty( $options['custom-target-link'] ) ) {
 361                  $linkAttribs['target'] = $options['custom-target-link'];
 362              } elseif ( !empty( $options['parser-extlink-target'] ) ) {
 363                  $linkAttribs['target'] = $options['parser-extlink-target'];
 364              }
 365              if ( !empty( $options['parser-extlink-rel'] ) ) {
 366                  $linkAttribs['rel'] = $options['parser-extlink-rel'];
 367              }
 368          } elseif ( !empty( $options['custom-title-link'] ) ) {
 369              /** @var Title $title */
 370              $title = $options['custom-title-link'];
 371              $linkAttribs = array(
 372                  'href' => $title->getLinkURL(),
 373                  'title' => empty( $options['title'] ) ? $title->getFullText() : $options['title']
 374              );
 375          } elseif ( !empty( $options['desc-link'] ) ) {
 376              $linkAttribs = $this->getDescLinkAttribs(
 377                  empty( $options['title'] ) ? null : $options['title'],
 378                  $query
 379              );
 380          } elseif ( !empty( $options['file-link'] ) ) {
 381              $linkAttribs = array( 'href' => $this->file->getURL() );
 382          } else {
 383              $linkAttribs = false;
 384          }
 385  
 386          $attribs = array(
 387              'alt' => $alt,
 388              'src' => $this->url,
 389          );
 390  
 391          if ( empty( $options['no-dimensions'] ) ) {
 392              $attribs['width'] = $this->width;
 393              $attribs['height'] = $this->height;
 394          }
 395          if ( !empty( $options['valign'] ) ) {
 396              $attribs['style'] = "vertical-align: {$options['valign']}";
 397          }
 398          if ( !empty( $options['img-class'] ) ) {
 399              $attribs['class'] = $options['img-class'];
 400          }
 401          if ( isset( $options['override-height'] ) ) {
 402              $attribs['height'] = $options['override-height'];
 403          }
 404          if ( isset( $options['override-width'] ) ) {
 405              $attribs['width'] = $options['override-width'];
 406          }
 407  
 408          // Additional densities for responsive images, if specified.
 409          if ( !empty( $this->responsiveUrls ) ) {
 410              $attribs['srcset'] = Html::srcSet( $this->responsiveUrls );
 411          }
 412  
 413          wfRunHooks( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
 414  
 415          return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
 416      }
 417  }
 418  
 419  /**
 420   * Basic media transform error class
 421   *
 422   * @ingroup Media
 423   */
 424  class MediaTransformError extends MediaTransformOutput {
 425      /** @var string HTML formatted version of the error */
 426      private $htmlMsg;
 427  
 428      /** @var string Plain text formatted version of the error */
 429      private $textMsg;
 430  
 431  	function __construct( $msg, $width, $height /*, ... */ ) {
 432          $args = array_slice( func_get_args(), 3 );
 433          $htmlArgs = array_map( 'htmlspecialchars', $args );
 434          $htmlArgs = array_map( 'nl2br', $htmlArgs );
 435  
 436          $this->htmlMsg = wfMessage( $msg )->rawParams( $htmlArgs )->escaped();
 437          $this->textMsg = wfMessage( $msg )->rawParams( $htmlArgs )->text();
 438          $this->width = intval( $width );
 439          $this->height = intval( $height );
 440          $this->url = false;
 441          $this->path = false;
 442      }
 443  
 444  	function toHtml( $options = array() ) {
 445          return "<div class=\"MediaTransformError\" style=\"" .
 446              "width: {$this->width}px; height: {$this->height}px; display:inline-block;\">" .
 447              $this->htmlMsg .
 448              "</div>";
 449      }
 450  
 451  	function toText() {
 452          return $this->textMsg;
 453      }
 454  
 455  	function getHtmlMsg() {
 456          return $this->htmlMsg;
 457      }
 458  
 459  	function isError() {
 460          return true;
 461      }
 462  }
 463  
 464  /**
 465   * Shortcut class for parameter validation errors
 466   *
 467   * @ingroup Media
 468   */
 469  class TransformParameterError extends MediaTransformError {
 470  	function __construct( $params ) {
 471          parent::__construct( 'thumbnail_error',
 472              max( isset( $params['width'] ) ? $params['width'] : 0, 120 ),
 473              max( isset( $params['height'] ) ? $params['height'] : 0, 120 ),
 474              wfMessage( 'thumbnail_invalid_params' )->text() );
 475      }
 476  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1