phppdftkphp-pdftk

Using the mikehaertl\php-pdftk library for manipulating PDFs, chaining commands fails when getDataFields is called first


I'm attempting to create a wrapper class around the mikehaertl\php-pdftk\pdf object for the purposes of populating PDF form fields. When trying to chain commands via the documentation the pdf fails to correctly execute the second command (or any after the first). It looks as though this is an issue with the underlying temp file handling and the tmep file not being written out as I watch my temp folder. As I debug, the temp file is there, but of 0 size.

Sample code demonstrating the issue

use mikehaertl\pdftk\Pdf;
class PDFTKTest extends TestCase
{
    public function testPdfTkOperations()
    {
        $cmdPath = 'D:\PDFtk\bin\pdftk.exe';
        $formPath = 'D:\test\sample_files\test.pdf';
        $options = ['command' => $cmdPath];

        $pdf = new Pdf($formPath, $options);

        $this->assertNotNull($pdf);

        //Get fields from PDF
        $fields = $pdf->getDataFields();
        $this->assertNotNull($fields);

        //Set some field Values
        $values = ['full_name' => 'John Q. Programmer'];
        $pdf2 = new Pdf($pdf, $options); //chaining broken
        //$pdf2 = new Pdf($formPath, $options); //works fine creating a new Pdf object
        $this->assertNotNull($pdf2);

        $res = $pdf2->fillForm($values)->execute();
        //Next assertion fails using chaining
        $this->assertTrue($res, "Execute failed: \n". $pdf2->getError());

        //Get fields with the updates
        $fields = $pdf2->getDataFields();
        $this->assertNotNull($fields);
        //Next assertion fails, getDataFields fails on a chained command
        $this->assertGreaterThan(0, count($fields));
    }
}

I've got a work around where I use separate \Pdf objects for each action and manage my own temp file, I was just hoping to take advantage of the classes functionality a bit more and not have to do so much of the mundane. Is this functionality broken, or am I using it incorrectly?


Solution

  • After looking deeper in to the PDFTK library which mikehaertl\php-pdftk\pdf wraps and reading the documentation on the dump_data_fields option I came up with the folowing observations:

    1. PDFTK doesn't produce an output file for the dump_data_fields command
    2. The php-pdftk class does create the underlying temp file when calling getDataFields, but it is empty and remains that way.
    3. When chaining another Pdf object, it references the empty temp file from the previous command. Here lies the rub.

    Solution

    When I call getFieldData I create a new Pdf object and chain it to the previous, however I don't save a reference to that. I only save the newly chained object if it is form a command that creates actual output.

    Here's an exmaple to demonstate:

    <?php
    use mikehaertl\pdftk\Pdf;
    
    class PDFTKFormService
    {
        protected $pdf = null;
    
        /**
        * @return array|bool|\mikehaertl\pdftk\DataFields
        */
        public function getDataFields()
        {
            //get data fields doesn't output a new file
            //so we need to use the existing instance or create a new one and
            $pdf = $this->getNextPdf();
            $fields = $pdf->getDataFields();
            if ($fields === false)
                return [];
            return $fields;
        }
    
        /**
         * @param array $data
         *
         * @return resource The stream resource
         */
        public function setDataFieldValues($data = [])
        {
            $this->pdf = $this->getNextPdf();
            $this->pdf->fillForm($data)->execute();
        }
    
        protected function getNextPdf()
        {
            $options = ['command' => 'Path\To\PDFTK\binary'];
    
            if ($this->pdf === null) {
                return new Pdf($this->getTemplatePath(), $options);
            } else {
                return new Pdf($this->pdf, $options);
            }
        }
    }
    

    Hopefully this can help someone else.