dealfonso / sapp

Simple and Agnostic PDF Document Parser in PHP - sign PDF docs using PHP
GNU Lesser General Public License v3.0
110 stars 29 forks source link

Got success message but didn't get the signed PDF #37

Closed brunohpaes88 closed 1 year ago

brunohpaes88 commented 1 year ago

Hi! I'm trying to sign a PDF document as a test, but my new PDF file don't have any signature.

This is my code:

<?php

require_once('vendor/autoload.php');

use ddn\sapp\PDFDoc;

$parameters = array(null, 'Google.pdf', 'certificate.pfx', 'mysignedfile.pdf');

if (!file_exists($parameters[1]))
    fwrite(STDERR, "failed to open file " . $parameters[1]);
else {
    $file_content = file_get_contents($parameters[1]);
    $obj = PDFDoc::from_string($file_content);

    if ($obj === false)
        fwrite(STDERR, "failed to parse file " . $parameters[1]);
    else {
        $obj->set_signature_certificate($parameters[3], "pfx_password");
        $docsigned = $obj->to_pdf_file_s();
        if ($docsigned === false)
            fwrite(STDERR, "could not sign the document");
        else
            try {
                $folder = 'downloads';

                if(!is_dir($folder)){
                   mkdir($folder,0775,true);
                } 

                if(file_put_contents('downloads/new_file.pdf', $docsigned)){
                    echo "Success";   
                } else {
                    echo "Error";
                }

            } catch(Exception $e){
                echo $e->getMessage();
            }
    }
}

When I run it using the URL I get the "Success" message and a new file is created, inside folder downloads, named "new_file.pdf". When I open this document using Adobe Acrobat for MacOS it looks like doesn't have any digital signature.

Where am I wrong?

Another weird situation, if I provide a wrong password for the PFX file I still get the success message.

brunohpaes88 commented 1 year ago

One more information: I used pdfsigni.php example and tried to add a visible signature on my file, and when I open it I found an empty space to sign. So, Adobe can recognize that this image is a signature field, but it doesn't have any signature in it.

parallels999 commented 1 year ago

Looks like a problem with your pfx, try with cert and pkey on pem

brunohpaes88 commented 1 year ago

I tried change from "certificate.pfx" to a PEM certificate that I have, and got same results :-(

parallels999 commented 1 year ago

Show how you did use pem? I test with pfx and with pkey and cert pem, and everything works

brunohpaes88 commented 1 year ago

Same way I was using PFX, but without password:

$obj->set_signature_certificate($parameters[3]); // This $parameters[3] has 'mycert.pem'

Am I missing something?

brunohpaes88 commented 1 year ago

This PEM was generated using this command line on MacOS Terminal:

openssl pkcs12 -in mycertificate.pfx -out mycert.pem -nodes

parallels999 commented 1 year ago

You are lost, allways read PHPDoc, it is not magic https://github.com/dealfonso/sapp/blob/7782f7f969268c877b9478f388ac8d5a19be2a33/src/PDFDoc.php#L283-L284

parallels999 commented 1 year ago

Maybe this not work on MacOS

brunohpaes88 commented 1 year ago

My bad, I really missed this.

But... still doesn't work. I get a new PDF with a signature field, but without any signature inside the document.

Captura de Tela 2022-11-03 às 20 30 50

When I click on this field it sends me to sign the document.

This PEM and PKEY files are working fine, I use them for another kind of signature (CMS/CADeS sign) and they are ok.

dealfonso commented 1 year ago

have you tried with different PDF files? Could you please attach the PDF file that is causing the problem?

dealfonso commented 1 year ago

From your code...

$parameters = array(null, 'Google.pdf', 'certificate.pfx', 'mysignedfile.pdf');
(...)
$obj->set_signature_certificate($parameters[3], "pfx_password");

$parameters[3] is 'mysignedfile.pdf' not the pfx file.

brunohpaes88 commented 1 year ago

Hi @dealfonso!

This is my test PDF. Google.pdf

I just printed a web page to test, it is very simple.

I changed this $parameters[3] to my PEM array in my last try, but still doesn't work. Here is my full code:

<?php

require_once('vendor/autoload.php');

use ddn\sapp\PDFDoc;

$cert = array('cert' => 'cert_wiseway.pem', 'pkey' => 'cert_wiseway_key.pem');
$parameters = array(null, 'Google.pdf', $cert, 'mysignedfile.pdf');

if (!file_exists($parameters[1]))
    fwrite(STDERR, "failed to open file " . $parameters[1]);
else {
    $file_content = file_get_contents($parameters[1]);
    $obj = PDFDoc::from_string($file_content);

    if ($obj === false)
        fwrite(STDERR, "failed to parse file " . $parameters[1]);
    else {
        $position = [ ];
        $image = 'https://www.google.es/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
        $imagesize = @getimagesize($image);
        if ($imagesize === false) {
            fwrite(STDERR, "failed to open the image $image");
            return;
        }
        $pagesize = $obj->get_page_size(0);
        if ($pagesize === false)
            return p_error("failed to get page size");

        $pagesize = explode(" ", $pagesize[0]->val());
        // Calculate the position of the image according to its size and the size of the page;
        //   the idea is to keep the aspect ratio and center the image in the page with a size
        //   of 1/3 of the size of the page.
        $p_x = intval("". $pagesize[0]);
        $p_y = intval("". $pagesize[1]);
        $p_w = intval("". $pagesize[2]) - $p_x;
        $p_h = intval("". $pagesize[3]) - $p_y;
        $i_w = $imagesize[0];
        $i_h = $imagesize[1];

        $ratio_x = $p_w / $i_w;
        $ratio_y = $p_h / $i_h;
        $ratio = min($ratio_x, $ratio_y);

        $i_w = ($i_w * $ratio) / 3;
        $i_h = ($i_h * $ratio) / 3;
        $p_x = $p_w / 3;
        $p_y = $p_h / 3;

        $obj->set_signature_appearance(0, [ $p_x, $p_y, $p_x + $i_w, $p_y + $i_h ], $image);

        $obj->set_signature_certificate($parameters[2]);
        $docsigned = $obj->to_pdf_file_s();
        if ($docsigned === false)
            fwrite(STDERR, "could not sign the document");
        else
            try {
                $folder = 'downloads';

                if(!is_dir($folder)){
                   mkdir($folder,0775,true);
                } 

                if(file_put_contents('downloads/new_file.pdf', $docsigned)){
                    echo "Success";   
                } else {
                    echo "Error";
                }

            } catch(Exception $e){
                echo $e->getMessage();
            }
    }
}

Also is attached the result PDF. new_file.pdf

brunohpaes88 commented 1 year ago

I'm still stucked with this, someone has any ideas about how to fix it? :-(

dealfonso commented 1 year ago

Hi,

I think that your problem has to do with your certificate. I get the same result than yours if I provide an invalid certificate or even an empty file.

Have you checked the result of set_signature_certificate? It will tell you wether your certificate is valid or not.

brunohpaes88 commented 1 year ago

Hi @dealfonso!

I tried with my original PFX file and IT WORKS! Probably when I copied the original one for my project it lost something, I have no idea what happened but the important is that right now it works!

Now I'll try to implement it inside my solution, but I'm really happy! You made my sunday happier, thanks!

Thanks @dealfonso and @parallels999 , you are great!

dealfonso commented 1 year ago

I am closing the issue as it seems to be solved.