The Main Class

Introduction

As any other SetaPDF component the Signer is represented by a main class: The SetaPDF_Signer class.  

It is the midsection of the signature workflow. It accepts several properties, creates the signature form field automatically, collects e.g. timestamp modules and will delegate the signature process to a signature module.   

Get an Instance

A class instance can be simply created by passing a document instance, that will get digital signed, to its constructor. The document instance should have a writer attached to it. At least this is required before the sign() or timestamp() method is called.

Optionally a callback can be passed, that will be called if an authentication to the documents security handler is needed:

__construct()

The constructor.

Encrypted Documents

If the document you want to sign is encrypted by a security handler which requires a password or a certificate to get the permission to sign the document, it is necessary to pass a callback to the constructor which is called everytime the component needs to authenticate against the security handler. 

PHP
$signer = new SetaPDF_Signer($document, function(SetaPDF_Core_SecHandler_SecHandlerInterface $secHandler) {
    $secHandler->auth('the password');
});

It is also needed to pass this callback if the document is encrypted in the same process because the SetaPDF-Signer component will need to work with temporary instances which need a re-authentication. 

Configuring the Instance

The Signer component allows you to configure the signature process through individual setter and getter methods.

Signature properties like the "time of signing", "contact information"or a "reason" can be set or get as described here.

The Signer component also allows you to create certified documents. This is done by defining a certification level as described here.

Setting the Signature Field Name

A digital signature requires a signature field. That may be a hidden or visible signature field. By default the Signer component will use a signature field that is named: 

The default signature field name

An individual name could be passed to the setSignatureFieldName() method. It has to be passed in UTF-8 encoding. 

Configure the Reserved Space for the Final Signature

Because the signature will be embedded in the PDF document it is needed to reserve an appropriate space in the PDF document into which the final signature will be placed afterwards.

Depending on the content of the final signature this space may be to small. In that case the component will restart the signature process but will reserve sufficient space. So the signature process will be done two times in this situation! 

The component will reserve 3500 bytes by default.

You can control this value with the setSignatureContentLength() method. The whole behavior could be controlled with the setAllowSignatureContentLengthChange() method.

If a timestamp module is used this behavior is automatically disabled because a timestamp request could cost you money. You have to adjust the reserved space your own by the setSignatureContentLength() method.

Add a Timestamp Module

A timestamp module has to be initiated seperately and has to implement the SetaPDF_Signer_Timestamp_Module_ModuleInterface interface.

The module shall be passed to the setTimestampModule() method before starting the signature process with the sign() or timestamp() method.

A detailed description about timestamp modules is available here

The sign() Method

A signature process will be finalized by calling the sign() method with a signature module.

Internally the method will create a temporary version of the document that will be passed to the signature module. The temporary version will be prepared with a reserved space as described earlier and a signature appearance, if a signature appearance module is used. 

The signature creation process is done by the individual signature modules. They return the final signature container. If a timestamp module is in use, the timestamp signature will be added to this container as well. The final container will be embedded into the final PDF document.

The resulting document will be written to the writer instance that was added to the initial document instance. 

The sign() method will save and finish the initial document, so that its instance cannot be used further! 

Example

A very simple signature process will look like: 

PHP
<?php
require_once('library/SetaPDF/Autoload.php');

// create a writer
$writer = new SetaPDF_Core_Writer_Http('simple.pdf', true);
// create a new document instance
$document = SetaPDF_Core_Document::loadByFilename(
    'files/pdfs/tektown/Laboratory-Report.pdf', $writer
);

// create a signer instance
$signer = new SetaPDF_Signer($document);

// set some signature properties
$signer->setReason('Testing');
$signer->setLocation('SetaPDF-Signer Manual');

// create a signature module
$module = new SetaPDF_Signer_Signature_Module_OpenSsl();
// load the certificate
$certificate = 'file://files/certificates/setapdf-no-pw.pem';
$module->setCertificate($certificate);
$module->setPrivateKey(array($certificate, '' /* no password */));

// sign the document and send the final document to the initial writer
$signer->sign($module);            

The timestamp() Method

Beside a signature process the component allows you to add a document level timestamp (PDF 2.0). Simliar to the sign() call the document will be finalized by calling the timestamp() method but it will add a document level timestamp.

Internally the method will also create a temporary version of the document. The temporary version will be prepared with a reserved space as described earlier and a signature appearance, if a signature appearance module is used. 

The calculated hash will be send to a trusted time stamp authority which shall return a valid TimeStampToken which becomes the content of the the signature itself. The final container will be embedded into the final PDF document.

The resulting document will be written to the writer instance that was added to the initial document instance. 

The timestamp() method will save and finish the initial document, so that its instance cannot be used further! 

Several Signatures

The PDF format does not support parallel signatures within a single signature field. To add several signatures to a PDF document, you simply have to re-start the whole signature process with a new signature field name and pass the temporary result around: 

PHP
<?php
require_once('library/SetaPDF/Autoload.php');

// create a temporary writer
$tempWriter = new SetaPDF_Core_Writer_String();

// create a new document instance
$document = SetaPDF_Core_Document::loadByFilename(
    'files/pdfs/tektown/Laboratory-Report.pdf', $tempWriter
);

// create a signer instance
$signer = new SetaPDF_Signer($document);

// set some signature properties
$signer->setReason('Testing');
$signer->setLocation('SetaPDF-Signer Manual');

// create a signature module
$module = new SetaPDF_Signer_Signature_Module_OpenSsl();
// load the certificate
$certificate = 'file://files/certificates/setapdf-no-pw.pem';
$module->setCertificate($certificate);
$module->setPrivateKey(array($certificate, '' /* no password */));

// sign the document and send the final document to the initial writer
$signer->sign($module);

// now simply re-start the process

// create the final writer
$writer = new SetaPDF_Core_Writer_Http('several-signatures.pdf', true);

// create a new document instance based on the temporary result
$document = SetaPDF_Core_Document::loadByString($tempWriter, $writer);

// create a signer instance
$signer = new SetaPDF_Signer($document);

// set a new signature field name
$signer->setSignatureFieldName('Signature 2');

// set some signature properties
$signer->setReason('Also testing');
$signer->setLocation('SetaPDF-Signer Manual');

// create a signature module
$module = new SetaPDF_Signer_Signature_Module_OpenSsl();
// load the certificate
$certificate = 'file://files/certificates/setapdf-no-pw.pem';
$module->setCertificate($certificate);
$module->setPrivateKey(array($certificate, '' /* no password */));

// sign the document and send the final document to the initial writer
$signer->sign($module);