id = $attId; if (!$db->fetch($attachment)) { http_response_code(404); msg_error(__("No attachment exists with this id")); exit; } $isImage = str_starts_with($attachment->mimeType, "image/"); $isVideo = str_starts_with($attachment->mimeType, "video/"); if (!$isImage && !$isVideo) { http_response_code(400); msg_error(__("Attachment is neither an image nor a video")); exit; } $contentHash = hash("sha256", $attachment->contents); $cacheId = bin2hex($attachment->id); $cacheDir = sys_get_temp_dir() . "/mystic/forum/0/cache/thumbs/" . substr($cacheId, 0, 2) . "/" . substr($cacheId, 0, 8) . "/"; if (!is_dir($cacheDir)) mkdir($cacheDir, recursive: true); $cacheFileData = $cacheDir . $cacheId . ".data"; $cacheFileInfo = $cacheDir . $cacheId . ".info"; if (is_file($cacheFileData) && is_file($cacheFileInfo)) { $info = json_decode(file_get_contents($cacheFileInfo)); if ($info->contentHash === $contentHash) { header("Content-Type: image/jpeg"); header("Cache-Control: max-age=86400"); //header("X-Debug-Content: $cacheFileData"); readfile($cacheFileData); exit; } } if ($isVideo) { $suffix = (microtime(true) * 1000) . "-" . random_int(0, 99999); $tempVid = sys_get_temp_dir() . "/video_" . $suffix; file_put_contents($tempVid, $attachment->contents); $tempImg = sys_get_temp_dir() . "/image_" . $suffix . ".jpg"; try { $ffprobe = FFProbe::create(); /** @var string $duration */ $duration = $ffprobe ->format($tempVid) ->get("duration", "0"); $screenshotFramePoint = TimeCode::fromSeconds(floatval($duration) / 2.0); $ffmpeg = FFMpeg::create(); $video = $ffmpeg->open($tempVid); $screenshot = $video ->frame($screenshotFramePoint) ->save($tempImg); $im = imagecreatefromjpeg($tempImg); } finally { if (is_file($tempVid)) unlink($tempVid); if (is_file($tempImg)) unlink($tempImg); } } elseif ($isImage) { $im = imagecreatefromstring($attachment->contents); } $w = imagesx($im); $h = imagesy($im); $r = $w / floatval($h); if ($w > $h) { $nw = THUMB_MAX_DIM; $nh = floor($nw / $r); } else { $nh = THUMB_MAX_DIM; $nw = floor($r * $nh); } $thumb = imagecreatetruecolor($nw, $nh); imagecopyresampled($thumb, $im, 0, 0, 0, 0, $nw, $nh, $w, $h); imagedestroy($im); header("Content-Type: image/jpeg"); header("Cache-Control: max-age=86400"); imagejpeg($thumb, $cacheFileData, 40); imagedestroy($thumb); file_put_contents($cacheFileInfo, json_encode([ "format" => 1, "contentHash" => $contentHash, "created" => time(), ], JSON_UNESCAPED_SLASHES)); readfile($cacheFileData);