223 lines
		
	
	
		
			No EOL
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			No EOL
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
class Cache {
 | 
						|
	protected static $includeCache = [];
 | 
						|
	protected static $templateCache = [];
 | 
						|
	protected static $resourceCache = [];
 | 
						|
 | 
						|
	public static function getIncludeCache(string $name) {
 | 
						|
		return isset(self::$includeCache[$name]) ? self::$includeCache[$name] : null;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function setIncludeCache(string $name, $data) {
 | 
						|
		self::$includeCache[$name] = $data;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getTemplateFromCache(string $name) {
 | 
						|
		if (isset(self::$templateCache[$name])) {
 | 
						|
			return self::$templateCache[$name];
 | 
						|
		}
 | 
						|
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function setTemplateToCache(string $name, $data) {
 | 
						|
		self::$templateCache[$name] = $data;
 | 
						|
	}
 | 
						|
 | 
						|
	protected static function fillResourceCache() {
 | 
						|
		$db = new Database();
 | 
						|
		$sql = "SELECT * FROM `resources`";
 | 
						|
		$stmt = $db::$handle->prepare($sql);
 | 
						|
		$result = $stmt->execute();
 | 
						|
 | 
						|
		while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
 | 
						|
			self::$resourceCache[$row["name"]] = $row;
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	public static function hasResourceCache(string $name) {
 | 
						|
		if (count(self::$resourceCache) == 0) {
 | 
						|
			self::fillResourceCache();
 | 
						|
		}
 | 
						|
 | 
						|
		return isset(self::$resourceCache[$name]);
 | 
						|
	}
 | 
						|
 | 
						|
	public static function setResourceCache(string $name, $data) {
 | 
						|
		self::$resourceCache[$name] = $data;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getResourceCache(string $name) {
 | 
						|
		if (count(self::$resourceCache) == 0) {
 | 
						|
			self::fillResourceCache();
 | 
						|
		}
 | 
						|
 | 
						|
		if (isset(self::$resourceCache[$name])) {
 | 
						|
			return self::$resourceCache[$name];
 | 
						|
		}
 | 
						|
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getResourceCacheByThumbnailUrl(string $url) {
 | 
						|
		if (count(self::$resourceCache) == 0) {
 | 
						|
			self::fillResourceCache();
 | 
						|
		}
 | 
						|
 | 
						|
		foreach (self::$resourceCache as $resource) {
 | 
						|
			if ($resource["url"] == $url) {
 | 
						|
				return $resource;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getCacheFile(string $name, $maxAge = 3600) {
 | 
						|
		$cacheFile = CACHE_DIR . "/" . $name;
 | 
						|
 | 
						|
		if (file_exists($cacheFile) && filemtime($cacheFile) > time() - $maxAge) {
 | 
						|
			Logger::log("Cache hit for " . $name, Logger::IOREAD, "Cache");
 | 
						|
			return COMPRESS_LOCAL_CACHE ? gzuncompress(file_get_contents($cacheFile)) : file_get_contents($cacheFile);
 | 
						|
		}
 | 
						|
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function saveCacheFile(string $name, string $data) {
 | 
						|
		$cacheFile = CACHE_DIR . "/" . $name;
 | 
						|
		file_put_contents($cacheFile, COMPRESS_LOCAL_CACHE ? gzcompress($data,9) : $data );
 | 
						|
		Logger::log("Saved cache file " . $name, Logger::IOWRITE, "Cache");
 | 
						|
	}
 | 
						|
 | 
						|
	public static function publicCacheExists(string $name, bool $skipExtensionCheck = false) {
 | 
						|
		return self::hasResourceCache($name);
 | 
						|
	}
 | 
						|
 | 
						|
	public static function savePublicCacheFile(string $name, string $data, int $cacheLevel = 70, bool $skipExtensionCheck = false) {
 | 
						|
		$originalName = $name;
 | 
						|
 | 
						|
		$name = strtolower($name);
 | 
						|
 | 
						|
		$ext = substr($name, strrpos($name, ".") + 1);
 | 
						|
		if ($skipExtensionCheck || strtolower($ext) == "jpg" || strtolower($ext) == "jpeg" || strtolower($ext) == "png" || strtolower($ext) == "webp"){
 | 
						|
			$size = strlen($data);
 | 
						|
			$img = new Imagick();
 | 
						|
			$img->readImageBlob($data);
 | 
						|
			$img->setImageFormat('webp');
 | 
						|
			$img->setImageCompressionQuality($cacheLevel);
 | 
						|
			$img->stripImage();
 | 
						|
			$data = $img->getImageBlob();
 | 
						|
			$name = str_replace("." . $ext, ".webp", strtolower($name));
 | 
						|
 | 
						|
			$cacheFile = PUBLIC_CACHE_DIR . "/" . $name;
 | 
						|
 | 
						|
			$blurhash = self::generateBlurHash($cacheFile, $img, $skipExtensionCheck);
 | 
						|
			$blurhashImage = self::getBlurHashImage($blurhash);
 | 
						|
 | 
						|
			$resourceSql = "INSERT OR REPLACE INTO `resources` (`name`, `type`, `blurhash`, `url`, `width`, `height`, `hasBeenProcessed`, `modified`, `hasEncodedVersion`, `encodedVersion`)
 | 
						|
							VALUES (:name,:type,:blurhash,:url,:width,:height,1,strftime('%Y-%m-%d %H:%M:%S','now'),1,:blurhashImage)";
 | 
						|
 | 
						|
			$db = new Database();
 | 
						|
			$resourceStmt = $db::$handle->prepare($resourceSql);
 | 
						|
			$resourceStmt->bindValue(":name", $originalName);
 | 
						|
			$resourceStmt->bindValue(":type", "image/webp");
 | 
						|
			$resourceStmt->bindValue(":blurhash", $blurhash);
 | 
						|
			$resourceStmt->bindValue(":url", PUBLIC_CACHE_URL . "/" . $name);
 | 
						|
			$resourceStmt->bindValue(":width", $img->getImageWidth());
 | 
						|
			$resourceStmt->bindValue(":height", $img->getImageHeight());
 | 
						|
			$resourceStmt->bindValue(":blurhashImage", $blurhashImage);
 | 
						|
			$resourceStmt->execute();
 | 
						|
 | 
						|
			// Append to the resource cache
 | 
						|
			self::setResourceCache($originalName, [
 | 
						|
				"name" => $originalName,
 | 
						|
				"type" => "image/webp",
 | 
						|
				"blurhash" => $blurhash,
 | 
						|
				"url" => PUBLIC_CACHE_URL . "/" . $name,
 | 
						|
				"width" => $img->getImageWidth(),
 | 
						|
				"height" => $img->getImageHeight(),
 | 
						|
				"hasBeenProcessed" => 1,
 | 
						|
				"modified" => date("Y-m-d H:i:s")
 | 
						|
			]);
 | 
						|
 | 
						|
			// For now don't transfer file if its generated name exists
 | 
						|
			if (file_exists($cacheFile)) {
 | 
						|
				//Logger::log("Public cache file " . $name . " already exists", Logger::INFO, "Cache");
 | 
						|
				return PUBLIC_CACHE_URL . "/" . $name;
 | 
						|
			}
 | 
						|
 | 
						|
			Logger::log("Compressed image from " . $size . " to " . strlen($data) . " bytes", Logger::METRICS, "Cache");
 | 
						|
		}
 | 
						|
 | 
						|
		$context = stream_context_create([
 | 
						|
			's3' => [
 | 
						|
				'ACL' => 'public-read'
 | 
						|
			]
 | 
						|
		]);
 | 
						|
 | 
						|
		file_put_contents($cacheFile, $data, 0, $context);
 | 
						|
 | 
						|
		Logger::log("Saved public cache file " . $name, Logger::IOWRITE, "Cache");
 | 
						|
 | 
						|
		return PUBLIC_CACHE_URL . "/" . $name;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function generateBlurHash(string $cacheFile, ?IMagick $img = null, bool $skipExtensionCheck = false):?string {
 | 
						|
		$pixels = [];
 | 
						|
 | 
						|
		if ($img === null) {
 | 
						|
			$img = new Imagick();
 | 
						|
			$img->readImage($cacheFile);
 | 
						|
		}
 | 
						|
 | 
						|
		$width = $img->getImageWidth();
 | 
						|
		$height = $img->getImageHeight();
 | 
						|
 | 
						|
		for ($y = 0; $y < $height; $y++) {
 | 
						|
			$row = [];
 | 
						|
			for ($x = 0; $x < $width; $x++) {
 | 
						|
				$pixel = $img->getImagePixelColor($x, $y);
 | 
						|
				$color = $pixel->getColor();
 | 
						|
				$row[] = [$color["r"], $color["g"], $color["b"]];
 | 
						|
			}
 | 
						|
			$pixels[] = $row;
 | 
						|
		}
 | 
						|
 | 
						|
		$hash = \kornrunner\Blurhash\Blurhash::encode($pixels, BLURHASH_X, BLURHASH_Y);
 | 
						|
 | 
						|
		return $hash;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getBlurHashImage($blurhash,$width = 269, $height = 173) {
 | 
						|
 | 
						|
		if (empty($blurhash)) {
 | 
						|
			return "data:image/jpg;base64,/9j/7gAhQWRvYmUAZIAAAAABAwAQAwIDBgAAAAAAAAAAAAAAAP/bAIQAEg4ODhAOFRAQFR4TERMeIxoVFRojIhcXFxcXIhEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAEUExMWGRYbFxcbFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8IAEQgAAwAEAwEiAAIRAQMRAf/EAF4AAQEBAAAAAAAAAAAAAAAAAAAEBwEBAAAAAAAAAAAAAAAAAAAABBABAAAAAAAAAAAAAAAAAAAAABEBAAAAAAAAAAAAAAAAAAAAABIBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQECEQMRAAAAsZ0Kj//aAAgBAgABBQB//9oACAEDAAEFAH//2gAIAQEAAQUAf//aAAgBAgIGPwB//9oACAEDAgY/AH//2gAIAQEBBj8Af//Z";
 | 
						|
		}
 | 
						|
 | 
						|
		$hash = \kornrunner\Blurhash\Blurhash::decode($blurhash, $width, $height);
 | 
						|
 | 
						|
		$img = new Imagick();
 | 
						|
		$img->newImage($width, $height, new ImagickPixel("white"));
 | 
						|
		$img->setImageFormat("webp");
 | 
						|
		$img->setImageCompressionQuality(60);
 | 
						|
 | 
						|
		$pixels = [];
 | 
						|
		for ($y = 0; $y < $height; ++$y) {
 | 
						|
			for ($x = 0; $x < $width; ++$x) {
 | 
						|
				[$r, $g, $b] = $hash[$y][$x];
 | 
						|
				$pixels[] = $r;
 | 
						|
				$pixels[] = $g;
 | 
						|
				$pixels[] = $b;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$img->importImagePixels(0, 0, $width, $height, "RGB", Imagick::PIXEL_CHAR, $pixels);
 | 
						|
 | 
						|
		$img->stripImage();
 | 
						|
		$data = $img->getImageBlob();
 | 
						|
 | 
						|
		return "data:image/webp;base64," . base64_encode($data);
 | 
						|
	}
 | 
						|
} |