Skip to content

Cli: command handlers and external-validator adapters

The command-line interface (CLI) module provides the engine’s diagnostics and conformance command surface. It includes handlers for benchmark, diff, init, verify, and capabilities commands, plus adapters that wrap external Portable Document Format (PDF) validators, including veraPDF and the Arlington PDF model, behind one interface. A single verify command can run any adapter.

Terminal window
composer require nextpdf/core:^3

Each command uses a handler class whose execute() method returns a process exit code. BenchmarkHandler runs benchmark scenarios. DiffHandler compares documents. InitHandler scaffolds a project. VerifyHandler runs conformance verification. CapabilitiesHandler reports runtime support. CliOutput is the thin stdout/stderr writer shared by the handlers, so output stays testable instead of coupled to globals. BinaryFinder resolves an external tool path on the host (@since 2.5.0).

The validation surface is the key architectural boundary. AlternateValidatorAdapter is the interface an external validator implements. validate() takes a PDF path and a ComplianceFlavour and returns a ComplianceValidationResult. isAvailable() reports whether the backing tool is installed. toolIdentifier() names it. VeraPdfCliAdapter, ArlingtonValidatorAdapter, and AsyncValidatorAdapter implement it. The engine does not re-implement third-party validators. It runs the reference tools and normalizes their verdict. A validator that is not installed reports isAvailable() === false instead of failing the run, so verification records the missing tool explicitly. The adapters are @since 3.0.0; the core handlers are @since 2.3.0@since 2.5.0.

ClassKey membersRole
BenchmarkHandlerexecute(string $format = 'pretty', ?string $scenario = null): intRuns benchmark scenarios (@since 2.4.0)
VerifyHandlerexecute(): intDrives conformance verification
DiffHandler / InitHandlerexecute(): intDocument diff / project scaffold
CapabilitiesHandlerexecute(string $format = 'pretty'): intReports runtime capabilities (@since 2.3.0)
AlternateValidatorAdapter (interface)validate(), isAvailable(), toolIdentifier()External-validator contract (@since 3.0.0)
VeraPdfCliAdapterimplements the adapterWraps the veraPDF CLI (@since 3.0.0)
ArlingtonValidatorAdapterimplements the adapterWraps the Arlington PDF model (@since 3.0.0)
AsyncValidatorAdapterimplements the adapterAsync-capable validator wrapper (@since 3.0.0)
CliOutputwrite(), writeln(), error()Testable stdout/stderr writer (@since 2.3.0)
BinaryFinderexternal-tool path resolutionLocates host tools (@since 2.5.0)

For the full PHPDoc table, run composer docs:generate-api-php -- --module=Cli.

Source: examples/33-validate-conformance.php. Select a validator adapter and check availability before use:

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Cli\VeraPdfCliAdapter;
use NextPDF\Compliance\ComplianceFlavour;
$validator = new VeraPdfCliAdapter(/* binary path / process factory */);
if (!$validator->isAvailable()) {
fwrite(STDERR, "veraPDF is not installed; conformance verification skipped.\n");
exit(2);
}
$result = $validator->validate('/srv/out/report.pdf', ComplianceFlavour::PdfA4);
echo $result->isCompliant() ? "PASS\n" : "FAIL\n";

Run verification through whichever validators are present. Treat an absent tool as a skipped check, not as a failure.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Cli\AlternateValidatorAdapter;
use NextPDF\Compliance\ComplianceFlavour;
use Psr\Log\LoggerInterface;
final readonly class ConformanceGate
{
/** @param list<AlternateValidatorAdapter> $validators */
public function __construct(
private array $validators,
private LoggerInterface $logger,
) {}
public function verify(string $pdfPath, ComplianceFlavour $flavour): bool
{
$ran = false;
foreach ($this->validators as $validator) {
if (!$validator->isAvailable()) {
$this->logger->info('Validator absent; skipped.', ['tool' => $validator->toolIdentifier()]);
continue;
}
$ran = true;
if (!$validator->validate($pdfPath, $flavour)->isCompliant()) {
$this->logger->error('Conformance failed.', ['tool' => $validator->toolIdentifier()]);
return false;
}
}
// No validator available is not a pass — surface it.
return $ran;
}
}
  • An unavailable validator returns isAvailable() === false and does not throw. “No validator available” is not a pass; handle it as a separate state, as the production sample does.
  • The adapters run external binaries. Their verdict is the external tool’s normalized verdict, not an independent re-implementation. Keep the tools current.
  • Handler execute() returns a process exit code. A non-zero code is a failure. Propagate it from your wrapper rather than discarding it.
  • BinaryFinder resolves a tool path on the host. A different host can resolve a different tool version. Pin the environment for reproducible verification.
  • The reproducibility profile is structural: verification reports include timestamps and tool versions, so those fields differ across runs.

Handler overhead is negligible. External validator processes dominate cost, and large documents can be slow. AsyncValidatorAdapter lets you overlap that latency. The performance_budget of 1500 ms wall / 64 MB peak is the engine reference, not a limit for an external validator. Benchmark output has a deterministic structure, but it necessarily includes timing data.

The adapters launch external processes for a PDF path. Treat the PDF as untrusted input, and run verification in a constrained environment. External validators parse hostile data. Validate and canonicalize any file path before you pass it to a handler, so path traversal cannot reach an unintended file. Do not pass unsanitized user input as command arguments. The adapters build process arguments, not shell strings. The input file itself remains attacker-controlled. See the engine threat model in /modules/core/security/.

This module makes no PDF-specification normative claim of its own. It orchestrates conformance verification by delegating to reference validators: veraPDF for PDF/A and PDF/UA, and the Arlington PDF model for ISO 32000-2 structural rules. The external tool provides the authoritative conformance verdict. This module normalizes and reports that verdict. End-to-end conformance and the golden baselines are described in /modules/core/conformance/.