knplabs/knp-snappy
Snappy is a PHP wrapper for wkhtmltopdf/wkhtmltoimage to generate PDFs, thumbnails, and snapshots from URLs or HTML. Supports Linux/macOS/Windows, configurable binaries and options, and integrates with Symfony and Laravel via community bundles.
knp-snappy excels at dynamic PDF/thumbnail generation from URLs or HTML, aligning perfectly with Laravel use cases like:
generateFromHtml()).wkhtmltopdf/wkhtmltoimage, reducing boilerplate for complex CLI interactions. Ideal for Laravel’s service-layer integration.setOption(), enabling fine-grained control over output.barryvdh/laravel-snappy (a Laravel wrapper) exists, simplifying integration with Laravel’s service container, caching, and queue systems.wkhtmltopdf (v0.12.x) must be installed system-wide or via Composer (e.g., h4cc/wkhtmltopdf-amd64).wkhtmltopdf binary, which may require environment-specific configuration (e.g., Docker, CI/CD).--enable-local-file-access (default: disabled) can expose the system to RCE vulnerabilities if untrusted HTML/JS is processed. Mitigation: Use sandboxing (AppArmor/SELinux) or alternatives like Puppeteer for high-risk workflows.wkhtmltopdf itself has historical CVEs (e.g., GHSA-92rv-4j2h-8mjj). Risk reduced by pinning to v0.12.x (last maintained version).wkhtmltopdf spawns a subprocess per request, which can bloat memory/CPU under high load. Mitigation: Use queues (Laravel’s queue:work) or caching (store generated PDFs temporarily).max_execution_time. Solution: Increase set_time_limit() or use asynchronous processing.wkhtmltopdf is accessible.wkhtmltopdf options (e.g., --encoding UTF-8).wkhtmltopdf be installed system-wide, via Composer, or in a Docker container? How will binary paths be managed across environments?config/snappy.php with environment-specific paths:
'binary' => env('WKHTMLTOPDF_BINARY', base_path('vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf')),
--enable-local-file-access be mitigated (e.g., sandboxing, input sanitization)?wkhtmltopdf fails?Knp\Snappy\Pdf as a singleton in AppServiceProvider:
$this->app->singleton(Pdf::class, function ($app) {
return new Pdf(config('snappy.binary'));
});
wkhtmltopdf path, default options, and cache settings in config/snappy.php:
return [
'binary' => env('WKHTMLTOPDF_BINARY'),
'options' => [
'disable-smart-shrinking' => true,
'encoding' => 'UTF-8',
],
'cache_dir' => storage_path('app/snappy_cache'),
];
use Knp\Snappy\Pdf;
use Illuminate\Support\Facades\Queue;
Queue::push(function () {
$pdf = app(Pdf::class);
$pdf->generateFromHtml('<h1>Hello</h1>', storage_path('app/report.pdf'));
});
barryvdh/laravel-snappy, leverage its Symfony Process integration, cached responses, and Blade directives:
// In a controller
return PDF::loadView('invoice', ['user' => $user])
->setOptions(['margin-top' => '20mm'])
->download('invoice.pdf');
Phase 1: Proof of Concept (PoC)
knplabs/knp-snappy and h4cc/wkhtmltopdf-amd64 via Composer.tinker):
$pdf = new \Knp\Snappy\Pdf('/usr/local/bin/wkhtmltopdf');
file_put_contents('test.pdf', $pdf->getOutput('https://example.com'));
Phase 2: Laravel Integration
snappy.php config file:
php artisan vendor:publish --provider="Knp\Snappy\SnappyServiceProvider" --tag="config"
AppServiceProvider (or use the bundle’s auto-registration).// app/Helpers/SnappyHelper.php
class SnappyHelper {
public static function generateFromView(string $view, array $data, string $filename) {
$pdf = app(Pdf::class);
$html = view($view, $data)->render();
return $pdf->generateFromHtml($html, $filename);
}
}
Phase 3: Production Hardening
.env to override binary paths (e.g., Docker vs. bare metal).file_put_contents + Cache::remember).Monolog integration).symfony/process: Used internally for subprocess management. Compatible with Laravel’s Process component.psr/log: Supports Laravel’s logging system out of the box.Snappy class name).wkhtmltopdf system-wide or via Composer (preferred for consistency):
composer require h4cc/wkhtmltopdf-amd64
/generate-pdf).How can I help you explore Laravel packages today?