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.

apache debian javascript node php

Comments

New Comment

If you have a comment you'd like to share, feel free to leave it below. I moderate all comments before they are published. Markdown is enabled. See syntax for help.


I'll never share your email with anyone else.

Blog

I mostly try to write non-opinionated posts about web development and Linux - reminders about how to complete tasks and get stuff done etc.

For short-form posts, see my status page.

Subscribe

Click the link below to subscribe to my Blog feed in your favourite news reader client:

RSS feed

Philip Newborough and a donkey enjoying a beer.

About

My name is and I’m a full stack web developer living and working in Lincoln, England. This website (philipnewborough.co.uk) serves as my personal homepage. When I’m not working with tech, I love to ride bicycles with my wife and friends.

An IndieWeb Webring 🕸💍