Sách Giáo Khoa Việt Nam - sachgiaokhoa.org
CodeIgniter 4 website:
- Catalog 999 SGK (lớp 1-12) từ API, lọc theo lớp/môn/NXB, tìm kiếm
- Trang chủ grouped browse (bậc học -> lớp -> môn, ưu tiên môn quan trọng)
- Chi tiết sách: metadata đầy đủ, cover nghệ thuật /thumb/{W}x{H}/
- Đọc online qua gate captcha + countdown, PDF viewer pdf.js
- Download: captcha + token một lần + auto cache-bust version
- Tự đồng bộ catalog/cover khi API thay đổi (refresh:catalog)
- Legal: DMCA, miễn trừ trách nhiệm, điều khoản, bảo mật, liên hệ
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Libraries\BookApi;
|
||||
|
||||
/**
|
||||
* Proxies cover + inline PDF streaming from the upstream API.
|
||||
*/
|
||||
class Media extends BaseController
|
||||
{
|
||||
private BookApi $api;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->api = new BookApi();
|
||||
}
|
||||
|
||||
public function cover(string $id)
|
||||
{
|
||||
$book = $this->api->book($id);
|
||||
if (! $book || ! $book['coverEndpoint']) {
|
||||
$this->response->setStatusCode(404);
|
||||
return;
|
||||
}
|
||||
|
||||
// serve from local disk cache once fetched
|
||||
$dir = WRITEPATH . 'cache/covers';
|
||||
$file = $dir . '/' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $id) . '.jpg';
|
||||
if (! is_file($file)) {
|
||||
$tmp = $file . '.tmp' . getmypid();
|
||||
$ok = $this->api->fetchToFile($book['coverEndpoint'], $tmp);
|
||||
if ($ok) {
|
||||
if (! is_dir($dir)) {
|
||||
mkdir($dir, 0775, true);
|
||||
}
|
||||
rename($tmp, $file);
|
||||
} else {
|
||||
@unlink($tmp);
|
||||
}
|
||||
}
|
||||
if (is_file($file)) {
|
||||
header('Content-Type: image/jpeg');
|
||||
header('Content-Length: ' . (string) filesize($file));
|
||||
header('Cache-Control: public, max-age=604800');
|
||||
readfile($file);
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->response->setHeader('Cache-Control', 'public, max-age=86400');
|
||||
$this->api->stream($book['coverEndpoint']);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function pdf(string $id)
|
||||
{
|
||||
// the PDF stream requires an access grant (captcha-verified session)
|
||||
if (! \App\Libraries\PdfAccess::has($id)) {
|
||||
return $this->response->setStatusCode(403)->setJSON([
|
||||
'error' => 'Truy cập bị từ chối. Vui lòng xác nhận captcha tại trang sách để xem nội dung.',
|
||||
]);
|
||||
}
|
||||
|
||||
$book = $this->api->book($id);
|
||||
if (! $book || ! $book['pdfEndpoint']) {
|
||||
$this->response->setStatusCode(404);
|
||||
return;
|
||||
}
|
||||
// inline disposition: viewer only, not a download
|
||||
header('Content-Disposition: inline');
|
||||
header('X-Robots-Tag: noindex');
|
||||
$this->api->stream($book['pdfEndpoint']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user