path($pdfStoragePath); if (!file_exists($pdfAbsPath)) { return null; } $tempPrefix = sys_get_temp_dir() . '/terr_thumb_' . uniqid(); $process = new Process([ 'pdftoppm', '-r', '72', '-png', '-l', '1', $pdfAbsPath, $tempPrefix, ]); $process->setTimeout(self::RENDER_TIMEOUT_SECONDS); try { $process->run(); } catch (ProcessTimedOutException) { Log::warning('pdftoppm timed out generating a territory thumbnail.', [ 'pdf' => $pdfStoragePath, 'timeout' => self::RENDER_TIMEOUT_SECONDS, ]); // Clean up whatever partial pages it managed to write. foreach (glob($tempPrefix . '*.png') ?: [] as $partial) { @unlink($partial); } return null; } // pdftoppm may produce -1.png, -01.png or even -001.png depending on page count $generated = null; foreach (['-1.png', '-01.png', '-001.png'] as $suffix) { $candidate = $tempPrefix . $suffix; if (file_exists($candidate)) { $generated = $candidate; break; } } if (!$generated) { return null; } $thumbRelPath = 'territori-thumbnails/' . basename($pdfStoragePath, '.pdf') . '.png'; Storage::disk('public')->put($thumbRelPath, file_get_contents($generated)); unlink($generated); return $thumbRelPath; } /** * Delete an existing thumbnail from the public disk. */ public function delete(string $thumbnailPath): void { if ($thumbnailPath) { Storage::disk('public')->delete($thumbnailPath); } } }