api = new BookApi(); } public function serve(string $size, string $file) { // parse size + id if (! preg_match('/^(\d{2,4})x(\d{2,4})$/', $size, $m)) { return $this->response->setStatusCode(400); } [, $w, $h] = $m; $id = preg_replace('/\.jpg$/', '', $file); if (! $id || ! preg_match('/^[a-zA-Z0-9._-]+$/', $id)) { return $this->response->setStatusCode(400); } $book = $this->api->book($id); if (! $book || ! $book['coverEndpoint']) { return $this->response->setStatusCode(404); } // ensure the original is cached locally (fetch on demand) $dir = WRITEPATH . 'cache/covers'; $orig = $dir . '/' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $id) . '.jpg'; if (! is_file($orig)) { $tmp = $orig . '.tmp' . getmypid(); if ($this->api->fetchToFile($book['coverEndpoint'], $tmp)) { if (! is_dir($dir)) { mkdir($dir, 0775, true); } rename($tmp, $orig); } else { @unlink($tmp); } } if (! is_file($orig)) { return $this->response->setStatusCode(404); } $thumb = CoverArt::thumb($id, $orig, $book, (int) $w, (int) $h); if (! $thumb || ! is_file($thumb)) { return $this->response->setStatusCode(404); } header('Content-Type: image/jpeg'); header('Content-Length: ' . (string) filesize($thumb)); header('Cache-Control: public, max-age=604800'); readfile($thumb); exit; } }