1<?php 2/** 3 * DokuWiki Plugin mediathumbnails (thumbnail class) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Thomas Schäfer <thomas.schaefer@itschert.net> 7 */ 8 9require('thumb_engines.php'); 10 11function getFileSuffix(string $file) { 12 return substr(strrchr($file,'.'),1); 13} 14 15class thumbnail { 16 17 private string $source_filepath; 18 private string $source_mediapath; 19 private ?thumb_engine $thumb_engine = null; 20 private int $max_dimension; 21 22 private static $formats; 23 private static ?bool $pdf_support = null; 24 private static ?bool $image_support = null; 25 private static ?bool $no_ghostscript_support = null; 26 private static ?bool $no_imagick_pdf_readwrite = null; 27 private static ?string $dependency_problem = null; 28 29 private static function testDependencies() { 30 31 self::$image_support = false; 32 self::$pdf_support = false; 33 self::$no_ghostscript_support = false; 34 self::$no_imagick_pdf_readwrite = false; 35 self::$dependency_problem = null; 36 37 if (class_exists ("Imagick")) { 38 // determine file formats supported by ImageMagick 39 self::$formats = \Imagick::queryformats(); 40 41 if (count(self::$formats) > 0) { 42 self::$image_support = true; 43 if (in_array("PDF", self::$formats)) { 44 // Check if GhostScript will answer! 45 try { 46 // blank.pdf is an empty reference PDF file to test if GhostScript will react upon loading the file into ImageMagick 47 $im = new imagick(realpath("lib/plugins/mediathumbnails/blank.pdf")."[0]"); 48 $im->clear(); 49 $im->destroy(); 50 self::$pdf_support = true; 51 } catch (ImagickException $e) { 52 if (strpos($e,"PDFDelegateFailed") !== false) { 53 self::$no_ghostscript_support = true; 54 } 55 if (strpos($e,"security policy") !== false) { 56 self::$no_imagick_pdf_readwrite = true; 57 } 58 self::$pdf_support = false; 59 self::$dependency_problem = "Catched ImagickException: ".$e->getMessage(); 60 } 61 } else { 62 self::$dependency_problem = "Imagick reports it does not support PDF files."; 63 } 64 } else { 65 self::$dependency_problem = "Imagick reports it doesn't support any output formats."; 66 } 67 68 } else { 69 self::$dependency_problem = "Imagick class not found: ImageMagick PHP extension is not installed."; 70 } 71 } 72 public static function supportsPDF() { 73 if (self::$pdf_support === null) { 74 self::testDependencies(); 75 } 76 return self::$pdf_support; 77 } 78 public static function supportsImages() { 79 if (self::$image_support === null) { 80 self::testDependencies(); 81 } 82 return self::$image_support; 83 } 84 public static function ghostScriptFailed() { 85 if (self::$no_ghostscript_support === null) { 86 self::testDependencies(); 87 } 88 return self::$no_ghostscript_support; 89 } 90 public static function imagickPDFpolicyFailed() { 91 if (self::$no_imagick_pdf_readwrite === null) { 92 self::testDependencies(); 93 } 94 return self::$no_imagick_pdf_readwrite; 95 } 96 97 public function __construct(string $source_filepath, DokuWiki_Syntax_Plugin $plugin, bool $ismediapath = true) { 98 99 if ($ismediapath) { 100 $this->source_mediapath = $source_filepath; 101 $this->source_filepath = mediaFN($source_filepath); 102 } else { 103 $this->source_mediapath = false; 104 $this->source_filepath = $source_filepath; 105 } 106 107 $this->max_dimension = $plugin->getConf('thumb_max_dimension'); 108 109 // Now attach the correct thumb_engine for the file type of the source file 110 //TODO: check for extension "fileinfo", then check for MIME type: if (mime_content_type($filepath_local_file) == "application/pdf") { 111 $sourceFileSuffix = getFileSuffix($this->source_filepath); 112 if ($sourceFileSuffix == "pdf") { 113 // file suffix is pdf, so assume it's a PDF file 114 if (self::supportsPDF()) { 115 $this->thumb_engine = new thumb_pdf_engine($this); 116 } else { 117 118 $hint = self::$dependency_problem ? " Hint: '".self::$dependency_problem."'\n" : ""; 119 120 if (self::ghostScriptFailed()) { 121 dbg("plugin mediathumbnails: PDF files are supported, but not on this system.\nMost likely, ImageMagick and its PHP extension imagick are installed properly, but GhostScript is not.\n".$hint."Please refer to the plugin documentation for a description of the dependencies. ".self::$dependency_problem); 122 } else if(self::imagickPDFpolicyFailed()) { 123 dbg("plugin mediathumbnails: PDF files are supported, but not on this system.\nMost likely, ImageMagick is configured so that PDF conversion is not allowed due to security policies.\n".$hint."Please refer to the plugin documentation for a description of the dependencies. ".self::$dependency_problem); 124 } else { 125 dbg("plugin mediathumbnails: PDF files are supported, but not on this system.\nMost likely, ImageMagick or its PHP extension imagick are not installed properly.\n".$hint."Please refer to the plugin documentation for a description of the dependencies."); 126 } 127 } 128 } else if (self::supportsImages() && in_array(strtoupper($sourceFileSuffix), self::$formats)) { 129 // file suffix is in support list of ImageMagick 130 $this->thumb_engine = new thumb_img_engine($this); 131 } else if (!self::supportsImages()) { 132 dbg("plugin mediathumbnails: Image files are supported, but not on this system.\nPlease refer to the plugin documentation for a description of the dependencies."); 133 } else { 134 // last resort: check if the source file is a ZIP file and look for thumbnails, therein 135 $this->thumb_engine = new thumb_zip_engine($this,$plugin->getConf('thumb_paths')); 136 } 137 } 138 139 public function getMaxDimension(): int { 140 return $this->max_dimension; 141 } 142 143 public function create_if_missing(): bool { 144 if (!$this->thumb_engine) { 145 return false; 146 } 147 148 return $this->thumb_engine->act(); 149 } 150 151 public function creation_has_failed(): bool { 152 if (!$this->thumb_engine) { 153 return true; 154 } 155 156 return $this->thumb_engine->has_failed(); 157 } 158 159 public function getSourceFilepath() { 160 return $this->source_filepath; 161 } 162 163 public function getSourceFileExists(): bool { 164 return file_exists($this->source_filepath); 165 } 166 167 protected function getFilename(): string { 168 169 return basename($this->source_filepath) . ".thumb".$this->max_dimension.".".$this->thumb_engine->getFileSuffix(); 170 } 171 172 public function getFilepath(): string { 173 return dirname($this->source_filepath) . DIRECTORY_SEPARATOR . $this->getFilename(); 174 } 175 176 public function getMediapath(): string|null { 177 if ($this->source_mediapath !== false) { 178 return substr($this->source_mediapath,0,strrpos($this->source_mediapath,':')) . ":" . $this->getFilename(); 179 } else { 180 return null; 181 } 182 } 183 184 public function getTimestamp(): bool|int { 185 return file_exists($this->getFilepath()) ? filemtime($this->getFilepath()) : false; 186 } 187}