image_cache.cls.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. /**
  3. * @package dompdf
  4. * @link http://dompdf.github.com/
  5. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  6. * @author Helmut Tischer <htischer@weihenstephan.org>
  7. * @author Fabien Ménager <fabien.menager@gmail.com>
  8. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  9. */
  10. /**
  11. * Static class that resolves image urls and downloads and caches
  12. * remote images if required.
  13. *
  14. * @access private
  15. * @package dompdf
  16. */
  17. class Image_Cache {
  18. /**
  19. * Array of downloaded images. Cached so that identical images are
  20. * not needlessly downloaded.
  21. *
  22. * @var array
  23. */
  24. static protected $_cache = array();
  25. /**
  26. * The url to the "broken image" used when images can't be loade
  27. *
  28. * @var string
  29. */
  30. public static $broken_image;
  31. /**
  32. * Resolve and fetch an image for use.
  33. *
  34. * @param string $url The url of the image
  35. * @param string $protocol Default protocol if none specified in $url
  36. * @param string $host Default host if none specified in $url
  37. * @param string $base_path Default path if none specified in $url
  38. * @param DOMPDF $dompdf The DOMPDF instance
  39. *
  40. * @throws DOMPDF_Image_Exception
  41. * @return array An array with two elements: The local path to the image and the image extension
  42. */
  43. static function resolve_url($url, $protocol, $host, $base_path, DOMPDF $dompdf) {
  44. $parsed_url = explode_url($url);
  45. $message = null;
  46. $remote = ($protocol && $protocol !== "file://") || ($parsed_url['protocol'] != "");
  47. $data_uri = strpos($parsed_url['protocol'], "data:") === 0;
  48. $full_url = null;
  49. $enable_remote = $dompdf->get_option("enable_remote");
  50. try {
  51. // Remote not allowed and is not DataURI
  52. if ( !$enable_remote && $remote && !$data_uri ) {
  53. throw new DOMPDF_Image_Exception("DOMPDF_ENABLE_REMOTE is set to FALSE");
  54. }
  55. // Remote allowed or DataURI
  56. else if ( $enable_remote && $remote || $data_uri ) {
  57. // Download remote files to a temporary directory
  58. $full_url = build_url($protocol, $host, $base_path, $url);
  59. // From cache
  60. if ( isset(self::$_cache[$full_url]) ) {
  61. $resolved_url = self::$_cache[$full_url];
  62. }
  63. // From remote
  64. else {
  65. $tmp_dir = $dompdf->get_option("temp_dir");
  66. $resolved_url = tempnam($tmp_dir, "ca_dompdf_img_");
  67. $image = "";
  68. if ($data_uri) {
  69. if ($parsed_data_uri = parse_data_uri($url)) {
  70. $image = $parsed_data_uri['data'];
  71. }
  72. }
  73. else {
  74. set_error_handler("record_warnings");
  75. $image = file_get_contents($full_url);
  76. restore_error_handler();
  77. }
  78. // Image not found or invalid
  79. if ( strlen($image) == 0 ) {
  80. $msg = ($data_uri ? "Data-URI could not be parsed" : "Image not found");
  81. throw new DOMPDF_Image_Exception($msg);
  82. }
  83. // Image found, put in cache and process
  84. else {
  85. //e.g. fetch.php?media=url.jpg&cache=1
  86. //- Image file name might be one of the dynamic parts of the url, don't strip off!
  87. //- a remote url does not need to have a file extension at all
  88. //- local cached file does not have a matching file extension
  89. //Therefore get image type from the content
  90. file_put_contents($resolved_url, $image);
  91. }
  92. }
  93. }
  94. // Not remote, local image
  95. else {
  96. $resolved_url = build_url($protocol, $host, $base_path, $url);
  97. }
  98. // Check if the local file is readable
  99. if ( !is_readable($resolved_url) || !filesize($resolved_url) ) {
  100. throw new DOMPDF_Image_Exception("Image not readable or empty");
  101. }
  102. // Check is the file is an image
  103. else {
  104. list($width, $height, $type) = dompdf_getimagesize($resolved_url);
  105. // Known image type
  106. if ( $width && $height && in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP)) ) {
  107. //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup.
  108. //Only execute on successful caching of remote image.
  109. if ( $enable_remote && $remote || $data_uri ) {
  110. self::$_cache[$full_url] = $resolved_url;
  111. }
  112. }
  113. // Unknown image type
  114. else {
  115. throw new DOMPDF_Image_Exception("Image type unknown");
  116. }
  117. }
  118. }
  119. catch(DOMPDF_Image_Exception $e) {
  120. $resolved_url = self::$broken_image;
  121. $type = IMAGETYPE_PNG;
  122. $message = $e->getMessage()." \n $url";
  123. }
  124. return array($resolved_url, $type, $message);
  125. }
  126. /**
  127. * Unlink all cached images (i.e. temporary images either downloaded
  128. * or converted)
  129. */
  130. static function clear() {
  131. if ( empty(self::$_cache) || DEBUGKEEPTEMP ) return;
  132. foreach ( self::$_cache as $file ) {
  133. if (DEBUGPNG) print "[clear unlink $file]";
  134. unlink($file);
  135. }
  136. self::$_cache = array();
  137. }
  138. static function detect_type($file) {
  139. list(, , $type) = dompdf_getimagesize($file);
  140. return $type;
  141. }
  142. static function type_to_ext($type) {
  143. $image_types = array(
  144. IMAGETYPE_GIF => "gif",
  145. IMAGETYPE_PNG => "png",
  146. IMAGETYPE_JPEG => "jpeg",
  147. IMAGETYPE_BMP => "bmp",
  148. );
  149. return (isset($image_types[$type]) ? $image_types[$type] : null);
  150. }
  151. static function is_broken($url) {
  152. return $url === self::$broken_image;
  153. }
  154. }
  155. Image_Cache::$broken_image = DOMPDF_LIB_DIR . "/res/broken_image.png";