Skip to content

lemsn/laravel-a1-pdf-sign

 
 

Repository files navigation

Sign PDF files with valid x509 certificate

Latest Stable Version Total Downloads Latest Unstable Version License

TL;DR


Install

Require this package in your composer.json and update composer. This will download the package and the dependencies libraries also.

composer require lsnepomuceno/laravel-a1-pdf-sign

Usage

Working with certificate

1 - Reading the certificate from file.

<?php

use LSNepomuceno\LaravelA1PdfSign\ManageCert;

class ExampleController() {
    public function dummyFunction(){
        try {
            $cert = new ManageCert;
            $cert->fromPfx('path/to/certificate.pfx', 'password');
            dd($cert->getCert());
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

2 - Reading the certificate from upload.

<?php

use Illuminate\Http\Request;
use LSNepomuceno\LaravelA1PdfSign\ManageCert;

class ExampleController() {
    public function dummyFunction(Request $request){
        try {
            $cert = new ManageCert;
            $cert->fromUpload($request->pfxUploadedFile, $request->password);
            dd($cert->getCert());
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

3 - The expected result will be as shown below.

Certificate

4 - Store certificate data securely in the database.

IMPORTANT: Store certificate column as binary data type
<?php

use App\Models\Certificate;
use LSNepomuceno\LaravelA1PdfSign\ManageCert;

class ExampleController() {
    public function dummyFunction(){
        try {
            $cert = new ManageCert;
            $cert->fromPfx('path/to/certificate.pfx', 'password');
        } catch (\Throwable $th) {
            // TODO necessary
        }
                
        // Postgres or MS SQL Server
        Certificate::create([
          'certificate' => $cert->getEncrypter()->encryptString($cert->getCert()->original) 
          'password'    => $cert->getEncrypter()->encryptString('password'),
          'hash'        => $cert->getHashKey(), // IMPORTANT
          ...
        ]);
        
        // For MySQL
        Certificate::create([
          'certificate' => $cert->encryptBase64BlobString($cert->getCert()->original) 
          'password'    => $cert->getEncrypter()->encryptString('password'),
          'hash'        => $cert->getHashKey(), // IMPORTANT
          ...
        ]);
    }
}

5 - Reading certificate from database.

<?php

use LSNepomuceno\LaravelA1PdfSign\ManageCert;
use Illuminate\Support\{Str, Facades\File};

class CertificateModel() {
    public function parse() {
        $cert = new ManageCert;
        $cert->setHashKey($this->hash);
        $pfxName = $cert->getTempDir() . Str::orderedUuid() . '.pfx';

        // Postgres or MS SQL Server
        File::put($pfxName, $cert->getEncrypter()->decryptString($this->bb_cert));
        
        // For MySQL
        File::put($pfxName, $cert->decryptBase64BlobString($this->bb_cert));
        
        try {
          return $cert->fromPfx(
              $pfxName,
              $cert->getEncrypter()->decryptString($this->password)
          );
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

Sign PDF File

1 - Sign PDF with certificate from file or upload.

<?php

use Illuminate\Http\Request;
use LSNepomuceno\LaravelA1PdfSign\{ManageCert, SignaturePdf};

class ExampleController() {
    public function dummyFunction(Request $request){
        
        // FROM FILE
        try {
            $cert = new ManageCert;
            $cert->fromPfx('path/to/certificate.pfx', 'password');
        } catch (\Throwable $th) {
            // TODO necessary
        }
        
        // FROM UPLOAD
        try {
            $cert = new ManageCert;
            $cert->fromUpload($request->pfxUploadedFile, $request->password);
            dd($cert->getCert());
        } catch (\Throwable $th) {
            // TODO necessary
        }
        
        // Returning signed resource string
        try {
            $pdf = new SignaturePdf('path/to/pdf/file.pdf', $cert->getCert(), SignaturePdf::MODE_RESOURCE) // Resource mode is default
            $resource = $pdf->signature();
            // TODO necessary
        } catch (\Throwable $th) {
            // TODO necessary
        }
        
        // Downloading signed file
        try {
            $pdf = new SignaturePdf('path/to/pdf/file.pdf', $cert->getCert(), SignaturePdf::MODE_DOWNLOAD)
            return $pdf->signature(); // The file will be downloaded
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

2 - Sign PDF with certificate from database (model based).

<?php

use Illuminate\Http\Request;
use App\Models\Certificate;
use LSNepomuceno\LaravelA1PdfSign\{ManageCert, SignaturePdf};

class ExampleController() {
    public function dummyFunction(Request $request){
        
        // Find certificate
        $cert = Certificate::find(1);
        
        // Returning signed resource string
        try {
            $pdf = new SignaturePdf('path/to/pdf/file.pdf', $cert->parse(), SignaturePdf::MODE_RESOURCE) // Resource mode is default
            $resource = $pdf->signature();
            // TODO necessary
        } catch (\Throwable $th) {
            // TODO necessary
        }
        
        // Downloading signed file
        try {
            $pdf = new SignaturePdf('path/to/pdf/file.pdf', $cert->parse(), SignaturePdf::MODE_DOWNLOAD)
            return $pdf->signature(); // The file will be downloaded
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

3 - The expected result in Adobe Acrobat/Reader will be as shown below.

Signed File

Helpers - signPdfFromFile(), signPdfFromUpload(), encryptCertData(), decryptCertData()

<?php

use Illuminate\Http\Request;

class ExampleController() {
    public function dummyFunction(Request $request){
    	// SIGNATURE FROM FILE
        try {
            signPdfFromFile('path/to/certificate.pfx', 'password', 'path/to/pdf/file.pdf');
        } catch (\Throwable $th) {
            // TODO necessary
        }
	
	// SIGNATURE FROM UPLOAD
        try {
            signPdfFromUpload($request->pfxUploadedFile, $request->password, 'path/to/pdf/file.pdf');
        } catch (\Throwable $th) {
            // TODO necessary
        }
		
	// ENCRYPT CERTIFICATE DATA
	// path/to/certificate.pfx or uploaded certificate file
	// return object with attr`s [hash, certificate, password]
        try {
            $encriptedCertificate = encryptCertData('path/to/certificate.pfx', 'password');
        } catch (\Throwable $th) {
            // TODO necessary
        }
	
	// DECRYPT THE CERTIFICATE DATA
        try {
	    decryptCertData($encriptedCertificate->hash, $encriptedCertificate->certificate, $encriptedCertificate->password);
        } catch (\Throwable $th) {
            // TODO necessary
        }
    }
}

💥 Is your project not Laravel / Lumen?

If you want to use this package in a project that is not based on Laravel / Lumen, you need to make the adjustments below

1 - Install dependencies to work correctly.

composer require illuminate/container illuminate/filesystem ramsey/uuid

2 - Prepare the code to launch the Container and FileSystem instance.

<?php

require_once 'vendor/autoload.php';

use Illuminate\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Facade;

try {
  $app = new Container();
  $app->singleton('app', Container::class);
  $app->singleton('files', fn () => new Filesystem);
  Facade::setFacadeApplication($app);
  
  // Allow the use of Facades, only if necessary
  // $app->withFacades();
} catch (\Throwable $th) {
  // TODO necessary
}

3 - After this parameterization, your project will work normally.

<?php

require_once 'vendor/autoload.php';

use Illuminate\Container\Container;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Facade;
use LSNepomuceno\LaravelA1PdfSign\ManageCert;

try {
  $app = new Container();
  $app->singleton('app', Container::class);
  $app->singleton('files', fn () => new Filesystem);
  Facade::setFacadeApplication($app);
  
  $cert = new ManageCert;
  $cert->fromPfx('path/to/certificate.pfx', 'password');
  var_dump($cert->getCert());
} catch (\Throwable $th) {
  // TODO necessary
}

Tests

Run the tests with:

composer run-script test

or

vendor/bin/phpunit

About

Sign PDF files with valid x509 certificate

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 100.0%