Protected PDF Documents

General Information

Since FPDI PDF-Parser version 2.1 the add-on allows FPDI to import pages of password encrypted or protected PDF documents.

The standard PDF protection is build by a pair of passwords: The owner and the user password. While adding protection to a PDF document the owner can define permissions for the user (e.g. allow printing, allow copy & paste,...) while the viewer or processing application is responsible for the compliance with these permissions. Sadly there's no explicit permission for allowing the user to extract pages from a PDF document - but that's what FPDI is doing.

Because of this the add-on only allows you to import PDF pages of encrypted/protected PDF documents if you are authenticated as the owner. In some situations the owner password is simply unknown (e.g. a random password was used) but you are legally allowed to do whatever you want with this document. That's why we prepared a flag which allows you to ignore the permission settings if you are authenticated as the user.

Supported Algorithms

The FPDI PDF-Parser supports all currently available decryption algorithms for the PDF's standard security handler.

Authentication

As the FPDI PDF-Parser add-on doesn't change the API of FPDI but is implemented on a much lower level it is required to pass authentication data through the methods of FPDI to it. For this we implemented a new method in FPDIs last release named setSourceFileWithParserParams() which is identically to setSourceFile() but has a second parameter for parser-parameters.

The class \setasign\FpdiPdfParser\PdfParser\PdfParser offers available parameter keys as constants.

If you want to authenticate as the owner, just pass its password as follows:

PHP
$pageCount = $pdf->setSourceFileWithParserParams(
    'path/to.pdf',
    [PdfParser::PARAM_OWNER_PASSWORD => 'the-owner-password']
);

If you want to authenticate as the user, you can do this as follows:

PHP
$pageCount = $pdf->setSourceFileWithParserParams(
    'path/to.pdf',
    [PdfParser::PARAM_USER_PASSWORD => 'the-user-password']
);

By passing the correct user-password the add-on is able to create the correct encryption key and is technically able to decrypt the content. But as noted earlier the authentication as the user will not allow you to extract pages from the origin PDF document and it will end in throwing an exception.

If you are legally allowed to bypass the restrictions you can do this as follows:

PHP
$pageCount = $pdf->setSourceFileWithParserParams(
    'path/to.pdf',
    [
        PdfParser::PARAM_USER_PASSWORD => 'the-user-password',
        PdfParser::PARAM_IGNORE_PERMISSIONS => true
    ]
);

If you want to pass a password without knowing if it is the user or owner password, just pass it as follows:

PHP
$pageCount = $pdf->setSourceFileWithParserParams(
    'path/to.pdf',
    [PdfParser::PARAM_PASSWORD => 'the-password']
);

By default the add-on tries to authenticate with an empty string.

Exeption Handling

If FPDI tries to handle an encrypted PDF it always throws a CrossReferenceException with the error code CrossReferenceException::ENCRYPTED.

To keep backwards compatibility this exception and code is still thrown if there's an authentication problem. But the exception receives a previous exception of the type SecHandlerException with more details about the problem. To get the details you have to check this previous exception:

PHP
<?php

use setasign\FpdiPdfParser\PdfParser\PdfParser;
use setasign\FpdiPdfParser\PdfParser\SecHandler\SecHandlerException;
use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;

//...

try {
    $pageCount = $pdf->setSourceFileWithParserParams(
        'path/to.pdf',
        [PdfParser::PARAM_PASSWORD => 'wrong-password']
    );
    // ...
} catch (CrossReferenceException $e) {
    $prev = $e->getPrevious();
    if ($prev instanceof SecHandlerException) {
        switch ($prev->getCode()) {
            case SecHandlerException::NOT_AUTHENTICATED:
                // the password is wrong
                // ...
                break;
            case SecHandlerException::NO_PERMISSIONS:
                // you are authenticated as the user which is not allowed to extract pages
                // ...
                break;
        }
    }
}