mikehaertl / phpwkhtmltopdf

A slim PHP wrapper around wkhtmltopdf with an easy to use and clean OOP interface
MIT License
1.6k stars 238 forks source link

PDF works but Image doesn't #371

Closed transcendtient closed 3 years ago

transcendtient commented 3 years ago

Simple as that...

AFTER commenting out the content-length header lines.

            //from File.php
            // #84: Content-Length leads to "network connection was lost" on iOS
            //$isIOS = preg_match('/i(phone|pad|pod)/i', $userAgent);
            //if (!$isIOS) {
            //    $headers['Content-Length'] = filesize($this->_fileName);
            //}

This works perfectly.

    $pdf = new Pdf(array(
        'no-outline',         // Make Chrome not complain
        'margin-top'    => 0,
        'margin-right'  => 0,
        'margin-bottom' => 0,
        'margin-left'   => 0,
        //'dpi' => 600,

        // Default page options
        'user-style-sheet' => $base_url.'/css/formpage.css',
        'user-style-sheet' => $base_url.'/css/print.css',
        //'disable-smart-shrinking'
    ));

    $pdf->addPage('http://google.com');

    if (!$pdf->send()) {
        $error = $pdf->getError();
        // ... handle error here
        // ... handle error here
        var_dump($error);
    }

I've also set $delete = false; in File.php and the temporary file it generates is always deleted whether I try PDF or Image. I was trying to see if the file generated has problems on the server but it was always deleted.

The code code below gives "cannot be displayed because it contains errors" on the webpage. I've printed out the command it executes and that works fine if I run it from the terminal.

        $image = new Image('http://google.com');
    if (!$image->send()) {
        $error = $image->getError();
        // ... handle error here
        var_dump($error);
    }
mikehaertl commented 3 years ago

Have you enabled compression in your Webserver (Nginx or Apache)? If so, this will create a mismatch with the Content-Length header we set here. But without that header there will be no download progress bar in the browser.

mikehaertl commented 3 years ago

Also what happens if you use $image->saveAs() to save the image somewhere and then download that saved file?

transcendtient commented 3 years ago

1) Yes I have deflate enabled. 2) saveAs() works.

Below works as well.

    $imageData = base64_encode($image->toString());

    // Format the image SRC:  data:{mime};base64,{data};
    $src = 'data: '.mime_content_type($image).';base64,'.$imageData;

    // Echo out a sample image
    echo '<img src="' . $src . '">';
mikehaertl commented 3 years ago

You could try to exclude the download URL from the deflate module

transcendtient commented 3 years ago

I'll be honest I don't really mind that the progress bar doesn't work unless that content-length header is causing my issue.

transcendtient commented 3 years ago

I did go ahead and add the following to my apache config file and uncommented the content-length lines. I restarted apache and had the same problem using send() for PDF and Image files.

        SetEnvIf Request_URI ^/tmp/ no-gzip=1

        <FilesMatch ".(png|pdf)">
                SetEnv no-gzip 1
        </FilesMatch>

So to reiterate, if I comment out the content-length lines, send() and send("filename") in Pdf.php works, send() and send("filename") in Image.php doesn't.

transcendtient commented 3 years ago

I've found a rule that allows using the content-length lines. Still not getting any Image with send().

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI "\.(?:pdf|png)$" no-gzip

I actually only need the line SetOutputFilter DEFLATE, SetEnvIfNoCase Request_URI "\.(?:pdf|png)$" no-gzip is superfluous which makes no sense to me at all.

mikehaertl commented 3 years ago

Related:

I may consider removing Content-Length but have to verify why it was there in the first place. All that download logic really starts to give me headaches.

mikehaertl commented 3 years ago

@transcendtient What is your download URL that you use with send()? Does it really end with .png? I'd rather expect some PHP file. In that case the SetEnvIfNoCase rule won't match. But I'm no expert on Apache settings either.

mikehaertl commented 3 years ago

@transcendtient I totally forgot a feature in one of the latest changes. You can suppress Content-Length, if you really want:

$image->send('name.png', false, [
    'Content-Length' => false,
]);

Could you try that? If you find a working setup with SetEnvIfNoCase I'd also be interested to know. I'd add it to the README.

mikehaertl commented 3 years ago

@transcendtient I'd also like to hear your feedback on a change I made to the README that adresses this issue. See the PR linke above here.

transcendtient commented 3 years ago

"If you find a working setup with SetEnvIfNoCase..." I probably won't pursue the issue since SetOutputFilter DEFLATE somehow works.

"I'd also like to hear your feedback on a change I made to the README" It's definitely something that should be documented. I don't see those changes have been pushed to the README.

What I'm doing as my workaround: At this point I'm staging files in my own temporary folder and cleaning it up with a cron job. The process is pretty heavyweight so cacheing a temporary file is probably the better way to go about it anyway.

TL;DR I'm working around the issue with saveAs().

mikehaertl commented 3 years ago

It's definitely something that should be documented. I don't see those changes have been pushed to the README.

I was waiting for your feedback before merging. The changes are here: https://github.com/mikehaertl/phpwkhtmltopdf/pull/372/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R265