lsnepomuceno/signet-pdf
Signet PDF is a Laravel package for digitally signing PDF documents. It provides a simple API for adding X.509 certificate signatures to existing or generated PDFs, helping PHP applications implement document authenticity, signature validation, and secure signing workflows with minimal setup.
Architecture fit. signet-pdf is a library for producing PAdES (ICP-Brasil) signatures over PDFs. The 3.0.0 headline is an architectural change rather than a feature: PreparedSignature::$document becomes a Support\DocumentBuffer, so signing streams the document instead of materialising it twice. For a TPM this matters because memory cost drops from ~2× document size to ~1× (the release cites 310 MB peak for a 300 MB file, down from 602 MB). That converts "large PDF signing" from a hard no into a capacity-planning question, and it removes a whole class of OOM incidents from the design. The second architectural shift is external key custody: a signature can be produced without the private key entering the PHP process, which is the prerequisite for HSM/remote-signer deployments and for any auditor asking "where does the key live?" The ICP-Brasil work (policy declaration, security store, the three PBAD_ entries archival policies need beyond PAdES) is a conformance play, not an API play.
Integration feasibility. Feasible for a Laravel app, with contained but real friction. Two of the three breaking changes are mechanical ($document type, intervention/image 4.x); the third is a semantic change — SignaturePolicy::forProfile(PadesBLT) now returns null because ITI publishes no policy a B-LT signature satisfies. That is the correct decision, but it means any call site that assumed a policy object existed will now fail at runtime, and it must be handled explicitly. The intervention/image 4.x requirement is the one most likely to ripple beyond this package: it is an app-wide Composer constraint, and any other image-handling dependency in the same application has to be compatible or the upgrade stalls.
Technical risk.
null for B-LT is a silent contract change for callers who do not read UPGRADE.md.Key questions.
DocumentBuffer stream from a disk/S3 path without a full read, or is it an in-memory abstraction with a nicer type?PBAD_ values hard-coded for ICP-Brasil, or extensible for other national profiles?ext-openssl, ext-gd, and disk?Stack fit. Good fit for a Laravel service that already generates documents (invoices, contracts, receipts) and needs to sign them server-side. It slots into the existing service-provider/config-publish pattern, uses the framework's storage disks and queue system, and does not impose a different execution model. The natural placement is a queued job: generate PDF → sign → store → record receipt(). The new receipt() accessor is a small but genuinely useful addition for audit trails and downstream reconciliation.
Migration path. 2.x → 3.0. Follow UPGRADE.md; the order matters:
intervention/image to 4.x first, in isolation, and confirm the rest of the application still works. This is the step most likely to surface unrelated breakage and should not be bundled with signing changes.PreparedSignature::$document with DocumentBuffer. Audit for strlen(), string concatenation, file_put_contents, and any code that hashed or persisted the raw document — those are the real break sites.PadesBLT null-policy case. Decide the product behaviour now: fall back to B-T, reject the request, or surface a configuration error.Compatibility. Pin exact versions and verify: PHP version, Laravel version, intervention/image 4.x coexistence with any other imaging package (Spatie Media Library, Glide, etc.), and whether the external-signer path requires a specific crypto extension or client library. If the application serves multiple document profiles, confirm the profile matrix against the external signer before committing.
Sequencing. Spike on a branch against a representative corpus (small, typical, and a genuinely large 100 MB+ file) → measure peak memory and wall time → run the upgrade steps above → obtain Verificador or equivalent validation on our own sample documents → pilot in a staging queue with production-sized payloads → cut over with 2.x pinned as a rollback. Do not cut over on the strength of the changelog claim alone.
On this line with a 2.x pinned rollback and a validated corpus, the 3.0 cut is a bounded change — the memory profile improves, key custody becomes a deployment decision rather than a code one, and the output becomes defensible against the national verifier. The cost is an intervention/image major bump and a null-policy contract change that will bite silently if the call sites are not audited; both are upgrade work, not steady-state work, and both fit inside a normal release cycle.
Maintenance. Expect majors to move forward and old lines to be archived. Budget a recurring upgrade line item rather than assuming 3.x is terminal. Track the maintainer's release cadence and CHANGELOG as an input to your own patch cadence.
Support. Open-source, community-supported. There is no vendor SLA behind a compliance claim, so the acceptance evidence has to be ours. If signing is revenue- or regulator-facing, designate an internal owner for the conformance story.
Scaling. Throughput is bound by CPU (hashing and signing) and by TSA round-trip latency for B-T and above, not by the package's I/O. Scale queue workers horizontally per signing profile; size each worker's memory_limit to document-size-plus-headroom rather than a flat 512 MB. Very large documents should route to a dedicated queue so they cannot starve ordinary traffic.
Failure modes to instrument.
null policy for B-LT surfacing as a fatal at the call site if not guarded.Ramp-up. Moderate. The API surface is small; the domain is not. PAdES policy OIDs, security stores, DSS/VRI structures and archival PBAD_ entries are where the learning cost sits, and getting them wrong is invisible until a verifier rejects the file. Plan one to two sprints: one for the mechanical upgrade and instrumentation, one for conformance validation with someone who owns the ICP-Brasil requirements. Treat the Verificador run as the definition of done.
How can I help you explore Laravel packages today?