sahifa / laravel
Laravel package for Sahifa: Arabic-ready HTML to PDF and screenshots, rendered in Saudi Arabia. Render Blade views to PDF without dompdf's Arabic problems.
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.5
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- illuminate/view: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.0|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Render Blade views to PDF with Arabic text that actually works: joined letters, correct word order, mixed Arabic and English, with Arabic fonts ready. Rendered by Chromium on Sahifa's servers in Saudi Arabia, so there is no browser to install and nothing to configure in your Laravel app.
If you came here because dompdf shows Arabic as ???? or as disconnected letters, this is the fix: dompdf does not shape Arabic, a browser engine does.
use Sahifa\Laravel\Facades\Sahifa; return Sahifa::pdfFromView('invoices.show', ['invoice' => $invoice])->download('invoice.pdf');
Installation
composer require sahifa/laravel
Add your key to .env (get a free one at sahifa.dev: 100 renders a month, no card needed):
SAHIFA_API_KEY=sk_live_...
The service provider and the Sahifa facade are registered automatically. To change the defaults, publish the config:
php artisan vendor:publish --tag=sahifa-config
Requirements: PHP 8.2+, Laravel 12 or 13.
Usage
PDF from a Blade view
$pdf = Sahifa::pdfFromView('invoices.show', ['invoice' => $invoice], [ 'format' => 'A4', 'margin' => '15mm', 'footer' => ['source' => '<div style="width:100%;text-align:center;font-size:9px">صفحة {{page}} من {{total}}</div>'], ]); return $pdf->download("invoice-{$invoice->number}.pdf"); // or ->inline() $pdf->store("invoices/{$invoice->number}.pdf", 's3'); // any filesystem disk $pdf->save(storage_path('app/invoice.pdf')); // local path $bytes = $pdf->content(); // raw bytes, e.g. for a Mailable attachment
Inside the page footer and header, {{page}} and {{total}} are replaced with page numbers. In a Blade file write them as @{{page}} so Blade leaves them alone.
PDF from HTML or a URL
Sahifa::pdf('<h1>Hello</h1>'); Sahifa::pdf('https://example.com/report/42', ['landscape' => true]);
All PDF options are passed through: format, landscape, margin, header, footer, css, javascript, delay, wait_for, pages, zoom.
Screenshots
Sahifa::screenshot(['url' => 'https://example.com', 'full_page' => true, 'format' => 'png']) ->store('screens/home.png');
See the screenshot options.
Mail attachments
use Illuminate\Mail\Attachment; public function attachments(): array { $pdf = Sahifa::pdfFromView('invoices.show', ['invoice' => $this->invoice]); return [Attachment::fromData(fn () => $pdf->content(), 'invoice.pdf')->withMime('application/pdf')]; }
An Arabic invoice view
<!doctype html> <html dir="rtl" lang="ar"> <head> <meta charset="utf-8"> <style> body { font-family: 'Noto Naskh Arabic', 'Amiri', serif; } td.num { text-align: end; font-variant-numeric: tabular-nums; } @page { size: A4; margin: 15mm; } </style> </head> <body> <h1>فاتورة ضريبية مبسطة</h1> <p>الرقم الضريبي: <bdi dir="ltr">{{ $seller->vat_number }}</bdi></p> <table> @foreach ($invoice->items as $item) <tr><td>{{ $item->name }}</td><td class="num"><bdi dir="ltr">{{ number_format($item->total, 2) }} SAR</bdi></td></tr> @endforeach </table> </body> </html>
- Put
dir="rtl"on<html>, so tables and layout mirror. - Wrap left-to-right parts (VAT numbers, IBANs, amounts, e-mails) in
<bdi dir="ltr">. Sahifa\Laravel\Sahifa::arabicDocument($fragment)wraps a fragment in a full RTL document with Arabic fonts.
Errors and retries
Failures throw Sahifa\Laravel\Exceptions\SahifaException with ->status, ->errorCode and the API's message. Busy and rate-limit responses (429, 502, 503, 504) and network errors are retried (SAHIFA_RETRIES, default 3), waiting for Retry-After.
use Sahifa\Laravel\Exceptions\SahifaException; try { $pdf = Sahifa::pdfFromView('invoices.show', $data); } catch (SahifaException $e) { if ($e->status === 402) { /* monthly allowance used up */ } report($e); }
Testing your app
The package uses Laravel's HTTP client, so Http::fake() works:
Http::fake(['api.sahifa.dev/*' => Http::response('%PDF-1.7', 200)]);
Why Sahifa
- Arabic done right: Chromium shaping and bidi, Arabic fonts preinstalled.
- In the Kingdom: documents are rendered in Jeddah and not stored. Data residency.
- Nothing to run: no Chrome, no fonts, no queue workers in your containers.
Documentation · Examples in five languages · Pricing · Support: support@sahifa.dev
MIT License. Sahifa is a service of Yimello LLC.