| Server IP : 139.59.63.204 / Your IP : 216.73.217.62 Web Server : Apache/2.4.58 (Ubuntu) System : Linux ubuntu-s-1vcpu-1gb-blr1-01 6.8.0-110-generic #110-Ubuntu SMP PREEMPT_DYNAMIC Thu Mar 19 15:09:20 UTC 2026 x86_64 User : root ( 0) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/abyogasms.com/vendor/tecnickcom/tc-lib-pdf/examples/ |
Upload File : |
<?php
/**
* E057_multisignature_incremental.php
*
* @since 2026-05-01
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
// NOTE: run make deps fonts in the project root to generate the dependencies and example fonts.
// autoloader when using Composer
require __DIR__ . '/../vendor/autoload.php';
// define fonts directory
\define('K_PATH_FONTS', \realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
/**
* Demonstrate a multi-signature approval flow.
*
* In a real approval workflow a document typically accumulates one signature
* per approver in sequence (incremental signatures). tc-lib-pdf supports this
* pattern by:
*
* 1. setSignature() – primary signing certificate (author / certifier)
* 2. setSignatureAppearance() – visible widget for the primary signature
* 3. addEmptySignatureAppearance() – empty widget placeholders for each subsequent approver
*
* The primary signature field (cert_type 2 = MDP/Author) locks the document
* against further modifications while still permitting subsequent approvals to
* fill in the reserved empty fields.
*
* This example creates a 3-page document:
* Page 1 – contract / document body
* Page 2 – approval form with 3 signature fields:
* · Author (primary – pre-signed by the library)
* · Reviewer (empty approval field)
* · Manager (empty approval field)
* Page 3 – signing guide / workflow description
*/
$certPath = \realpath(__DIR__ . '/data/cert/tcpdf.crt');
if ($certPath === false) {
throw new \RuntimeException('Missing signing certificate: examples/data/cert/tcpdf.crt');
}
$cert = 'file://' . $certPath;
// main TCPDF object
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
unit: 'mm',
isunicode: true,
subsetfont: false,
compress: true,
mode: '',
objEncrypt: null,
);
$pdf->setCreator('tc-lib-pdf');
$pdf->setAuthor('Nicola Asuni');
$pdf->setSubject('tc-lib-pdf example: 057');
$pdf->setTitle('Multi-Signature Approval Flow');
$pdf->setKeywords('TCPDF tc-lib-pdf example signature approval multi-signature incremental');
$pdf->setPDFFilename('E057_multisignature_incremental.pdf');
$pdf->enableDefaultPageContent();
$bfont = $pdf->font->insert($pdf->pon, 'helvetica', '', 10);
$bfontB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 12);
// -----------------------------------------------------------------------
// Page 1 – Document body (contract)
// -----------------------------------------------------------------------
$page1 = $pdf->addPage();
$pdf->page->addContent($bfontB['out']);
$pdf->page->addContent($pdf->getTextCell(
txt: 'SERVICE AGREEMENT EXAMPLE',
posx: 15,
posy: 15,
width: 180,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'C',
));
$pdf->page->addContent($bfont['out']);
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
$html1 = <<<HTML
<p>This Service Agreement ("Agreement") is entered into as of the date of the last signature below
between <strong>Client</strong> and <strong>Service Provider</strong>.</p>
<p><b>1. Services.</b> Service Provider agrees to deliver software development services as described
in Schedule A attached hereto.</p>
<p><b>2. Payment.</b> Client agrees to pay the fees set forth in Schedule B within 30 days of invoice.</p>
<p><b>3. Term.</b> This Agreement commences on the Effective Date and continues for 12 months unless
earlier terminated by either party upon 30 days written notice.</p>
<p><b>4. Confidentiality.</b> Each party agrees to keep the other party's confidential information
strictly confidential and not to disclose it to any third party without prior written consent.</p>
<p><b>5. Governing Law.</b> This Agreement shall be governed by the laws of the applicable jurisdiction.</p>
<p>The parties have executed this Agreement as of the dates indicated in the signature fields on
the following page.</p>
HTML;
$pdf->addHTMLCell(html: $html1, posx: 15, posy: 30, width: 180);
// -----------------------------------------------------------------------
// Page 2 – Approval / signature form
// -----------------------------------------------------------------------
$page2 = $pdf->addPage();
$pdf->page->addContent($bfontB['out']);
$pdf->page->addContent($pdf->getTextCell(
txt: 'SIGNATURE PAGE EXAMPLE',
posx: 15,
posy: 15,
width: 180,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'C',
));
$pdf->page->addContent($bfont['out']);
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
$pdf->page->addContent($pdf->getTextCell(
txt: 'The following parties have reviewed and approved this Agreement:',
posx: 15,
posy: 30,
width: 180,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'L',
));
// Signature box helper labels (rendered as PDF text cells)
$labels = [
['role' => 'Author / Certifier', 'name' => 'John Doe', 'y' => 45],
['role' => 'Reviewer', 'name' => '(awaiting sig.)', 'y' => 90],
['role' => 'Manager', 'name' => '(awaiting sig.)', 'y' => 135],
];
foreach ($labels as $lbl) {
$pdf->page->addContent($bfontB['out']);
$pdf->page->addContent($pdf->getTextCell(
txt: $lbl['role'],
posx: 15,
posy: (float) $lbl['y'],
width: 85,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'L',
));
$pdf->page->addContent($bfont['out']);
$pdf->page->addContent($pdf->getTextCell(
txt: 'Name: ' . $lbl['name'],
posx: 15,
posy: (float) ($lbl['y'] + 7),
width: 85,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'L',
));
$pdf->page->addContent($pdf->getTextCell(
txt: 'Date: ___________________',
posx: 15,
posy: (float) ($lbl['y'] + 14),
width: 85,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'L',
));
}
// -----------------------------------------------------------------------
// Register the primary (author/certifier) digital signature.
// cert_type = 2 → MDP / author signature
// -----------------------------------------------------------------------
$pdf->setSignature([
'cert_type' => 2,
'info' => [
'ContactInfo' => 'https://github.com/tecnickcom/tc-lib-pdf',
'Location' => 'Demo Office',
'Name' => 'John Doe',
'Reason' => 'Author / certifier signature – approval workflow example',
],
'password' => '',
'privkey' => $cert,
'signcert' => $cert,
]);
// Primary signature appearance – placed on page 2 at the first slot.
$pdf->setSignatureAppearance(posx: 100, posy: 45, width: 90, heigth: 35, page: $page2['pid'], name: 'Author');
// Empty approval fields for the remaining approvers.
$pdf->addEmptySignatureAppearance(posx: 100, posy: 90, width: 90, heigth: 35, page: $page2['pid'], name: 'Reviewer');
$pdf->addEmptySignatureAppearance(posx: 100, posy: 135, width: 90, heigth: 35, page: $page2['pid'], name: 'Manager');
// -----------------------------------------------------------------------
// Page 3 – Workflow guide
// -----------------------------------------------------------------------
$page3 = $pdf->addPage();
$pdf->page->addContent($bfontB['out']);
$pdf->page->addContent($pdf->getTextCell(
txt: 'Multi-Signature Workflow Guide',
posx: 15,
posy: 15,
width: 180,
height: 0,
offset: 0,
linespace: 1,
valign: 'T',
halign: 'L',
));
$pdf->page->addContent($bfont['out']);
$pdf->font->insert($pdf->pon, 'helvetica', '', 10);
$html3 = <<<HTML
<p><b>How incremental multi-signature works in tc-lib-pdf</b></p>
<p>A PDF approval workflow typically progresses through these steps:</p>
<ol>
<li><b>Author creates and certifies the document.</b>
The primary signature (Author field) is applied by <code>setSignature()</code> with
<em>cert_type 2</em> (MDP). This locks the document against structural changes
while reserving the empty approval fields for subsequent signers.</li>
<li><b>Reviewer opens the document, validates the Author signature, and applies their
signature to the Reviewer field.</b> In a PDF viewer (e.g. Acrobat) the reviewer
uses the reserved empty widget. Each subsequent signature is appended to the file
as an incremental update, preserving all prior signature data.</li>
<li><b>Manager repeats the same process for the Manager field.</b></li>
</ol>
<p><b>tc-lib-pdf API summary</b></p>
<table border="1" cellpadding="4" cellspacing="0">
<tr><th>Method</th><th>Purpose</th></tr>
<tr><td>setSignature()</td><td>Register the primary signing certificate and options.</td></tr>
<tr><td>setSignatureAppearance()</td><td>Visible widget for the primary signature.</td></tr>
<tr><td>addEmptySignatureAppearance()</td><td>Reserve an empty widget for a future approver.</td></tr>
<tr><td>setSignTimeStamp()</td><td>Optionally attach an RFC 3161 TSA timestamp (see E008).</td></tr>
</table>
<p><b>Certification levels (cert_type)</b></p>
<table border="1" cellpadding="4" cellspacing="0">
<tr><th>cert_type</th><th>Meaning</th></tr>
<tr><td>1</td><td>No changes permitted after signing.</td></tr>
<tr><td>2</td><td>Form fills and approval signatures permitted (MDP).</td></tr>
<tr><td>3</td><td>Annotations and form fills permitted.</td></tr>
</table>
HTML;
$pdf->addHTMLCell(html: $html3, posx: 15, posy: 30, width: 180);
// -----------------------------------------------------------------------
// Output
// -----------------------------------------------------------------------
$rawpdf = $pdf->getOutPDFString();
$pdf->renderPDF(rawpdf: $rawpdf);