44 lines
1.4 KiB
PHP
44 lines
1.4 KiB
PHP
<?php
|
|
// Serves a cached course thumbnail — a frame captured from the course's first
|
|
// video at THUMBNAIL_SEEK_PERCENT, generated by the scanner (see
|
|
// generateThumbnails() in includes/functions.php). Looked up by folder ID
|
|
// only, mirroring stream.php's containment check; 404s (no thumbnail yet, or
|
|
// the id isn't a course) are expected and handled by the client falling back
|
|
// to its colour-block placeholder.
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
require_once __DIR__ . '/includes/functions.php';
|
|
|
|
$userId = currentUserId();
|
|
if ($userId === null) {
|
|
http_response_code(403);
|
|
exit('Forbidden');
|
|
}
|
|
|
|
$courseId = (int)($_GET['course_id'] ?? 0);
|
|
$dir = realpath(THUMBNAILS_DIR);
|
|
$file = ($courseId > 0 && $dir !== false)
|
|
? realpath($dir . '/' . $courseId . '.jpg')
|
|
: false;
|
|
|
|
if ($dir === false || $file === false || !str_starts_with($file, $dir . DIRECTORY_SEPARATOR)
|
|
|| !is_file($file)) {
|
|
http_response_code(404);
|
|
exit('No thumbnail');
|
|
}
|
|
|
|
$mtime = filemtime($file);
|
|
$etag = '"' . md5($courseId . '-' . $mtime) . '"';
|
|
|
|
header('Cache-Control: private, max-age=86400');
|
|
header('ETag: ' . $etag);
|
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
|
|
|
|
if (($_SERVER['HTTP_IF_NONE_MATCH'] ?? null) === $etag) {
|
|
http_response_code(304);
|
|
exit;
|
|
}
|
|
|
|
header('Content-Type: image/jpeg');
|
|
header('Content-Length: ' . filesize($file));
|
|
readfile($file);
|