xref: /plugin/mediathumbnails/thumbnail.php (revision e19533e13ade8665caee6886acf0de2dbdc8883d)
147d2d32aSternite<?php
247d2d32aSternite/**
347d2d32aSternite * DokuWiki Plugin mediathumbnails (thumbnail class)
447d2d32aSternite *
547d2d32aSternite * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
647d2d32aSternite * @author  Thomas Schäfer <thomas.schaefer@itschert.net>
747d2d32aSternite */
847d2d32aSternite
947d2d32aSterniterequire('thumb_engines.php');
1047d2d32aSternite
1147d2d32aSternitefunction getFileSuffix(string $file) {
1247d2d32aSternite	return substr(strrchr($file,'.'),1);
1347d2d32aSternite}
1447d2d32aSternite
1547d2d32aSterniteclass thumbnail {
1647d2d32aSternite
17*e19533e1Sternite	private string $source_filepath;
18*e19533e1Sternite	private string $source_mediapath;
1947d2d32aSternite	private ?thumb_engine $thumb_engine = null;
2047d2d32aSternite	private int $max_dimension;
2147d2d32aSternite
2247d2d32aSternite	private static $formats;
2347d2d32aSternite	private static ?bool $pdf_support = null;
2447d2d32aSternite	private static ?bool $image_support = null;
2547d2d32aSternite	private static ?bool $no_ghostscript_support = null;
265fa23922Sternite	private static ?bool $no_imagick_pdf_readwrite = null;
27a99f1509Sternite	private static ?string $dependency_problem = null;
2847d2d32aSternite
2947d2d32aSternite	private static function testDependencies() {
30086d90eeSternite
3147d2d32aSternite		self::$image_support = false;
3247d2d32aSternite		self::$pdf_support = false;
3347d2d32aSternite		self::$no_ghostscript_support = false;
345fa23922Sternite		self::$no_imagick_pdf_readwrite = false;
35a99f1509Sternite		self::$dependency_problem = null;
36086d90eeSternite
3747d2d32aSternite		if (class_exists ("Imagick")) {
3847d2d32aSternite			// determine file formats supported by ImageMagick
3947d2d32aSternite			self::$formats = \Imagick::queryformats();
4047d2d32aSternite
4147d2d32aSternite			if (count(self::$formats) > 0) {
4247d2d32aSternite				self::$image_support = true;
4347d2d32aSternite				if (in_array("PDF", self::$formats)) {
4447d2d32aSternite					// Check if GhostScript will answer!
4547d2d32aSternite					try {
4647d2d32aSternite						// blank.pdf is an empty reference PDF file to test if GhostScript will react upon loading the file into ImageMagick
4747d2d32aSternite						$im = new imagick(realpath("lib/plugins/mediathumbnails/blank.pdf")."[0]");
4847d2d32aSternite						$im->clear();
4947d2d32aSternite						$im->destroy();
5047d2d32aSternite						self::$pdf_support = true;
5147d2d32aSternite					} catch (ImagickException $e) {
5247d2d32aSternite						if (strpos($e,"PDFDelegateFailed") !== false) {
5347d2d32aSternite							self::$no_ghostscript_support = true;
5447d2d32aSternite						}
555fa23922Sternite						if (strpos($e,"security policy") !== false) {
565fa23922Sternite							self::$no_imagick_pdf_readwrite = true;
575fa23922Sternite						}
5847d2d32aSternite						self::$pdf_support = false;
59a99f1509Sternite						self::$dependency_problem = "Catched ImagickException: ".$e->getMessage();
60a99f1509Sternite					}
61a99f1509Sternite				} else {
62a99f1509Sternite					self::$dependency_problem = "Imagick reports it does not support PDF files.";
63a99f1509Sternite				}
64a99f1509Sternite			} else {
65a99f1509Sternite				self::$dependency_problem = "Imagick reports it doesn't support any output formats.";
6647d2d32aSternite			}
6747d2d32aSternite
68a99f1509Sternite		} else {
69a99f1509Sternite			self::$dependency_problem = "Imagick class not found: ImageMagick PHP extension is not installed.";
7047d2d32aSternite		}
7147d2d32aSternite	}
7247d2d32aSternite	public static function supportsPDF() {
7347d2d32aSternite		if (self::$pdf_support === null) {
7447d2d32aSternite			self::testDependencies();
7547d2d32aSternite		}
7647d2d32aSternite		return self::$pdf_support;
7747d2d32aSternite	}
7847d2d32aSternite	public static function supportsImages() {
7947d2d32aSternite		if (self::$image_support === null) {
8047d2d32aSternite			self::testDependencies();
8147d2d32aSternite		}
8247d2d32aSternite		return self::$image_support;
8347d2d32aSternite	}
8447d2d32aSternite	public static function ghostScriptFailed() {
8547d2d32aSternite		if (self::$no_ghostscript_support === null) {
8647d2d32aSternite			self::testDependencies();
8747d2d32aSternite		}
8847d2d32aSternite		return self::$no_ghostscript_support;
8947d2d32aSternite	}
905fa23922Sternite	public static function imagickPDFpolicyFailed() {
915fa23922Sternite		if (self::$no_imagick_pdf_readwrite === null) {
925fa23922Sternite			self::testDependencies();
935fa23922Sternite		}
945fa23922Sternite		return self::$no_imagick_pdf_readwrite;
955fa23922Sternite	}
9647d2d32aSternite
9747d2d32aSternite	public function __construct(string $source_filepath, DokuWiki_Syntax_Plugin $plugin, bool $ismediapath = true) {
9847d2d32aSternite
9947d2d32aSternite		if ($ismediapath) {
10047d2d32aSternite			$this->source_mediapath = $source_filepath;
10147d2d32aSternite			$this->source_filepath = mediaFN($source_filepath);
10247d2d32aSternite		} else {
10347d2d32aSternite			$this->source_mediapath = false;
10447d2d32aSternite			$this->source_filepath = $source_filepath;
10547d2d32aSternite		}
10647d2d32aSternite
10747d2d32aSternite		$this->max_dimension = $plugin->getConf('thumb_max_dimension');
10847d2d32aSternite
10947d2d32aSternite		// Now attach the correct thumb_engine for the file type of the source file
11047d2d32aSternite		//TODO: check for extension "fileinfo", then check for MIME type: if (mime_content_type($filepath_local_file) == "application/pdf") {
11147d2d32aSternite		$sourceFileSuffix = getFileSuffix($this->source_filepath);
11247d2d32aSternite		if ($sourceFileSuffix == "pdf") {
11347d2d32aSternite			// file suffix is pdf, so assume it's a PDF file
11447d2d32aSternite			if (self::supportsPDF()) {
11547d2d32aSternite				$this->thumb_engine = new thumb_pdf_engine($this);
11647d2d32aSternite			} else {
117a99f1509Sternite
118a99f1509Sternite				$hint = self::$dependency_problem ? "  Hint: '".self::$dependency_problem."'\n" : "";
119a99f1509Sternite
12047d2d32aSternite				if (self::ghostScriptFailed()) {
121a99f1509Sternite					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);
1225fa23922Sternite				} else if(self::imagickPDFpolicyFailed()) {
123a99f1509Sternite					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);
12447d2d32aSternite				} else {
125a99f1509Sternite					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.");
12647d2d32aSternite				}
12747d2d32aSternite			}
12847d2d32aSternite		} else if (self::supportsImages() && in_array(strtoupper($sourceFileSuffix), self::$formats)) {
12947d2d32aSternite			// file suffix is in support list of ImageMagick
13047d2d32aSternite			$this->thumb_engine = new thumb_img_engine($this);
13147d2d32aSternite		} else if (!self::supportsImages()) {
13247d2d32aSternite			dbg("plugin mediathumbnails: Image files are supported, but not on this system.\nPlease refer to the plugin documentation for a description of the dependencies.");
13347d2d32aSternite		} else {
13447d2d32aSternite			// last resort: check if the source file is a ZIP file and look for thumbnails, therein
13547d2d32aSternite			$this->thumb_engine = new thumb_zip_engine($this,$plugin->getConf('thumb_paths'));
13647d2d32aSternite		}
13747d2d32aSternite	}
13847d2d32aSternite
139*e19533e1Sternite	public function getMaxDimension(): int {
14047d2d32aSternite		return $this->max_dimension;
14147d2d32aSternite	}
14247d2d32aSternite
143*e19533e1Sternite	public function create_if_missing(): bool {
14447d2d32aSternite		if (!$this->thumb_engine) {
14547d2d32aSternite			return false;
14647d2d32aSternite		}
14747d2d32aSternite
14847d2d32aSternite		return $this->thumb_engine->act();
14947d2d32aSternite	}
15047d2d32aSternite
151*e19533e1Sternite	public function creation_has_failed(): bool {
152*e19533e1Sternite		if (!$this->thumb_engine) {
153*e19533e1Sternite			return true;
154*e19533e1Sternite		}
155*e19533e1Sternite
156*e19533e1Sternite		return $this->thumb_engine->has_failed();
157*e19533e1Sternite	}
158*e19533e1Sternite
15947d2d32aSternite	public function getSourceFilepath() {
16047d2d32aSternite		return $this->source_filepath;
16147d2d32aSternite	}
16247d2d32aSternite
163*e19533e1Sternite	public function getSourceFileExists(): bool {
164a99f1509Sternite		return file_exists($this->source_filepath);
165a99f1509Sternite	}
166a99f1509Sternite
167*e19533e1Sternite	protected function getFilename(): string {
16847d2d32aSternite
16947d2d32aSternite		return basename($this->source_filepath) . ".thumb".$this->max_dimension.".".$this->thumb_engine->getFileSuffix();
17047d2d32aSternite	}
17147d2d32aSternite
172*e19533e1Sternite	public function getFilepath(): string {
17347d2d32aSternite		return dirname($this->source_filepath) . DIRECTORY_SEPARATOR . $this->getFilename();
17447d2d32aSternite	}
17547d2d32aSternite
176*e19533e1Sternite	public function getMediapath(): string|null {
17747d2d32aSternite		if ($this->source_mediapath !== false) {
17847d2d32aSternite			return substr($this->source_mediapath,0,strrpos($this->source_mediapath,':')) . ":" . $this->getFilename();
17947d2d32aSternite		} else {
180*e19533e1Sternite			return null;
18147d2d32aSternite		}
18247d2d32aSternite	}
18347d2d32aSternite
184*e19533e1Sternite	public function getTimestamp(): bool|int {
18547d2d32aSternite		return file_exists($this->getFilepath()) ? filemtime($this->getFilepath()) : false;
18647d2d32aSternite	}
18747d2d32aSternite}