Download the PHP package lsnepomuceno/laravel-a1-pdf-sign without Composer

On this page you can find all versions of the php package lsnepomuceno/laravel-a1-pdf-sign. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-a1-pdf-sign

Sign PDF files with an A1 certificate

Digital signatures for Laravel, from PKCS#12 or PEM, with PAdES profiles, long-term validation
and cryptographic verification of signatures a document already carries.

The signing engine is signet-pdf. This package is the Laravel half: the container, the config,
Storage disks as a signing source, and everything faked with the framework's own tools.

Latest version Downloads Tests License

PHP Laravel PHPStan Type coverage

Documentation  ·  Release notes  ·  Upgrading  ·  The engine


Installation

Nothing else to register: the service provider is discovered, and the A1PdfSign facade is available immediately.

openssl on PATH is not required to sign; it is used only for verifying a signature and for reading a legacy PFX file. Where it is needed it is needed properly: ext-openssl being loaded is a different thing from the binary being installed, and a minimal container commonly has the first without the second. Validating without it raises MissingBinaryException, and an environment where proc_open is disabled raises ProcessUnavailableException. Neither is reported as a signature that failed to verify.

Every exception this package raises implements Exceptions\SignetException, so an application can handle them as a group rather than by name:

The classes stay granular beneath it. InvalidCertificatePasswordException is the one worth catching on its own, since a wrong password is the failure a production application meets most, and it extends InvalidCertificateContentException so the general catch still works.

Signing

[!IMPORTANT] Signing appends a revision rather than rebuilding the document. The original bytes survive byte for byte, so annotations, form fields and every earlier signature are preserved, and a document can carry as many signatures as it needs. That is TCPDF#430, open since 2021, and it is the single most important behaviour in this package.

The document does not have to be a local file

An application keeping contracts on s3, minio or any Flysystem disk does not have to download one first, and the signed result does not have to come back through one either:

fromUpload() does the same for a document that arrived in a request, reading it where it already is rather than copying it to a temporary file. toDisk() with no path keeps the name the document carries, which is the original with _signed appended.

All of these hold the whole document in memory. For one too large for that, the engine takes a stream: see signet-pdf.

What it does

PKCS#12 and PEM .pfx, .p12, or a PEM certificate with the key beside it or in its own file
PAdES profiles legacy through pades-b-lta, with RFC 3161 timestamps and long-term validation
Visible seals rendered from the certificate or drawn from your own artwork, on the page you name
Template fields fills a signature field a contract already carries, instead of appending beside it
Certification ISO 32000-1 §12.8.2.2 DocMDP, plus field locks that later signatures honour
Encrypted documents AES-128 and AES-256, signed and re-encrypted under the document's own key
Archive maintenance refresh a B-LTA archive with no certificate and no key material involved
Verification the CMS is actually verified, with the timestamp, the profile and revocation reported
ICP-Brasil identity CPF, CNPJ and the rest, read from the certificate rather than parsed out of a name
PDF/A a signed document stays conformant, measured with veraPDF rather than assumed
PDF/UA measured too: an invisible signature keeps an accessible document conformant, a visible seal does not

Bringing your own seal

The seal is drawn by Contracts\SealRenderer, bound in the container, so replacing it is one line in your own service provider:

That is the route for a corporate logo, a QR code linking to a validation page, or any layout of your own. The contract has two methods: render() builds a seal from the certificate, and fromImage() embeds artwork you already have.

fromImage() is also the answer to "can I draw the seal with Blade". Render your view to an image however you like and hand the result over; the package stays out of the business of turning HTML into pixels, which would be a large dependency for a signing library.

Testing an application that signs

Your own suite should not need a PKCS#12 bundle, nor should it build a real CMS for a test that merely passes through the signing call:

It replaces the engine in the container, not just one binding, so certificate() accepts any path and nothing is parsed, rendered or signed. The result is still a SignedPdf, so code calling ->contents, ->size() or ->save() keeps working. Two-phase signing records too: assertPrepared() and assertCompleted().

The three other seams

The fake covers signing. The rest of what the package touches is replaced with Laravel's own tools, which is most of the reason this package exists rather than just signet-pdf:

For the profiles above pades-b-b, substituting the transport with Signet\Testing\LocalTimestampAuthority gates them offline with real RFC 3161 tokens, rather than reporting them against a live authority:

Certificates

The encoding is decided by content, not by extension, since PEM ships as .pem, .crt, .cer, .key and .txt. Pass an empty password when the private key is unencrypted: PEM permits that and PKCS#12 does not, and an unprotected key on disk is readable by anything that can read the file.

One call, when there is nothing to configure

The builder exists for the cases that need it. When none of them apply, there is a one-shot form for each source:

Storing a certificate

A certificate and its password can be encrypted for storage and read back later, so an application that signs on a schedule does not keep either in plaintext:

The hash is the key, so keep it somewhere other than the ciphertext it opens. Without it the pair cannot be read back, by you or by anyone else.

PAdES profiles

Profile Adds
legacy ISO 32000-1 detached CMS. Widest reader support
pades-b-b CAdES signed attributes, with ESS signing-certificate-v2. Default
pades-b-t plus an RFC 3161 timestamp, so the signing time is attested by a third party
pades-b-lt plus a Document Security Store, so it still verifies after the certificate expires
pades-b-lta plus an archive timestamp over the whole file

An archive is a chain rather than a state, so it can be extended before the algorithms behind it weaken. No certificate is involved: a DocTimeStamp is signed by the authority, not by the signer, so a scheduled job can do this with no key material anywhere near it.

Profiles, in detail →

Signing into a template's own fields

