Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.22% covered (success)
97.22%
35 / 36
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
EncryptDictionary
97.22% covered (success)
97.22%
35 / 36
50.00% covered (danger)
50.00%
1 / 2
17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 toPdf
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
16
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Core\Security;
6
7use Phpdftk\Pdf\Core\PdfArray;
8use Phpdftk\Pdf\Core\PdfBoolean;
9use Phpdftk\Pdf\Core\PdfDictionary;
10use Phpdftk\Pdf\Core\PdfName;
11use Phpdftk\Pdf\Core\PdfNumber;
12use Phpdftk\Pdf\Core\PdfObject;
13use Phpdftk\Pdf\Core\PdfString;
14use Phpdftk\Pdf\Core\PdfVersion;
15use Phpdftk\Pdf\Core\RequiresPdfVersion;
16
17/**
18 * Encryption dictionary (/Type /Encrypt) — ISO 32000-2 §7.6.
19 *
20 * This is the **object-model** representation only. It serializes to a
21 * spec-compliant dictionary but is not wired into `PdfWriter`'s trailer
22 * or into per-object string/stream encryption — callers implementing
23 * actual encryption are responsible for driving the {@see
24 * \Phpdftk\Crypt\PdfKeyDerivation} primitives and patching the writer
25 * output themselves. This distinction is deliberate so the object model
26 * stays usable for libraries that want to emit encryption metadata
27 * without phpdftk taking over the crypto pipeline.
28 *
29 * Covers both the Standard security handler (Table 21) and the
30 * Public-key handler (Table 26), plus the shared crypt filter entries.
31 */
32#[RequiresPdfVersion(PdfVersion::V1_1)]
33class EncryptDictionary extends PdfObject
34{
35    public const PDF_TYPE = 'Encrypt';
36
37    // ---------- Common entries (Table 20) ----------
38    public PdfName $filter;                   // /Filter     required (e.g. Standard, Adobe.PubSec)
39    public ?PdfName $subFilter = null;        // /SubFilter
40    public int $v;                            // /V          algorithm version
41    public ?int $length = null;               // /Length     key length in bits (multiple of 8)
42    public ?PdfDictionary $cf = null;         // /CF         crypt filter dict
43    public ?PdfName $stmF = null;             // /StmF
44    public ?PdfName $strF = null;             // /StrF
45    public ?PdfName $eff = null;              // /EFF        filter for embedded files
46
47    // ---------- Standard handler (Table 21) ----------
48    public ?int $r = null;                    // /R          revision (2..6)
49    public ?PdfString $o = null;              // /O          owner password string
50    public ?PdfString $u = null;              // /U          user password string
51    public ?PdfString $oe = null;             // /OE         owner encryption key (R=6)
52    public ?PdfString $ue = null;             // /UE         user encryption key (R=6)
53    public ?int $p = null;                    // /P          permissions bitfield
54    public ?PdfString $perms = null;          // /Perms      encrypted perms (R=6)
55    public ?bool $encryptMetadata = null;     // /EncryptMetadata
56
57    // ---------- Public-key handler (Table 26) ----------
58    public ?PdfArray $recipients = null;      // /Recipients
59
60    public function __construct(string $filter = 'Standard', int $v = 2)
61    {
62        $this->filter = new PdfName($filter);
63        $this->v = $v;
64    }
65
66    public function toPdf(): string
67    {
68        $dict = new PdfDictionary();
69        $dict->set('Filter', $this->filter);
70        if ($this->subFilter !== null) {
71            $dict->set('SubFilter', $this->subFilter);
72        }
73        $dict->set('V', new PdfNumber($this->v));
74        if ($this->length !== null) {
75            $dict->set('Length', new PdfNumber($this->length));
76        }
77        if ($this->cf !== null) {
78            $dict->set('CF', $this->cf);
79        }
80        if ($this->stmF !== null) {
81            $dict->set('StmF', $this->stmF);
82        }
83        if ($this->strF !== null) {
84            $dict->set('StrF', $this->strF);
85        }
86        if ($this->eff !== null) {
87            $dict->set('EFF', $this->eff);
88        }
89        if ($this->r !== null) {
90            $dict->set('R', new PdfNumber($this->r));
91        }
92        if ($this->o !== null) {
93            $dict->set('O', $this->o);
94        }
95        if ($this->u !== null) {
96            $dict->set('U', $this->u);
97        }
98        if ($this->oe !== null) {
99            $dict->set('OE', $this->oe);
100        }
101        if ($this->ue !== null) {
102            $dict->set('UE', $this->ue);
103        }
104        if ($this->p !== null) {
105            $dict->set('P', new PdfNumber($this->p));
106        }
107        if ($this->perms !== null) {
108            $dict->set('Perms', $this->perms);
109        }
110        if ($this->encryptMetadata !== null) {
111            $dict->set('EncryptMetadata', new PdfBoolean($this->encryptMetadata));
112        }
113        if ($this->recipients !== null) {
114            $dict->set('Recipients', $this->recipients);
115        }
116        return $dict->toPdf();
117    }
118}