SetaPDF-Encryptor Implement identical functionality as the SetaPDF-Encryptor offered

Introduction

Beginning with SetaPDF 2 standard security (user and owner password) was already implemented in the SetaPDF-Core component by default which was automatically available for all other components. 

As of version 2.16.0.754 the SetaPDF-Core component also supports certificate based encryption which makes the SetaPDF-Encryptor API obsolete. 

This article will show replacement code for specific methods of the old API.

Error Handling

While in version 1 error objects were returned, version 2 uses Exceptions throughout. More details can be found here.  

Loading and Saving PDF Documents

The SetaPDF-Encryptor offered only the possibility to load a PDF file from a file. The new system allows a PDF document to be read from various sources through so called Reader objects.

Nearly same things exists for the resulting document: SetaPDF_Core_Writer_WriterInterface

PHP
$filename = 'a/path/to/a/Pdf/file.pdf';
$target = 'a/path/to/the/resulting/file.pdf';
     
// old version
$encryptor = \SetaPDF_Encryptor::factory($filename);
// ...
$encryptor->encrypt($target, ...);
     
// will become:
$reader = new \SetaPDF_Core_Reader_File($filename);
$writer = new \SetaPDF_Core_Writer_File($target);
$document = \SetaPDF_Core_Document::load($reader, $writer);
// ...
$document->save()->finish();

In the new version it is possible to define separate readers or writers, which was impossible for the old version.

Equivalent Code of Methods

The whole class SetaPDF_Encryptor doesn't exist in SetaPDF-Core anymore. Encryption is done by so called security handler classes (SetaPDF_Core_SecHandler_Standard and SetaPDF_Core_SecHandler_PublicKey).

To create a new security handler instance the Core component offers factory-methods (Standard and PublicKey) for individual encryption algorithms and strengths. 

The old methods can be refactored to the new version as follows: 

Permissions

While permissions were defined as text strings in an array structure in the SetaPDF_Encryptor API they are represented as constants (integer) in SetaPDF 2. A permission set has to be created by joining the permission flags bitwise: 

PHP
// old:
$permissions = array('print', 'copy');
// new:
$permissions = \SetaPDF_Core_SecHandler::PERM_PRINT | \SetaPDF_Core_SecHandler::PERM_COPY;

All available permission constants are defined here or described here

SetaPDF_Encryptor::encrypt()

The encrypt()-method is not available in SetaPDF 2 but is replaced by a logic which allows you to pass a separately created security handler instance to a document instance: 

PHP
$filename = 'a/path/to/a/pdf/file.pdf';
$target = 'a/path/to/the/resulting/file.pdf';

$ownerPassword = 'owner';
$userPassword = 'user';

$permissionsOld = array('print', 'copy');
$permissionsNew = \SetaPDF_Core_SecHandler::PERM_PRINT | \SetaPDF_Core_SecHandler::PERM_COPY;

$dest = 'F';
$stream = false;

// old code
$encryptor = new \SetaPDF_Encryptor($filename);
$encryptor->encrypt($target, $ownerPassword, $userPassword, $permissionsOld, \SETAPDF_ENC_RC4_40, $dest, $stream);


// new code
$writer = new \SetaPDF_Core_Writer_File($target);
$reader = new \SetaPDF_Core_Reader_File($filename);
$document = \SetaPDF_Core_Document::load($reader, $writer);

$secHandler = \SetaPDF_Core_SecHandler_Standard_Arcfour40::factory(
    $document,
    $ownerPassword,
    $userPassword,
    $permissionsNew
);

// Attach the handler to the document
$document->setSecHandler($secHandler);
$document->save()->finish();

As you can see the permission flags are switched from a textual representation to an integer representation.

Additionally the encryption strength isn't represented by a constant but by a specific class that offers a factory() method:

For public key security equivalent factory-classes exist:

The handling of public-key security has changed, too: All recipients have to be created as individual objects which need to be passed as an array to the factory() method then: 

PHP
$recipientA = file_get_contents('/path/to/public/key/certificate-a.cer');
$recipientB = file_get_contents('/path/to/public/key/certificate-b.cer');
$recipientC = file_get_contents('/path/to/public/key/certificate-c.cer');

$permissionsOld = array('print', 'copy');
$permissionsNew = \SetaPDF_Core_SecHandler::PERM_PRINT | \SetaPDF_Core_SecHandler::PERM_COPY;

// old
// [...]
$encryptor->encrypt($target, array(
    0 => array(
        'certs' => array($recipientA, $recipientB),
        'permissions' => $permissionsOld
    ),
    1 => array(
        'certs' => array($recipientC),
        'owner' => true
    )
), '', \SETAPDF_ENC_AES_128);

// new
$recipients = array();
$recipients[] = new \SetaPDF_Core_SecHandler_PublicKey_Recipient($recipientA, $permissionsNew);
$recipients[] = new \SetaPDF_Core_SecHandler_PublicKey_Recipient($recipientB, $permissionsNew);
$recipients[] = new \SetaPDF_Core_SecHandler_PublicKey_Recipient($recipientC, \SetaPDF_Core_SecHandler_PublicKey::PERM_OWNER);

$secHandler = \SetaPDF_Core_SecHandler_PublicKey_Aes128::factory($document, $recipients);
$document->setSecHandler($secHandler);
// [...]

SetaPDF_Encryptor::setTmpDirectory() / SetaPDF_Encryptor::factory()

The handling of temporary files, which is only needed for public-key security was moved to a temporary writer class. The path for temporary files was set in the 2nd parameter of the factory()- or in the setTmpDirectory() method: 

PHP
// old:
$encryptor = \SetaPDF_Encryptor::factory($sourceFile, 'temp/');
$encryptor->setTmpDirectory('temp/');
// new:
\SetaPDF_Core_Writer_TempFile::setTempDir('temp/');