Skip to content

compat-legacy security and operations

The adapter uses the NextPDF engine’s security model and adds a few deliberate hardenings over legacy TCPDF 6.2.13. This page states exactly what is available and what is not, without overstatement. Read the signing section carefully; its scope is intentionally narrow.

The adapter changes three historical TCPDF 6.2.13 behaviors for safety. They are not configurable back to the unsafe form:

ConcernLegacy TCPDF 6.2.13Adapter
Error handlingError() calls die() and terminates the processError() throws RuntimeException; callers can observe and catch the failure, with no silent process kill.
HTML executionAn escape hatch could run PHP from markupThe K_TCPDF_CALLS_IN_HTML constant is fixed to false; markup cannot trigger PHP execution.
Direct outputOutput() echoes to the active output bufferOutput goes through a safe destination bridge and does not pollute a caller-controlled output buffer.

The error-handling change ensures you can observe a failure instead of losing the process to termination. Open Worldwide Application Security Project (OWASP) Application Security Verification Standard (ASVS) 5.0 §16.5.3 states that an application should fail gracefully and securely and prevent fail-open conditions. The throw-instead-of-die change applies that principle. The HTML hardening removes a code-execution sink. Treat legacy code that depended on the old behavior as a defect to fix during /integrations/tcpdf-compat/migration/. The pinned clause digest is in the page front-matter citations.

The adapter exposes TCPDF’s SetProtection() and delegates to the NextPDF engine’s standard security handler.

  • The standard handler uses AES-256. The legacy $mode parameter is accepted for method-signature compatibility and ignored; there is no way to select a weaker cipher through this method. When strict mode is on, a non-default $mode throws so the migration is forced to acknowledge it (asserted in tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php).
  • If no owner password is supplied, the adapter generates a cryptographically strong random owner password instead of reusing the user password. This prevents holders of user-level access from gaining owner-level control of the document.
  • Certificate-based (public-key) encryption is not done through SetProtection(); the adapter ignores its $pubkeys parameter. Use the modern public-key encryption entry point exposed on the adapter (setPublicKeyEncryption()), which delegates to the engine.

The encryption behavior reflects the standard security handler described in ISO 32000-2 §7. That clause defines the encryption dictionary entries and the AES-256 standard handler the engine uses. This documentation does not claim the output is “secure by default” or “tamper-proof”. It states only the cipher used and the owner-password behavior implemented by the code. The pinned clause digest is in the page front-matter citations.

examples/security-encryption.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Encrypted document');
// User password set; owner password auto-generated (strong, random).
$pdf->SetProtection([], 'user-secret');
$pdf->Output(__DIR__ . '/encrypted.pdf', 'F');

Read this section literally. It is deliberately conservative.

  • The TCPDF legacy setSignature() and addEmptySignatureAppearance() methods are unimplemented in the adapter on the core engine. In default mode, they do nothing. In strict mode, they throw TcpdfNotImplementedException.
  • Digital signing is not a capability of the core distribution through this adapter. Baseline signature support requires a commercial NextPDF edition.
  • If a commercial edition is present, the adapter exposes a modern signature entry point (setSignatureV2()) that delegates to the engine. Its default profile is the baseline (B-B) profile.
  • This documentation makes no claim that any edition produces timestamped, long-term-validation, or archival signature profiles through this adapter. Specifically, it does not assert B-T, B-LT, or B-LTA behavior. The PDF Advanced Electronic Signatures (PAdES) baseline specification §6.1 defines four distinct baseline levels: B-B, B-T, B-LT, and B-LTA. Each has its own requirements. B-B is the baseline level, and the higher levels (timestamp, long-term, archival) are separate, more demanding profiles. Only the B-B baseline is in scope for this compatibility layer’s documentation. The higher levels are explicitly out of scope and are not claimed for any edition here. The pinned clause digest is in the page front-matter citations.
  • This documentation makes no “certified”, “guaranteed”, “legally valid”, or “eIDAS-qualified” signature claim anywhere. Signing correctness, trust-anchor policy, and legal validity are the responsibility of the signing edition and the caller’s Public Key Infrastructure (PKI), not of this compatibility layer.

If your migration requires signing, treat it as a separate workstream: adopt the modern signature application programming interface (API) on a commercial edition and validate the resulting signature with an independent verifier. Do not rely on the TCPDF setSignature() call; it is a no-op here.

The legacy setTimeStamp() method is accepted for method-signature compatibility and emits a notice; it does not produce a timestamped signature through this adapter.

The constructor’s pdfa flag is accepted for method-signature compatibility. PDF/A archival conformance requires a commercial NextPDF edition. The adapter exposes enablePdfA(), which delegates to the engine, and the engine returns an actionable configuration error when the required edition is absent. The adapter does not silently produce a non-conformant file while claiming PDF/A.

Output is always PDF 2.0 (ISO 32000-2). ISO 32000-2 §7.5.2 specifies that a conforming writer identifies the document version as 2.0 and does not lower it to an older version on save. Therefore, setPDFVersion() cannot down-target an older version (see /integrations/tcpdf-compat/method-coverage/ §4). The pinned clause digest is in the page front-matter citations.

  • No process termination. Because Error() throws instead of die(), wrap render entry points in try/catch and map failures to your application’s error contract. Do not assume a failed render ends the request.
  • Output buffer safety. Output() with S returns bytes; with F writes a file; with E returns a base64 Multipurpose Internet Mail Extensions (MIME) body; with I/D it routes through the engine output path. Prefer S or F in workers and Hypertext Transfer Protocol (HTTP) handlers so you control the response yourself; see /integrations/tcpdf-compat/production-usage/.
  • Strict mode is not a production setting. Keep it to a continuous integration (CI) or audit job. An exception in a production render path is worse than a silently degraded parameter.
  • Constant hygiene. Define PDF_* / K_* constants before the first adapter construction. The two hardened flags (K_TCPDF_CALLS_IN_HTML, K_TCPDF_THROW_EXCEPTION_ERROR) cannot be relaxed; do not attempt to relax them.
  • Random owner passwords. If you rely on a deterministic owner password, set it explicitly. Otherwise, a strong random one is generated per document and is not recoverable.
  • For image methods, the adapter refuses a stream-wrapper path before any filesystem read. Image type detection (TcpdfImages::getImageFileType) treats any scheme:// path, including phar://, php://, and other PHP stream wrappers, as a wrapper and skips the file_get_contents / getimagesize probe, falling back to extension-only inference. This closes a phar metadata-deserialization vector on the PHP 7.4 backport target; the engine rejects the wrapper-path embed itself.
  • The adapter does not add path validation or sanitization for file paths passed to image or output methods beyond what the engine does. Treat caller-supplied paths and URLs as untrusted at your application boundary.
  • HTML passed to the HTML methods is rendered by the engine, not by a TCPDF HTML parser. The legacy PHP-execution sink is closed, but you should still treat caller-supplied HTML as untrusted input.
  • Encryption protects document confidentiality at rest under the standard handler. It is not a substitute for transport security or access control in your application.
  • /integrations/tcpdf-compat/method-coverage/ — exact behavior of SetProtection(), setSignature()
  • /integrations/tcpdf-compat/configuration/ — the two hardened, non-configurable flags
  • /integrations/tcpdf-compat/production-usage/ — workers, buffers, failure handling
  • docs/TCPDF_COVERAGE.md — authoritative coverage matrix
  • Package NOTICE — independent-implementation statement