eckinox/php-puppeteer
Generate PDFs in PHP using Puppeteer. Render from a URL or HTML string with a simple API and minimal dependencies. Includes setup guidance for installing Puppeteer/Chromium and basic examples for returning PDF output.
Install Dependencies:
sudo npm install --global --unsafe-perm puppeteer
puppeteer --version
Composer Install:
composer require eckinox/php-puppeteer
First Use Case: Generate a PDF from a URL (e.g., a Laravel route for invoices):
use Eckinox\PhpPuppeteer\Browser;
$browser = new Browser();
$pdfContent = $browser->pdf([
'url' => 'https://example.com/invoice/123',
'pdf' => ['format' => 'A4', 'margin' => '1cm']
]);
return response($pdfContent, 200)->header('Content-Type', 'application/pdf');
Key Files to Review:
vendor/eckinox/php-puppeteer/src/Browser.php (core class).examples/ in the repo for advanced use cases (e.g., cookies, page breaks).// app/Services/PdfService.php
class PdfService {
public function generateInvoice($userData) {
$html = view('invoices.pdf', compact('userData'))->render();
$browser = new Browser();
return $browser->pdf([
'html' => $html,
'pdf' => ['format' => 'A4', 'margin' => '1cm'],
'viewport' => ['width' => 1280, 'height' => 800]
]);
}
}
storage/app/pdf/ using Laravel’s filesystem.// app/Jobs/GeneratePdfJob.php
class GeneratePdfJob implements ShouldQueue {
use Dispatchable, InteractsWithQueue;
public function handle() {
$pdf = app(PdfService::class)->generateInvoice($this->userData);
Storage::put("pdfs/{$this->filename}.pdf", $pdf);
}
}
GeneratePdfJob::dispatch($userData, 'invoice_123.pdf')->onQueue('pdfs');
// app/Providers/AppServiceProvider.php
public function boot() {
$this->app->singleton(Browser::class, function () {
return new Browser(['cacheDir' => storage_path('chromium-cache')]);
});
}
$browser = app(Browser::class);
$pdf = $browser->pdf([...]);
$browser = new Browser();
$page = $browser->newPage();
$page->setCookie([
'name' => 'session',
'value' => $user->apiToken,
'domain' => 'example.com'
]);
$pdf = $page->pdf(['url' => 'https://example.com/dashboard']);
Laravel Views:
Use Blade templates for HTML, then pass to php-puppeteer:
$html = view('report', ['data' => $reportData])->render();
$pdf = $browser->pdf(['html' => $html]);
API Endpoints: Expose PDF generation via Laravel routes:
Route::post('/pdf/generate', function (Request $request) {
$pdf = app(PdfService::class)->generateFromRequest($request);
return response($pdf)->header('Content-Type', 'application/pdf');
});
Testing:
Mock the Browser class in unit tests:
$mockBrowser = Mockery::mock(Browser::class);
$mockBrowser->shouldReceive('pdf')->andReturn('mock-pdf-content');
$this->app->instance(Browser::class, $mockBrowser);
Chromium Resource Usage:
Browser instance spawns a new Chromium process (~500MB RAM).Headless Environment Failures:
xvfb (Linux) or Docker with --no-sandbox:
docker run --rm -e PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true -e PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser puppeteer/chromium
Font Loading Issues:
@font-face in CSS or preload fonts:
$browser->pdf([
'html' => '<link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet">'.$html,
'launchArgs' => ['--no-sandbox']
]);
URL/HTML Sanitization:
javascript: URLs) can exploit Puppeteer.php-puppeteer:
use Symfony\Component\DomCrawler\Crawler;
$cleanHtml = (new Crawler($html))->html();
Deprecated PHP 5 Support:
composer.json:
"config": {
"platform": {
"php": "7.4"
}
}
Log Chromium Output:
Add --log-level=debug to launchArgs to debug rendering issues:
$browser = new Browser(['launchArgs' => ['--log-level=debug']]);
Inspect Pages:
Use Puppeteer’s page.screenshot() to debug layout issues:
$page = $browser->newPage();
$page->goto('https://example.com');
$page->screenshot(['path' => 'debug.png']);
Timeout Errors:
Increase waitUntil in goto options for slow-loading pages:
$browser->pdf([
'url' => 'https://slow-site.com',
'goto' => ['waitUntil' => 'networkidle2']
]);
Custom Puppeteer Options:
Extend the Browser class to support additional Puppeteer features:
class ExtendedBrowser extends Browser {
public function screenshot(array $options = []) {
$page = $this->newPage();
return $page->screenshot($options);
}
}
Laravel Service Provider:
Bind the Browser class to the container with custom configs:
// app/Providers/PuppeteerServiceProvider.php
public function register() {
$this->app->bind(Browser::class, function () {
return new Browser([
'cacheDir' => storage_path('chromium-cache'),
'launchArgs' => ['--no-sandbox', '--disable-setuid-sandbox']
]);
});
}
Queue Monitoring: Track failed PDF jobs in Laravel Horizon:
// app/Jobs/GeneratePdfJob.php
public function failed(Throwable $exception) {
Log::error("PDF generation failed: " . $exception->getMessage());
}
cacheDir:
Set a persistent directory to avoid re-downloading Chromium:
$browser = new Browser(['cacheDir' => storage_path('chromium-cache')]);
launchArgs:
Common flags for production:
['launchArgs' => [
'--no-sandbox',
'--disable-setuid-sandbox
How can I help you explore Laravel packages today?