Issue running Google Lighthouse from PHP file

Viewed 24

I have Lighthouse installed to run speed test scores for our websites .. And it works, for me, user zak

I want to be able to run this from a php script .. Here is the entire script.

<?php
if ( empty( $_POST['website'] ) ){
    die('Invalid Website');
}
echo shell_exec("whoami") . "<br />";
$website = $_POST['website'];
$test = shell_exec("npx lighthouse $website --chrome-flags='--headless'  2>&1");

echo "Test result for $website:<br />$test";

I get a return of:

www-data
Test result for exaple.com:
npm ERR! Cannot read properties of undefined (reading 'split')

If I run that command native logged in as Zak:

$zak: npx lighthouse http://example.com --chrome-flags='--headless'  2>&1

It runs happily.

I made a bash script to test what www-data can see .. And ran:

#!/bin/bash
node -v
nodejs -v
nmp -v
npx -v
which npx

Which returned

v16.16.0
v16.16.0
8.11.0
8.11.0
/usr/local/bin/npx

The super interesting part is, if I issue:

$zak: sudo -u www-data npx lighthouse http://example.com --chrome-flags='--headless'  2>&1

It runs command line!

So I know www-data can run npx and node commands just fine. The error even indicates that it is trying to run it. Why is npx lighthouse not running from my php file? Is there special permissions I need to give it? I cannot find any definitive documentation on this error. Can I run further checks? This seems like it might be a lighthouse bug?

UPDATE

After reading the verbose log:

33 verbose stack TypeError: Cannot read properties of undefined (reading 'split')
33 verbose stack     at Object.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/libnpmexec/lib/index.js:24:3)
33 verbose stack     at Module._compile (node:internal/modules/cjs/loader:1119:14)
33 verbose stack     at Module._extensions..js (node:internal/modules/cjs/loader:1173:10)
33 verbose stack     at Module.load (node:internal/modules/cjs/loader:997:32)
33 verbose stack     at Module._load (node:internal/modules/cjs/loader:838:12)
33 verbose stack     at Module.require (node:internal/modules/cjs/loader:1021:19)
33 verbose stack     at require (node:internal/modules/cjs/helpers:103:18)
33 verbose stack     at Object.<anonymous> (/usr/local/lib/node_modules/npm/lib/commands/exec.js:1:17)
33 verbose stack     at Module._compile (node:internal/modules/cjs/loader:1119:14)
33 verbose stack     at Module._extensions..js (node:internal/modules/cjs/loader:1173:10)

The pertinent contents of node_modules/libnpmexec/lib/index.js is:

const { delimiter, dirname, resolve } = require('path')
const { promisify } = require('util')
const read = promisify(require('read'))

const Arborist = require('@npmcli/arborist')
const ciDetect = require('@npmcli/ci-detect')
const log = require('proc-log')
const npmlog = require('npmlog')
const mkdirp = require('mkdirp-infer-owner')
const npa = require('npm-package-arg')
const pacote = require('pacote')

const cacheInstallDir = require('./cache-install-dir.js')
const { fileExists, localFileExists } = require('./file-exists.js')
const getBinFromManifest = require('./get-bin-from-manifest.js')
const noTTY = require('./no-tty.js')
const runScript = require('./run-script.js')
const isWindows = require('./is-windows.js')
const _localManifest = Symbol('localManifest')

/* istanbul ignore next */
const PATH = (
  process.env.PATH || process.env.Path || process.env.path
).split(delimiter)  // <- ERROR
1 Answers

Even though my ENV PATH was set for www-data:

$zak: sudo -u www-data printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

I had to include it into the command:

$test = shell_exec("export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin && npx lighthouse --verbose http://example.com --chrome-flags='--headless --no-sandbox'  2>&1");

The issue is that natively speaking PHP does not have access to even Apache's ENV set .. It is turned off by default in the php.ini. So if you print_r($_ENV) and see an empty array, most likely you need to uncomment the line that allows ENV in php.ini and you may need to set your PATH inside Apache, or PHP configuration. I just figure it's easier setting the export path as a superglobal in my PHP application and call it that way.

$_GLOBALS['export_path'] = 'export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'

$test = shell_exec("$export_path && npx lighthouse --verbose http://example.com --chrome-flags='--headless --no-sandbox'  2>&1");

UPDATE

After reading PHP Documentation I found that the $_SERVER superglobal contains everything that $_ENV does. And I printed out echo $_SERVER['PATH']; and viola .. There it was staring me in the face the entire time.

Related