mikehaertl/php-pdftk

Can not write to temp directory

PaulusMenheere opened this issue ยท 27 comments

Whenever I try to fill in a form using fillForm I get an error message stating
Error: Failed to open form data file: \n /tmp/php_pdftk_xfdf_uL6Hf2.xfdf\n No output created.
code:
$tempPdf = new \mikehaertl\pdftk\Pdf(__DIR__ . '/Mededelingsformulier_scheiding_2019_2.pdf'); $tempPdf->fillForm($arr = [ 'test' => 'test', ]); $tempPdf->saveAs(__DIR__ . '/tempfile.pdf'); $error = $tempPdf->getError(); $this->assertEquals('', $error);
All files are accessible, other functions work perfectly (getDataFileds, GenerateFdf)
I'm working with Laravel running on an updated Homestead vagrant instance using pdftk from a snap install.

Hmm, sounds weird. I'd still assume a permission problem with /tmp. Can you have a look at vendor/mikehaertl/php-tmpfile/src/File.php? It's a simple helper that creates temporary files and auto-deletes them when done (See here: https://github.com/mikehaertl/php-tmpfile). If you can, you could modify this file on the fly and add some debug output (e.g. if the file is really written in the constructor, etc).

I saw the file allready created in the /tmp folder. However: the command failed.
If I use the CLI of pdftk using the /tmp/path it failed too. So I assumed the xfdf was wrongly generated. if I copy the generated file out of the /tmp folder it works.... on the Commandline

Well, can you inspect the file? XFDF is an XML format, thus text based.

Yup, I even copied the executed command generated on /vendor/mikehaertl/php-shellcommand/src/Command.php:321
using the xfdf in the /tmp - Error
using the xfdf outside the /tmp - works as a charm

Sorry, misread your answer. So it seems, that when executing pdftk from PHP it has no permission to access the /tmp file. This is not the same like "PHP has no permission". It's rather "A shell process, started from PHP has no permission". I remember something like this with selinux or something.

Sorry, I can't help you much more here. You should try to find out, what permission restrictions are active on the system. Also maybe do some tests with exec() or proc_open() like ls -l /tmp/xyz.xfdf and see if that command works.

Okay, I now know what the error is.
pdftk is a bit outdated. I believe a version 3.0 is in the works using the open version of Java

However to install pdftk on a recent version of ubuntu is using snap. this will install it in a secure way so that it doesn't have access to the /tmp folder. That's why it's failing out of the box

sudo add-apt-repository ppa:malteworld/ppa
sudo apt update
sudo apt-get install pdftk 

This works. Maybe to put in your readme ? to avoid using the snaps (or you should rewrite parts of your code to generate fdf files outside of the /tmp folder

Hmm, yeah, I'm also using the version from malteworld. I've added a note to the README.

I'm just noting that I also ran into the problem that pdftk-from-snap-is-failing because it can't access the temp directory.

Im having this issue now on the latest Homestead. Any ideas? Totally lost, /tmp seems to be writeable so I dont get the issue.

@robmpreston The issue is that the snap format improves safety and security by whitelisting filesystem access to particular directories. Apparently the snap package for pdftk lacks permission to create tmp files, badly breaking it. This assumes you are using the snap for pdftk.

Would it help to make the temp directory configurable? Without looking at the code I think this is currently not so easy. I could add a feature that you can pass options to the underlying https://github.com/mikehaertl/php-tmpfile .

Im having this issue now on the latest Homestead. Any ideas? Totally lost, /tmp seems to be writeable so I dont get the issue.

I've copied a part of my after.sh script of my homestead installation. might provide you with a start to a solution...

#!/bin/sh

# If you would like to do some extra provisioning you may
# add any commands you wish to this file and they will
# be run after the Homestead machine is provisioned.

if [ ! -f /usr/local/extra_homestead_software_installed ]; then
	echo 'installing some extra software'

    sudo locale-gen nl_NL nl_NL.utf8

    sudo snap install pdftk
    sudo ln -s /snap/pdftk/current/usr/bin/pdftk /usr/bin/pdftk
    
    
    touch /usr/local/extra_homestead_software_installed
else    
    echo "extra software already installed... moving on..."
fi

I have this strange issue too,my tmp folder's chmod is 777 but not even this case is possible to write to there by pdftk

I don't understand why did you close this issue if it not solved.
I may find the issue.It is not because of not having permission to tmp folder.
The error occur when try to create the xpdf file.

The command is :

pdftk 'A'='/var/www/html/test/webroot/simply.pdf' 'fill_form' '/tmp/php_pdftk_xfdf_fmZ2ON.xfdf' 'output' '/tmp/tmp_php_pdftk_V763rq.pdf' 'drop_xfa' 'flatten'

when i run it from the terminal i got this:

Error: Failed to open form data file:
/tmp/php_pdftk_xfdf_fmZ2ON.xfdf
No output created.

Remove a few words from the command:
pdftk 'A'='/var/www/html/test/webroot/simply.pdf' 'output' '/tmp/tmp_php_pdftk_V763rq.pdf' 'drop_xfa' 'flatten'
this is a working command,it can write into the tmp folder.

What makes the error is
'fill_form' '/tmp/php_pdftk_xfdf_fmZ2ON.xfdf'
because no /tmp/php_pdftk_xfdf_fmZ2ON.xfdf' file created in tmp folder

This is what i know already but i am busy now with other things to solve totally.

I'm just noting that I also ran into the problem that pdftk-from-snap-is-failing because it can't access the temp directory.

snap only access to user's home directory

@Avemaar There's now a PR, where I've added an option that makes the temporary directory configurable:

#177

$pdf = new Pdf('/some/file.pdf');
$pdf->tempDir = '/home/mike/temp';

Can you (or anyone interested) help testing this please?

I still see people struggle to find a writeable directory. But that's really out of the scope of this library. We need a writeable directory or things just don't work. The library can't solve this.

If you want to test it you can install the version from the PR with this command:

composer require mikehaertl/php-pdftk:dev-master#007a63d29c65f39cde722c868a9c0b5ee38a5695

I am also running into the same error (using Laravel also).

Not sure if this is helpful, but I get the following when debugging using php artisan tinker both locally (working) and on another server (not working):

Local Environment

>>> $pdf = new Pdf(resource_path('files/pdf_templates/test.pdf'));
=> mikehaertl\pdftk\Pdf {#3304
     +ignoreWarnings: false,
     +tempDir: null,
   }
>>> $pdf->fillForm($mapping)->execute();
=> true
>>> $pdf->getError();
=> ""
>>>

Other Server

>>> $pdf = new Pdf(resource_path('files/pdf_templates/test.pdf'));
=> mikehaertl\pdftk\Pdf {#3367
     +ignoreWarnings: false,
   }
>>> $pdf->fillForm($mapping)->execute();
=> false
>>> $pdf->getError();
=> """
   Error: Failed to open form data file: \n
      /tmp/php_pdftk_xfdf_ZPMb4U.xfdf\n
      No output created.
   """
>>>

Even though it's the same code in each case, I do notice that there's an additional tempDir option set when running it locally. Not sure if that would have anything to do with it?

Note: Tried it with the dev-master version from the previous comment.

Following the suggestions above, manually setting the tempDir resolved the error. For those using Laravel Forge, this would look something like:

On the server:

cd /home/forge
mkdir tmp

and then in the code:

$pdf = new Pdf('/some/file.pdf');
$pdf->tempDir = '/home/forge/tmp';

Although now there is unrelated issue I'm currently wrestling with:

sh: 1: pdftk: not found

But I think that may because pdftk was installed using snap. This will require further debugging.

@jimhlad Let's summarize:

  • If you use the snap version:

    • the new tempDir option can help solving the issue with write permission as described under Shell Command in the README
    • you may also have to set the location of pdftk as described under Temporary File in the README
  • The (better) alternative is not to use the snap version but install pdftk as described by @PaulMenheere in his comment above:

    sudo add-apt-repository ppa:malteworld/ppa
    sudo apt update
    sudo apt-get install pdftk 
    

I've just released 0.8.0 including this change.

sudo ln -s /snap/pdftk/current/usr/bin/pdftk /usr/bin/pdftk

worked for me too....

Thanks @PaulMenheere , that command resolved the second issue I was having!

Combined with the code tweaks @mikehaertl made, I can confirm I am now able to fill & generate PDF forms.

I feel like I got insanely lucky with the timing here. Ran into this issue in the afternoon and then was surprised to see that there was already a PR an hour earlier. Thanks again!

okey i solved the issue, the php can not run pdftk command because the www-data has no permission to run script

@PaulMenheere's repo doesn't contain that package anymore

Hello, everybody. I'm a junior developer.
I have successfully used Pdftk locally following the suggestions here. Development with Laravel. It works locally, but it doesn't work online. Why? Thanks.
PS. The project is on a VPS with Ubuntu 18.4

$pdf = new PdfTk(storage_path().'/app/modelli/registri/registro_presenze.pdf',
[
'command' => '/usr/bin/pdftk',
'useExec' => true
]
);
$pdf-> tempDir = storage_path().'/tmp';
$pdf->fillForm([
'numero_registro' => $numero_registro
])
->flatten()
->execute();

$file = $pdf->getTmpFile();
$content = file_get_contents((string) $pdf->getTmpFile());
Storage::put('/registri/registro_'.$numero_registro.'.pdf', $content);

I found the solution. I was wrong to give permission to the tmp folder ;-)

Here's an update:

  • The version from ppa:malteworld/ppa is no longer available.
  • The maintainer now points to his answer on askubuntu: https://askubuntu.com/a/1028983/175814
  • For Ubuntu 18.10 and later you can install the pdftk-java package with apt
  • For Ubuntu 18.04 you can manually download that package for focal and still install it manually
  • If you didn't install with apt you probably end up with the snap version which has the write permission issue with the temp file. In that case you can also set an alternative tempDir.