在Web服务器上通过PHP运行SlimerJS +无头Firefox脚本?

On my server (Ubuntu 14.04.4 LTS), I have a Firefox installed, as well as xvfb for headless Firefox operation, and CasperJS with SlimerJS. I also have a CasperJS script which works fine. I want to utilize this script from PHP; this is the essence of my PHP script for this, let's call it mytest.php:

echo "php_sapi_name() " . php_sapi_name() . "
"; // "cli" for php cli, "apache2handler" for php via webserver

chdir(dirname(__FILE__));

$nodeModPath = "/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules";

putenv("SLIMERJSLAUNCHER=/usr/bin/firefox46");
$cmdline = "xvfb-run $nodeModPath/casperjs/bin/casperjs --engine=slimerjs --debug=true mySlimerScript.js";

$returnString = shell_exec($cmdline);
echo "$returnString
";

EDIT: Note that the command could as well be just:

$cmdline = "xvfb-run $nodeModPath/casperjs/bin/casperjs --engine=slimerjs --debug=true 2>&1";

... that is, without any JS script listed - in which case the help should be dumped (and is, in case of CLI access - but the same error as below is reported when accessing through webserver)


When I run this PHP script from the terminal command line (via SSH), that is through PHP in CLI mode:

$ php mytest.php 

... everything runs fine, there is no problem whatsoever.

However, when I invoke this PHP script online through the webserver, that is via http://example.com/mytest.php, it fails first with the error:

Gecko error: it seems /usr/bin/firefox46 is not compatible with SlimerJS.
See Gecko version compatibility. If version is correct, launch slimerjs
with --debug=true to see Firefox error message

... and after adding --debug=true (as already included in the example above), I additionally get this error:

JavaScript error: resource://gre/modules/FileUtils.jsm, line 63: NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get]

So, apparently my headless Firefox does not want to run, when PHP is invoked through the webserver (in which case, PHP reports that it uses the apache2handler SAPI).

Would anyone know why this happens - and how can I get the script to execute properly when called from a webserver, just as when it runs under PHP CLI mode?


EDIT 2: Can now reconstruct this error via CLI mode too, and can confirm it is due to the user; so without any JS script provided in the $command, I get this:

$ sudo -H -u root php mytest.php
...
Usage: casperjs [options] script.[js|coffee] [script argument [script argument ...]]
       casperjs [options] test [test path [test path ...]]
       casperjs [options] selftest
...

$ sudo -H -u www-data php mytest.php
JavaScript error: resource://gre/modules/FileUtils.jsm, line 63: NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get]
Gecko error: it seems /usr/bin/firefox46 is not compatible with SlimerJS.
See Gecko version compatibility. If version is correct, launch slimerjs
with --debug=true to see Firefox error message

Well, this was a nasty problem. I ended up doing an strace, and comparing the logs, for the root user and the www-data user when running a full slimerjs (the full command line can be found by adding echoes to /path/to/slimerjs-0.10.1-pre/slimerjs):

sudo -H -u www-data strace \
  /usr/bin/firefox46 -app /path/to/slimerjs-0.10.1-pre/application.ini \
  --profile /path/to/firefox-46.0.1/profile-46 -no-remote --debug=true /home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/bootstrap.js --casper-path=/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs \
  --cli 2>&1 \
  | tee /tmp/strace.log

sudo -H -u root strace \
  /usr/bin/firefox46 -app /path/to/slimerjs-0.10.1-pre/application.ini \
  --profile /path/to/firefox-46.0.1/profile-46 -no-remote --debug=true /home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/bootstrap.js --casper-path=/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs \
  --cli 2>&1 \
  | tee /tmp/straceR.log

If these logs are now compared in say meld, then the eventually start diverging at a point like this:

mkdir("/root/.innophi", 0700)           = 0
mkdir("/root/.innophi/slimerjs", 0700)  = 0

... [vs.] ...

mkdir("/var/www/.innophi", 0700)        = -1 EACCES (Permission denied)
access("/var/www/.innophi", F_OK)       = -1 ENOENT (No such file or directory)

So, casperJS basically tries to create a directory in the home directory of the user; the problem is , www-data's $HOME is /var/www, where it seemingly has no write access!

So, the easiest thing for me was to "hack" the $HOME environment variable in the mytest.php script, and set it to /tmp, where www-data definitely has write permissions:

...
putenv("SLIMERJSLAUNCHER=/usr/bin/firefox46");
putenv("HOME=/tmp");
...

... and whaddayaknow, finally the script works under the www-data user from CLI too:

$ sudo -H -u www-data php test_commands.php
...
Options:

--verbose   Prints log messages to the console
--log-level Sets logging level
--help      Prints this help
...

Btw, this .innophi directory seems to also be mentioned in https://docs.slimerjs.org/current/configuration.html#profiles ,