A contract laid out by someone else arrives with its signature fields already placed. intoField() fills the one you name instead of appending another beside it:

A field that is missing or already signed raises rather than falling back to appending. That fallback is the failure this prevents: a signature that is valid and in the wrong place, with the template's field still empty.

Placing the field in the first place

addSignatureField() is the other half, for when nobody has laid the template out for you:

Signing where the key is somewhere else

For a private key that never enters the process, in an HSM, a remote service or a smartcard, signing splits in two:

$prepared carries no key and no secret, so it survives a queue. That is usually the point: the digest goes to a worker with access to the signing device, and the document comes back finished.

Certification and locks

A certification governs the whole document; a lock governs the fields you name. The half that matters is the reading: a later signature into a field an existing lock covers is refused, rather than producing a document whose earlier signature silently stopped verifying.

Encrypted documents

A password-protected document is signed and re-encrypted under its own key, so the file stays consistent:

The document's password and the certificate's are different things and are passed separately: one opens the file, the other unlocks the key that signs it. AES-128 and AES-256 are supported. RC4 is refused, because signing it would mean writing RC4 back into a document in order to sign it.

Validation

isValid() means the CMS actually verifies. Each signature also reports what the document can prove about it:

Revocation is evaluated from the material the document carries, and the material is verified against the issuer before it is believed. Nothing is fetched: validation makes no network request and cannot be made to.

Whether to accept the signer is a separate question, answered against roots you name:

[!NOTE] The package ships no trust store and will not. A bundled one goes stale between releases, and shipping it would make this package's release cadence the thing that decides whose signatures you accept. For ICP-Brasil, fetch the current chain from the ITI and keep it with your configuration. OpenSSL does the path validation, so intermediate validity, basicConstraints, key usage and name constraints are all checked rather than approximated.

An untrusted signature is not an invalid one: the two questions are independent.

ICP-Brasil

A Brazilian certificate carries the holder's identity in subjectAlternativeName, not in the subject, and PHP renders every one of those fields as othername:<unsupported>. This package reads them:

A certificate can also be checked against the rules its own specification states, before anything is signed:

[!WARNING] conforms() is not isTrusted(). Every rule it checks is decidable from the certificate alone, so a self-signed certificate built to satisfy them will conform. Whether the chain reaches an ICP-Brasil root is TrustStore's question, and it is a different one.

AI agents

An agent can read a signed document and tell you who signed it, and, with a person's approval of every call, sign one. The package ships the tools, on Laravel's own AI packages, and leaves the agent to you. Both packages are optional:

Nothing is reachable until you open a disk to agents, which is empty by default:

Reading goes through MCP, so Claude Code, Cursor or Boost can ask, and an AI SDK agent runs the same tools:

Signing goes through the AI SDK, because only there can a tool insist on approval. The run pauses, your application shows a person exactly what would be signed and with whose certificate, and it resumes with their decision:

Approval cannot be switched off, a repeated call signs once, a signed copy never overwrites a file, and a model's path never leaves the disks you opened. Who may read or sign which document is your Gate, through two abilities the tools ask before they look at the document. The agents guide has the whole flow, and 0040 the reasoning.

Command line

pdf:add-field places an empty field for somebody else to sign later, and leaves it invisible when no rectangle is given. pdf:extend renews a B-LTA document before its archive timestamp ages out, which is the one operation here that a scheduler calls rather than a request.

Compatibility

Package Laravel PHP Engine
^3 ^13 8.4.1 – 8.5 signet-pdf ^3
^2 ^13 8.4 – 8.5 in-package
^1 ^9 – ^12 8.1 – 8.4 in-package
^0 ^8 ^7.4 in-package

Laravel 12 is not supported, despite reaching PHP 8.5: it requires symfony/process ^7.2 while the test toolchain requires ^8.1, so the two cannot be installed together.

v3 needs intervention/image ^4, which arrives through signet-pdf. An application pinned to ^3 cannot install it.

The agent tools, from 3.1, need laravel/mcp ^1 for reading and laravel/ai ^1 for signing. Both are optional, and the package refuses to install beside any other major of either.

Coming from 2.x? Every class moved to the LSNepomuceno\Signet\ namespace and nothing else changed. UPGRADE.md has the table.

Verified, not asserted

Signed output is checked against tools that were not written here, because a validator sharing its assumptions with the signer proves very little: poppler pdfsig reads the output independently, veraPDF decides PDF/A and PDF/UA conformance, pyHanko enforces /DocMDP, and qpdf checks structure.

All four run in signet-pdf, which is where the bytes are produced. They measure what a writer writes, and this package writes none: what it is measured on is whether the wiring, the adapters and the config carry your instructions through unchanged.

Contributing

Patches are expected to come with tests. composer check runs everything CI runs: Pint, PHPStan at level max with no baseline, a dependency report and the suite.

See ARCHITECTURE.md for how the package is put together and why. The rules that break the product when violated are in docs/spec/invariants.md, and the reasoning behind the design is one numbered file per decision in docs/decisions/.

Security

Found a vulnerability? Please follow SECURITY.md rather than opening a public issue.

License

MIT. See LICENSE.md.


All versions of laravel-a1-pdf-sign with dependencies

PHP Build Version
Package Version
Requires php Version >=8.4.1 <8.6
ext-json Version *
illuminate/console Version ^13
illuminate/encryption Version ^13
illuminate/http Version ^13
illuminate/process Version ^13
illuminate/support Version ^13
lsnepomuceno/signet-pdf Version ^3.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package lsnepomuceno/laravel-a1-pdf-sign contains the following files

Loading the files please wait ...