Skip to main content

Calling Puppeteer via PHP

My Puppeteer screenshot script stopped working recently and it took me a while to figure out why. The script had been working fine, although it was a bit fiddly to set-up and never really felt very robust. In hindsight, I'm not sure how it ever worked, given what was required to get it fixed.

Anyhow, the script is pretty basic and its job is to take a screenshot of a website. The script is called whenever I create a bookmark and tag it with 'inspiration', I can also call it manually when I want to attach a screenshot to some content.

My website is written PHP using the CodeIgniter framework and I call the Puppeteer script inside a custom library/class using PHP's builtin exec function. The PHP code looks like this:

$command = '/usr/bin/node ' . ROOTPATH . 'misc/node-puppeteer-screenshot/screenshot.js';
$img = $prefix . md5($url) . '.png';
$img_path = WRITEPATH . 'uploads/tmp/' . $img;
// Run the NodeJS screenshot script
$result = exec(
    command: sprintf(
    $command . " '%s' '%s' '%s' '%s'",
    escapeshellcmd($url),
    escapeshellcmd($img_path),
    escapeshellcmd($width),
    escapeshellcmd($height)
   ),
    result_code: $exit_code
);

And the JavaScript looks like this:

const puppeteer = require('puppeteer');

(async() => {
    let width = process.argv[4];
    let height = process.argv[5];

    if(width === undefined){
        width = 1280;
    }

    if(height === undefined){
        height = 720;
    }

    const browser = await puppeteer.launch({
        args: ['--no-sandbox', '--disable-setuid-sandbox'],
        headless: 'true',
        defaultViewport: {
            width: parseInt(width),
            height: parseInt(height),
        },
        executablePath: '/usr/bin/chromium',
    });

    const page = await browser.newPage();
    await page.goto(process.argv[2], {
        waitUntil: 'load',
    });
    await page.screenshot({
        captureBeyondViewport: false,
        path: process.argv[3],
    });

    await browser.close();
})();

The PHP script passes 4 arguments to the JavaScript:

  • URL - the address of the website to take a screenshot of
  • Path - location to save the image to
  • Width - width of the image in pixels
  • Height - height of the image in pixels

As I mentioned, the script was working fine, but then it stopped working. The error messages produced by the script were not too helpful, and interestingly, the Puppeteer script worked fine when I ran it directly under my user account. The script also worked when run as root. So, I figured the issue had to be with the Apache user under Debian.

Turns out, the Apache user www-data does not respect the XDG Base Directory Specification, which is to be expected, but this meant that Chromium was unable to start. I fixed the error by exporting the required environment variables in the PHP script directly before calling the JavaScript. The PHP now looks like this:

$command = 'export XDG_CONFIG_HOME=/tmp/.chromium && ';
$command .= 'export XDG_CACHE_HOME=/tmp/.chromium && ';
$command .= '/usr/bin/node ' . ROOTPATH . 'misc/node-puppeteer-screenshot/screenshot.js';
$img = $prefix . md5($url) . '.png';
$img_path = WRITEPATH . 'uploads/tmp/' . $img;
// Run the NodeJS screenshot script
$result = exec(
    command: sprintf(
    $command . " '%s' '%s' '%s' '%s'",
    escapeshellcmd($url),
    escapeshellcmd($img_path),
    escapeshellcmd($width),
    escapeshellcmd($height)
   ),
    result_code: $exit_code
);

I thought I'd write a quick blog post about this, just in case anyone else encounters a similar issue; hopefully I can save them some debugging time.

View as: JSON Markdown

If you enjoyed this post or found it useful, you can subscribe to my RSS feed.

Similar posts

  1. How to install PHP extension for Microsoft SQL Server under Fedora

    I found myself needing to connect to a Microsoft SQL Server via a PHP application running under Fedora. Finding concise details about installing the necessary drivers and extensions was not easy, so here is a blog post detailing how I did it.

    php microsoft fedora mssql sql linux
  2. How to set-up WatchGuard VPN with IKEv2 under Debian and Fedora

    A blog post detailing how to set-up WatchGuard VPN with IKEv2 under both Debian and Fedora Linux. This guide works for me under Debian 12 (bookworm) and Fedora 40/41, but your mileage may vary depending on how your VPN service is configured.

    debian vpn watchguard ikev2 fedora ipsec
  3. My Debian 12 (bookworm) server set-up

    I've been running Debian on my servers for years. It's dependable. I guess my server set-up is pretty common, consisting of Apache, PHP and MariaDB, but I figure it is still worth sharing details of how I provision my servers.

    php composer mariadb apache debian linux node fish
  4. My Debian 12 (bookworm) desktop set-up

    Creating a good Debian desktop experience is not too difficult, thanks to the excellent work of the Debian developers, but I thought it might be interesting to share how I set-up my Debian systems.

    debian linux
  5. How to add a custom search engine to Firefox

    I thought it would be trivial to add a custom search engine to Firefox. To be fair, it is fairly trivial, but not quite as easy as navigating to the correct Firefox settings page and adding a new entry. Instead, I found the process to be somewhat hidden and less obvious.

    opensearch search firefox mozilla php
  6. Switching desktop Linux from Debian to Fedora

    Last week I switched the operating system on my daily driver (Lenovo ThinkPad T14s) from Debian 12 to Fedora 40. In this post I write a little about why I switched and how the switch went.

    debian linux fedora
  7. Firefox Nightly as a daily driver

    I believe that it's really important to support and use Firefox. Not only do I think that Mozilla understand/support user's privacy more than Google, but I also think it's important for the health of the web that more than one option exists when it comes to rendering engines. Also, it's a really good web browser.

    debian chrome firefox mozilla
  8. Single computing device lifestyle

    I've recently decided to simplify my life by moving away from using multiple computers to using a single laptop. What are the main advantages and disadvantages of using a single computer?

    debian thinkpad
  9. Redux

    As a web developer, I like to build and rebuild websites. My own website is no different.

    markdown fediverse mastodon codeigniter php bootstrap jquery debian
  10. How to create Bash aliases in Fedora

    Creating your own Bash aliases is a relatively easy process. That said, I recently switched my desktop linux distribution from Debian to Fedora and there are subtle differences.

    linux fedora debian bash