Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pdfcrowd Php Laravel Package

radweb/pdfcrowd-php

A PHP wrapper for the Pdfcrowd API that converts HTML, URLs, and files into PDFs. Integrates with Laravel and plain PHP apps, exposing Pdfcrowd conversion options through a simple client for generating downloadable or stored PDF documents.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Laravel-flavoured wrapper around PDFCrowd's PHP client: a service provider, a config file, and (usually) a facade that proxies to a Pdfcrowd\HtmlToPdfClient-style object. It is archived, so treat it as a vendored dependency you own rather than something you can file issues against.

  1. Pull it in (expect it to resolve to a pinned commit since there are no new releases):

    composer require radweb/pdfcrowd-php
    
  2. Publish the config and wire credentials:

    php artisan vendor:publish --provider="Radweb\Pdfcrowd\PdfcrowdServiceProvider"
    

    Then set your PDFCrowd API credentials — the package reads them from config/pdfcrowd.php, which in turn should read from config/services.php or env():

    // config/pdfcrowd.php
    return [
        'username' => env('PDFCROWD_USERNAME'),
        'api_key'  => env('PDFCROWD_API_KEY'),
    ];
    
  3. Look here first, in this order:

    • config/pdfcrowd.php — the only knob most teams touch.
    • src/PdfcrowdServiceProvider.php — see what's bound into the container (usually a singleton client factory).
    • src/Facade/Pdfcrowd.php (or similar) — this tells you the exact call surface. Because the wrapper is thin, the real API surface is PDFCrowd's own client docs at pdfcrowd.com/doc/php/.
  4. First use case — Blade view to PDF. Render a view to a string, hand it to the client, stream it:

    use Radweb\Pdfcrowd\Facades\Pdfcrowd;
    
    Route::get('/invoices/{invoice}/pdf', function (Invoice $invoice) {
        $html = view('invoices.pdf', compact('invoice'))->render();
    
        $pdf = Pdfcrowd::convertHtml($html);
    
        return response($pdf, 200, [
            'Content-Type'        => 'application/pdf',
            'Content-Disposition' => 'inline; filename="invoice-'.$invoice->id.'.pdf"',
        ]);
    });
    

If that returns a PDF, you've validated the whole stack (credentials → client → HTML parse → binary response).

Implementation Patterns

Inject the client, don't reach for the facade in domain code. Facades are convenient in controllers, but anything reused (jobs, mailables, services) should take the client — or a small PdfRenderer interface you own — via constructor injection. That keeps you one refactor away from swapping in the official pdfcrowd/pdfcrowd-php SDK when the archived wrapper inevitably rots.

Centralise a PdfRenderer service. The wrapper's fluent setters (setAuthor, setTitle, setPageSize, setMargin*, setHeaderHtml, setFooterHtml, useHttpAuthentication) mutate the client instance, so a shared singleton can leak state between calls. Build a small factory each time:

final class PdfRenderer
{
    public function render(string $html, array $opts = []): string
    {
        $client = app(PdfcrowdClientFactory::class)->make(); // fresh instance
        $client->setAuthor(config('app.name'));
        $client->setPageSize($opts['page_size'] ?? 'A4');
        $client->setFooterHtml('<span>Generated '.now()->toDateString().'</span>');

        return $client->convertHtml($html);
    }
}

Two rendering flavours, pick deliberately.

  • convertHtml($html) — full control, works offline for styling, but relative asset URLs break. Either view()->render() with asset URLs made absolute, or use <base href="...">.
  • convertUrl($url, $options) — lets PDFCrowd fetch the page (good for authenticated apps you expose internally, and for SPAs that need JS execution). Pass auth via setHttpAuth() / custom cookies rather than embedding tokens in the URL.

Large / slow conversions belong in a queue. HTML-to-PDF is a network round trip plus PDFCrowd-side rendering; a complex report easily takes 5–30s. Job pattern:

public function handle(PdfRenderer $renderer): void
{
    $html = view('reports.pdf', ['report' => $this->report])->render();
    $pdf  = $renderer->render($html);

    Storage::disk('s3')->put($this->report->pdfPath(), $pdf);
    $this->report->update(['rendered_at' => now()]);
}

Then the controller simply redirects or serves the pre-rendered file. This is the single biggest quality-of-life decision — synchronous PDFCrowd calls are what make users think the app is broken.

Storage vs streaming. Small invoices: return response($pdf)->header(...). Anything reused (statements, receipts): write to disk and serve a signed URL. PDFs are stable artifacts; regenerating on every request burns PDFCrowd credits.

Testing: fake the renderer, not the network. Because the client is a thin singleton, you can bind a stub into the container in setUp():

$this->app->bind(PdfRenderer::class, fn () => new class extends PdfRenderer {
    public function render(string $html, array $opts = []): string { return '%PDF-1.4 fake'; }
});

Assert on the generated HTML in feature tests (snapshot the Blade output) and keep one integration test that hits PDFCrowd in a dedicated, credential-gated test group.

Error mapping. Wrap calls and translate the client's PdfcrowdException (wrong credentials, quota exhausted, unsupported input) into domain exceptions so your HTTP layer can return sensible statuses instead of a 500.

Gotchas and Tips

  • It's archived, with one star. No security patches, no PHP 8.x support guarantees, no response to PDFCrowd API changes. Audit the source (it's small), vendor or fork it, and put a calendar reminder to migrate to the official pdfcrowd/pdfcrowd-php client. The wrapper's value is the Laravel config/facade sugar, which is ~50 lines you can reimplement.
  • Config caching traps. env() calls in config/pdfcrowd.php will silently return null after php artisan config:cache unless the file uses env() only at that top level (which it does if written correctly). If PDFs suddenly fail after a deploy, php artisan config:clear first, then check php artisan tinker → config('pdfcrowd.api_key').
  • State leakage with a singleton client. If the provider registers the client as a singleton and you call setPageSize() in one request, it may persist into the next within a long-running worker (Octane, queue worker). Always make() a fresh client, or reset setters explicitly.
  • Relative URLs break. CSS, images, and fonts referenced as /css/app.css or storage/... won't resolve in convertHtml. Use asset() / Storage::url() with a fully-qualified host, or inject <base href="{{ config('app.url') }}"> into the layout. This is the #1 cause of "the PDF looks unstyled in production but fine locally".
  • PDFCrowd is a paid, credit-metered API. Every conversion costs. Cache generated PDFs keyed by content hash; don't debug by re-running the full report generator in a loop. Set up a separate PDFCrowd account for staging so test runs don't exhaust production quota.
  • Timeouts. Default HTTP timeouts in the underlying client can be short for heavy pages. If you see truncated PDFs or socket errors on large reports, raise the timeout on the client (via the underlying convert* options) and on your queue worker's $timeout.
  • HTTP status on the PDFCrowd side. A 200 from your app doesn't mean PDFCrowd succeeded — the client throws on upstream errors, but if you've wrapped calls in a broad catch (\Throwable $e) you'll render a "PDF" that's actually an error page. Log the exception class and message; do not return $e->getMessage() as PDF content.
  • Extension points are scarce. The clean ones: (a) bind your own PdfRenderer interface, (b) override the config path, (c) subclass the facade's underlying client if you need per-tenant credentials (multi-tenant setups need a factory keyed by tenant, not a global singleton). Anything deeper means forking.
  • No dependents means no community answers. Stack Overflow results for this package are essentially nil — search for pdfcrowd php (the upstream SDK) instead; the method names and error types are the same, and that's where all the real documentation lives.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core