Repository navigation
Add typed API for existing PDF signature fields #62
Description
Context
JSignPdf 3.2.0 supports:
- listing existing PDF signature fields with
--list-sig-fields; - signing an existing empty signature field with
--sig-field.
jsignpdf-php should expose these capabilities through a typed PHP API.
Applications using this library should not need to know JSignPdf CLI syntax or parse JSignPdf output themselves.
This issue requires JSignPdf 3.2.0 to already be available as the default runtime.
Track the runtime update separately and mark this issue as blocked by it.
Goal
Allow PHP applications to:
- inspect the signature fields reported by JSignPdf;
- read the field name, page, rectangle and state;
- select an existing signature field when signing.
The PHP API must hide JSignPdf CLI details from applications.
Important implementation rule
Do not parse PDF or AcroForm structures in PHP.
JSignPdf already discovers and interprets the signature fields.
The wrapper only needs to:
- run the existing JSignPdf commands;
- parse the documented JSignPdf 3.2.0 output;
- expose the result through a typed PHP API.
Do not add Java code or another PDF library.
Public model
Add a final immutable value object under the signing namespace:
final class SignatureFieldIt should expose:
public function getName(): string;
public function getPage(): int;
public function getLlx(): float;
public function getLly(): float;
public function getUrx(): float;
public function getUry(): float;
public function isSigned(): bool;
public function isHidden(): bool;Also provide:
public function isBlank(): bool;
public function hasVisibleRectangle(): bool;with:
isBlank() = !isSigned()
hasVisibleRectangle() =
urx > llx
&& ury > lly
The object must not expose mutable setters.
Meaning of the values
SignatureField represents the values reported by JSignPdf.
Do not inspect the PDF again to verify or recalculate them.
In particular:
isSigned()represents thesignedstate reported by JSignPdf;- it does not mean that the PHP wrapper cryptographically validated the signature;
isHidden()represents thehiddenstate reported by JSignPdf;- page and rectangle values are the values reported by JSignPdf.
A zero-size rectangle is valid output and must remain in the result.
Inspect signature fields
Add this method to JSignService:
/**
* @return list<SignatureField>
*/
public function getSignatureFields(JSignParam $params): array;This is an inspection operation, not a signing operation.
It requires:
- PDF content;
- the configured Java runtime;
- the configured JSignPdf runtime;
- the existing temporary-file infrastructure.
It must not require:
- a signing certificate;
- certificate password;
- TSA configuration;
- other signing-only parameters.
Do not call signing validation that requires certificate material.
Run the inspection command
The inspection flow should:
- store the PDF using the existing temporary-file mechanism;
- execute JSignPdf with
--list-sig-fields; - use
--quietso normal JSignPdf logging does not interfere with the listing; - force English JSignPdf messages for predictable parsing;
- parse the output;
- create
SignatureFieldobjects; - preserve the order returned by JSignPdf;
- clean temporary files on success and failure.
Reuse the existing Java runtime resolution, JSignPdf runtime resolution and process execution infrastructure.
Do not create a second execution mechanism only for this feature.
JSignPdf 3.2.0 field output
JSignPdf formats a signature field as:
#<number> <field name> page <page> [<llx> <lly> <urx> <ury>] <state>
Example:
#1 CustomerSignature page 1 [70.0 700.0 300.0 760.0] blank
Another example:
#2 Manager Signature page 2 [70.0 600.0 300.0 660.0] signed, hidden
The states produced by JSignPdf are:
blank
signed
blank, hidden
signed, hidden
Coordinates are formatted by JSignPdf with Locale.ROOT.
The PHP parser must therefore parse . as the decimal separator independently from the PHP system locale.
The leading #<number> is part of the JSignPdf CLI representation.
It does not need to become part of the public PHP model.
Parse field names safely
JSignPdf formats the field name using a minimum display width of 30 characters.
Field names may contain spaces and may be longer than this width.
Do not:
- use fixed character offsets;
- split the complete line by spaces.
Parse the structural parts of the line:
#<number>
<field name>
page <page>
[<coordinates>]
<state>
and use the text between the leading number and the page ... [...] section as the field name after removing display padding.
Normal single-line Unicode field names must be supported.
Known limitation
The JSignPdf output is intended for human-readable CLI output, so it is not a lossless serialization of every possible PDF field name.
Because the field name is padded with spaces, trailing spaces that are part of the original PDF field name cannot be distinguished from display padding.
Do not try to guess them.
If an output entry cannot be parsed safely, fail explicitly instead of returning incorrect data.
Selector-shadow suffix
JSignPdf gives an exact field-name match priority over its auto and #N convenience selectors.
For a field whose literal name is:
auto
or a numeric selector such as:
#1
the listing may append:
- this field name shadows the selector of the same name, the field name wins
Ignore this informational suffix when parsing.
It must not become part of SignatureField.
PDF without signature fields
For a valid PDF without signature fields, JSignPdf prints:
<file>: no signature fields
and exits successfully.
getSignatureFields() must return:
[]This is not an error.
Inspection failure
When JSignPdf cannot read the signature fields, it reports:
Can not read the signature fields of '<file>': <reason>
and the listing command exits with code 5.
getSignatureFields() must throw an exception.
Do not return an empty list for this case.
Preserve useful JSignPdf diagnostic information in the exception.
Unexpected output
Do not silently ignore a signature-field entry that does not match the expected JSignPdf 3.2.0 format.
If a field line cannot be parsed, throw an exception containing the unexpected line.
Do not guess a new format.
This avoids silently returning incomplete data if JSignPdf changes its CLI output in the future.
Do not reproduce JSignPdf internals
Do not add PHP logic for:
- finding AcroForm fields;
- deciding whether a PDF field is a signature field;
- deciding whether a field is signed;
- reading
/Rect; - reading widget flags;
- deciding field order;
- resolving
auto; - resolving
#N; - deciding whether a field can be signed.
These rules belong to JSignPdf.
The wrapper only consumes the result.
Select an existing field for signing
Add to JSignParam:
public function setSignatureField(?string $fieldName): self;
public function getSignatureField(): ?string;Default:
nullWhen the value is null, existing signing behavior must remain unchanged.
For a non-null value, JSignService must pass it to JSignPdf using:
--sig-field
Applications must not need to add this option manually through:
setJSignParameters()Use the existing command escaping rules.
Do not reinterpret the configured value
The PHP wrapper must not implement its own signature-field selector.
Do not:
- trim the configured value;
- translate it to another identifier;
- implement
autoin PHP; - implement
#Nin PHP; - pre-resolve the value using
getSignatureFields().
Pass the configured value to JSignPdf and let JSignPdf perform its normal resolution.
This preserves JSignPdf behavior for fields whose literal names are:
auto
or:
#1
because JSignPdf checks exact field names before interpreting its convenience selectors.
Field placement
Do not calculate or modify existing field placement in PHP.
JSignPdf resolves the selected field and uses its existing placement.
Do not copy the page or rectangle from SignatureField into the normal visible-signature coordinate options.
Signing failures
JSignPdf already handles invalid field selections, including cases such as:
- no matching field;
- no signature fields in the PDF;
- already signed field;
- invalid field selection.
Preserve useful JSignPdf diagnostic output when signing fails.
Do not duplicate these validations in PHP before calling JSignPdf.
Backward compatibility
Existing applications must continue working without changes.
In particular:
JSignParamwithoutsetSignatureField()follows the current signing path;setJSignParameters()remains available;- certificate handling remains unchanged;
- password handling remains unchanged;
- TSA behavior remains unchanged;
- existing visible-signature behavior remains unchanged when no field is configured.
Do not redesign unrelated wrapper APIs.
Tests
SignatureField
Add unit tests for:
- constructor values;
- getters;
isSigned();isBlank();isHidden();hasVisibleRectangle();- zero-size rectangle.
Output parser
Use strings based on the real JSignPdf 3.2.0 formatter.
Cover:
- blank field;
- signed field;
- blank hidden field;
- signed hidden field;
- field name with spaces;
- single-line Unicode field name;
- field name longer than 30 characters;
- literal field name
auto; - literal field name
#1; - selector-shadow suffix;
- decimal coordinates;
- negative coordinates;
- multiple fields;
- malformed field entry.
A malformed field entry must fail instead of being ignored.
Do not invent alternative JSignPdf output formats for the tests.
Inspection integration
Use small real PDF fixtures for:
- PDF without signature fields;
- one blank signature field;
- multiple signature fields;
- blank and signed fields together;
- hidden signature field;
- zero-size rectangle;
- unreadable or invalid PDF.
Verify the PHP result against the values reported by JSignPdf.
Do not add PHP PDF parsing only to implement test assertions.
Signing integration
Cover:
- signing a blank field by name;
- field name with spaces;
- single-line Unicode field name;
- literal field name
auto; - literal field name
#1; - attempting to sign an already signed field;
- attempting to sign a missing field;
- signing without
setSignatureField()keeps the current behavior.
Let JSignPdf resolve and validate the selected field.
Documentation
Update the README with small examples.
Inspect fields
$params = JSignParam::instance()
->setPdf($pdf);
$fields = (new JSignService())->getSignatureFields($params);
foreach ($fields as $field) {
if ($field->isBlank()) {
echo $field->getName();
}
}Sign an existing field
$params = JSignParam::instance()
->setPdf($pdf)
->setCertificate($certificate)
->setPassword($password)
->setSignatureField('CustomerSignature');
$signedPdf = (new JSignService())->sign($params);Applications should not need to call --list-sig-fields or --sig-field directly.
Out of scope
Do not add:
- Java code;
- changes to JSignPdf;
- another PDF library;
- PHP AcroForm parsing;
- generic PDF form editing;
- PDF field creation;
- automatic field selection in PHP;
- PHP implementation of
auto; - PHP implementation of
#N; - recipient concepts;
- workflow concepts;
- application-specific business rules.
Good first issue
The public API and JSignPdf 3.2.0 integration behavior are already defined.
The contributor does not need to research PDF internals or design signature-field behavior.
Reuse:
JSignParam;JSignService;- the existing Java runtime resolution;
- the existing JSignPdf runtime resolution;
- temporary-file handling;
- command execution and escaping patterns.
The main work is:
- add
SignatureField; - add
getSignatureFields(); - run
--list-sig-fields --quiet; - parse the documented JSignPdf 3.2.0 output;
- add
setSignatureField()andgetSignatureField(); - pass the configured value through
--sig-field; - add focused tests;
- update the README.
Do not expand this issue into PDF parsing or application field-domain design.
If real JSignPdf 3.2.0 output is found that is not covered here, discuss it before adding new public API behavior.
Done when
-
SignatureFieldprovides an immutable typed representation of JSignPdf field information. -
getSignatureFields()works without signing credentials. - Inspection uses quiet mode and predictable English messages.
- Valid PDFs without signature fields return an empty list.
- Inspection failures throw an exception.
- Blank, signed and hidden states are represented.
- Zero-size rectangles are preserved.
- Field names are parsed without fixed-width assumptions.
- Normal single-line Unicode names are supported.
- Unexpected field entries are not silently ignored.
- Applications can configure an existing field through
setSignatureField(). - The wrapper does not trim or reinterpret the configured value.
-
autoand#Nare not implemented in PHP. - Applications do not need to construct signature-field CLI options.
- Existing signing behavior remains unchanged when no field is configured.
- Useful JSignPdf errors are preserved.
- Temporary files are cleaned on success and failure.
- Unit, parser and integration tests cover the supported behavior.
- README documents inspection and signing with existing fields.
Activity
vikas-kushwaha-dev commentedon Sep 16, 2026
Hi @vitormattos, I'd also be interested in working on this after #63 is completed. I'm planning to start with the JSignPdf 3.2.0 runtime update in #63 first, then I can work on the typed signature-field API here.
If that approach works for you, could you assign this issue to me as well?
vitormattos commentedon Sep 16, 2026
@vikas-kushwaha-dev finish first the issue #63, after merging, I can assign this to you.