xref: /plugin/mediathumbnails/thumbnail.php (revision a99f150968d94c1d45e20e5e1fcfb35c280afe95)
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 $source_filepath;
18	private $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() {
140		return $this->max_dimension;
141	}
142
143	public function create() {
144		if (!$this->thumb_engine) {
145			return false;
146		}
147
148		return $this->thumb_engine->act();
149	}
150
151	public function getSourceFilepath() {
152		return $this->source_filepath;
153	}
154
155	public function getSourceFileExists() {
156		return file_exists($this->source_filepath);
157	}
158
159	protected function getFilename() {
160
161		return basename($this->source_filepath) . ".thumb".$this->max_dimension.".".$this->thumb_engine->getFileSuffix();
162	}
163
164	public function getFilepath() {
165		return dirname($this->source_filepath) . DIRECTORY_SEPARATOR . $this->getFilename();
166	}
167
168	public function getMediapath() {
169		if ($this->source_mediapath !== false) {
170			return substr($this->source_mediapath,0,strrpos($this->source_mediapath,':')) . ":" . $this->getFilename();
171		} else {
172			return false;
173		}
174	}
175
176	public function getTimestamp() {
177		return file_exists($this->getFilepath()) ? filemtime($this->getFilepath()) : false;
178	}
179}