dompdf icon indicating copy to clipboard operation
dompdf copied to clipboard

Loading assets by path is not working

Open koertho opened this issue 4 years ago • 8 comments

Hi. First of all, thanks for this library. It worked for me wonderfull with images and external css files when using remote_enabled.

But here comes my problem: in our company we have a development setup, where we couldn't load the resources like this, so I hoped to reference the images and css files by path from the local file system. But I always get Image not found or type unknown (for images). The same images works if remote is enabled, so there seems to be a path problem.

Here is a testing code, none of the images is working:

$options = new Options();
$options->setChroot('/home/dev/Kunden/.../produkte/contao');
$dompdf = new Dompdf();
$dompdf->loadHtml('<p>hello world</p>
<img src="files/media/news/partner-logos/image.png">
<img src="file://files/media/news/partner-logos/image.png">
<img src="/home/dev/Kunden/.../produkte/contao/files/media/news/partner-logos/image.png">
<img src="/home/dev/Kunden/.../produkte/contao/web/files/media/news/partner-logos/image.png">
<img src="file:///home/dev/Kunden/.../produkte/contao/files/media/news/partner-logos/image.png">
<img src="file:///home/dev/Kunden/.../produkte/contao/web/files/media/news/partner-logos/image.png">
');
 
$dompdf->setPaper('A4');
$dompdf->render();
$dompdf->stream('file', ['Attachment' => 0]);

Explanation: I tested relative and absolute path. The files within the web folder are symlinked. I also tried the setProtocol and setBasePath options, but they are not working (they are reseted within the code before the image processing starts).

Options (before calling the stream method):

rootDir = "/home/dev/Kunden/.../produkte/contao/vendor/dompdf/dompdf"
tempDir = "/tmp"
fontDir = "/home/dev/Kunden/.../produkte/contao/vendor/dompdf/dompdf/lib/fonts"
fontCache = "/home/dev/Kunden/.../produkte/contao/vendor/dompdf/dompdf/lib/fonts"
chroot = {array} [1]
    0 = "/home/dev/Kunden/.../produkte/contao"
logOutputFile = "/tmp/log.htm"
defaultMediaType = "screen"
defaultPaperSize = "letter"
defaultPaperOrientation = "portrait"
defaultFont = "serif"
dpi = {int} 96
fontHeightRatio = {float} 1.1
isPhpEnabled = false
isRemoteEnabled = false
isJavascriptEnabled = true
isHtml5ParserEnabled = false
isFontSubsettingEnabled = true
debugPng = false
debugKeepTemp = false
debugCss = false
debugLayout = false
debugLayoutLines = true
debugLayoutBlocks = true
debugLayoutInline = true
debugLayoutPaddingBox = true
pdfBackend = "CPDF"
pdflibLicense = ""

I also don't want to base64 encode the images, as also css files not working, I hope for a better solution. Do you have an idea where I go wrong?

Dompdf 1.0.2 PHP 7.4.16

koertho avatar May 11 '21 07:05 koertho

At a high level this looks OK. Just to confirm the basic requirements: do you have the GD extension enabled and does the running script has read/write access to the tmp directory?

Have you tried a JPG image? Those can be inserted into the PDF without any extra processing.

bsweeney avatar May 13 '21 12:05 bsweeney

I will look into your questions in the next days, but I can confirm the same images have worked when I used the remote option, so Gd and tmp should work. When I used phpunit to debug, I stumbled over this line, where the protocol is always http, even if remote is disabled and there is no http in the file path (as shown above): https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Image/Cache.php#L68

koertho avatar May 13 '21 20:05 koertho

I think it is better to have a dev server so you could load your assets from there instead, as a workaround.

fd6130 avatar May 14 '21 15:05 fd6130

Hi, now I'm able to answer your questions: GD library is installed in version 2.3.0. Script has read/write access to tmp folder I also tried with jpg image, same result.

I think it is better to have a dev server so you could load your assets from there instead, as a workaround.

Sure, load the images from another server would be possible. But that would not solve the problem that loading images from paths not work (which is IMHO a bug of this library) and would lead to the point that dompdf is hard to use in a reusable way for multi project extensions.

koertho avatar May 17 '21 07:05 koertho

Hi, I've digged a little deeper on this topic. My problem described above was due symlinks resolved by the library and the real paths weren't in the chroot. Is realpath real needed here? https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Image/Cache.php#L126

If I add the symlinked path, it works with image also with remote set to false. But then I have problems with the base tag and external css files. If I set a base tag, images won't work again, but css files work. Without a base tag images work, but css files won't. Image won't work with a base tag cause the protocol is set here, if a base tag is defined: https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Dompdf.php#L607 This lead to an error in combination with remote disabled here: https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Image/Cache.php#L68 https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Image/Cache.php#L77

But without a base tag, css files are not loaded correctly from filesystem cause the library tries to get the real path from the relative path of the filesystem here: https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Css/Stylesheet.php#L372

koertho avatar May 19 '21 11:05 koertho

I have the exact same issue. In my opinion this is a bug in the Cache::resolve_url method.

This check: https://github.com/dompdf/dompdf/blob/0ccafeb142dd04f556b43f1e8b5541aa06de1c26/src/Image/Cache.php#L129 leads to an exception showing the "image not found" error in PDF files, if the file is locally referenced, because it is pretty likely not in the root path if the library installation.

If I just skip this check, everything seems to work fine. I don't understand what it's all about with chroot and in which case the check should make sense, but it does prevent rendering images referenced locally.

Even worse, since this is a static call, I did not find a way to overcome this issue by adding some options, extending classes or even override autoloading to use my own class instead of \Dompdf\Image\Cache...

sandreas avatar Aug 04 '21 22:08 sandreas

I have the same problem. If I add the image path to chroot option, it works.

$options = new Options();
$options->setChroot(['/user/home/public/img/']);
$dompdf->setOptions($options);

rezaf-dev avatar Jan 29 '22 09:01 rezaf-dev

@rezaf-dev You, sir, are my hero! I was having a problem with my PHP app, it wouldn't load a logo no matter what path I used. Setting the root to / has solved my issue. Thanks so much!

drelich avatar May 21 '22 14:05 drelich

@bsweeney I am dealing with the same issue. We are using always fully qualified realpaths for our assets and they do not get loaded. I was now setting the root to "/" which solved my issue but should the fully qualified path not override the root setting? Is this a security concern or why is it handled like this?

roberthenniger avatar Nov 22 '22 16:11 roberthenniger

@roberthenniger I don't quite follow? Are you saying you set the chroot option to "/"? The paths you specify for your assets, fully qualified or not, once the path is normalized should fall under the paths specified for the chroot option. So if your path is something like "/path/to/assets/image.png" then you could set you your chroot option to "/path/to/assets".

bsweeney avatar Nov 28 '22 13:11 bsweeney

Closing this issue since the problem resolution is to set the chroot option with all the potential local paths for asset references.

bsweeney avatar Nov 28 '22 13:11 bsweeney