Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

npm install not working via php system() (exec / shell_exec)

I am installing gulp-sass among other packages using npm install. This works fine using CLI (with sudo su forge):

cd /path/to/package.json/
npm install

The package.json look like:

{
  "name": "skeleton",
  "version": "1.0.0",
  "authors": [
    "Me <[email protected]>"
  ],
  "private": true,
  "devDependencies": {
    "gulp": "^3.8.11",
    "gulp-autoprefixer": "^2.1.0",
    "gulp-concat": "^2.5.2",
    "gulp-minify-css": "^1.0.0",
    "gulp-notify": "^2.2.0",
    "gulp-sass": "^1.3.3",
    "gulp-sourcemaps": "^1.5.2",
    "gulp-uglify": "^1.2.0"
  },
  "dependencies": {
    "node-notifier": "^4.2.1",
    "streamqueue": "^0.1.3"
  }
}

It also works fine using PHP at the command line:

php -r "system('npm install');"

But running the following PHP via nginx/PHP-FPM:

<?php

set_time_limit(0);
chdir('/path/to/package.json/');
echo "<pre>";
echo shell_exec('npm install 2>&1');

die();

Outputs a debug file containing the following lines:

81427 error Linux 4.5.5-x86_64-linode69
81428 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "install"
81429 error node v0.12.7
81430 error npm  v2.11.3
81431 error file sh
81432 error path sh
81433 error code ELIFECYCLE
81434 error errno ENOENT
81435 error syscall spawn sh
81436 error [email protected] install: `node scripts/install.js`
81436 error spawn sh ENOENT
81437 error Failed at the [email protected] install script 'node scripts/install.js'.
81437 error This is most likely a problem with the node-sass package,
81437 error not with npm itself.
81437 error Tell the author that this fails on your system:
81437 error     node scripts/install.js
81437 error You can get their info via:
81437 error     npm owner ls node-sass
81437 error There is likely additional logging output above.

I have tried comparing the two scenarios with the following:

which npm

both return '/usr/local/bin/npm'

--

echo $USER

both return 'forge'

--

echo $GROUP

both return '' (empty)

--

echo $PATH

CLI returns:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

PHP returns:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

--

which sh

both return '/bin/sh'

--

ps $$

CLI returns:

    PID TTY      STAT   TIME COMMAND
  13111 pts/2    S      0:00 bash

PHP returns:

    PID TTY      STAT   TIME COMMAND
  25759 ?        S      0:00 sh -c ps $$

--

npm -v

both return '2.11.3'

--

npm version

CLI returns:

{ skeleton: '1.0.0',
  npm: '2.11.3',
  http_parser: '2.3',
  modules: '14',
  node: '0.12.7',
  openssl: '1.0.1p',
  uv: '1.6.1',
  v8: '3.28.71.19',
  zlib: '1.2.8' }

PHP returns without skeleton 1.0.0:

{ npm: '2.11.3',
  http_parser: '2.3',
  modules: '14',
  node: '0.12.7',
  openssl: '1.0.1p',
  uv: '1.6.1',
  v8: '3.28.71.19',
  zlib: '1.2.8' }

--

npm config ls -l

CLI returns:

; cli configs
long = true
user-agent = "npm/2.11.3 node/v0.12.7 linux x64"

; userconfig /home/forge/.npmrc
ignore-scripts = false
loglevel = "info"
prefix = "/home/forge/npm"
progress = false

; default values
access = null
always-auth = false
bin-links = true
browser = null
ca = null
cache = "/home/forge/.npm"
cache-lock-retries = 10
cache-lock-stale = 60000
cache-lock-wait = 10000
cache-max = null
cache-min = 10
cafile = undefined
cert = null
color = true
depth = null
description = true
dev = false
editor = "vi"
engine-strict = false
fetch-retries = 2
fetch-retry-factor = 10
fetch-retry-maxtimeout = 60000
fetch-retry-mintimeout = 10000
force = false
git = "git"
git-tag-version = true
global = false
globalconfig = "/home/forge/npm/etc/npmrc"
globalignorefile = "/home/forge/npm/etc/npmignore"
group = 1013
heading = "npm"
https-proxy = null
if-present = false
ignore-scripts = false
init-author-email = ""
init-author-name = ""
init-author-url = ""
init-license = "ISC"
init-module = "/home/forge/.npm-init.js"
init-version = "1.0.0"
json = false
key = null
link = false
local-address = undefined
; loglevel = "warn" (overridden)
; long = false (overridden)
message = "%s"
node-version = "0.12.7"
npat = false
onload-script = null
optional = true
parseable = false
; prefix = "/usr/local" (overridden)
production = false
proprietary-attribs = true
proxy = null
rebuild-bundle = true
registry = "https://registry.npmjs.org/"
rollback = true
save = false
save-bundle = false
save-dev = false
save-exact = false
save-optional = false
save-prefix = "^"
scope = ""
searchexclude = null
searchopts = ""
searchsort = "name"
shell = "/bin/bash"
shrinkwrap = true
sign-git-tag = false
spin = true
strict-ssl = true
tag = "latest"
tag-version-prefix = "v"
tmp = "/tmp"
umask = 2
unicode = true
unsafe-perm = true
usage = false
user = 1013
; user-agent = "npm/{npm-version} node/{node-version} {platform} {arch}" (overridden)
userconfig = "/home/forge/.npmrc"
version = false
versions = false
viewer = "man"

PHP returns:

; cli configs
long = true
user-agent = "npm/2.11.3 node/v0.12.7 linux x64"

; userconfig /home/forge/.npmrc
ignore-scripts = false
loglevel = "warn"
prefix = "/home/forge/npm"
progress = false

; default values
access = null
always-auth = false
bin-links = true
browser = null
ca = null
cache = "/home/forge/.npm"
cache-lock-retries = 10
cache-lock-stale = 60000
cache-lock-wait = 10000
cache-max = null
cache-min = 10
cafile = undefined
cert = null
color = true
depth = null
description = true
dev = false
editor = "vi"
engine-strict = false
fetch-retries = 2
fetch-retry-factor = 10
fetch-retry-maxtimeout = 60000
fetch-retry-mintimeout = 10000
force = false
git = "git"
git-tag-version = true
global = false
globalconfig = "/home/forge/npm/etc/npmrc"
globalignorefile = "/home/forge/npm/etc/npmignore"
group = 1000
heading = "npm"
https-proxy = null
if-present = false
ignore-scripts = false
init-author-email = ""
init-author-name = ""
init-author-url = ""
init-license = "ISC"
init-module = "/home/forge/.npm-init.js"
init-version = "1.0.0"
json = false
key = null
link = false
local-address = undefined
loglevel = "warn"
; long = false (overridden)
message = "%s"
node-version = "0.12.7"
npat = false
onload-script = null
optional = true
parseable = false
; prefix = "/usr/local" (overridden)
production = false
proprietary-attribs = true
proxy = null
rebuild-bundle = true
registry = "https://registry.npmjs.org/"
rollback = true
save = false
save-bundle = false
save-dev = false
save-exact = false
save-optional = false
save-prefix = "^"
scope = ""
searchexclude = null
searchopts = ""
searchsort = "name"
shell = "bash"
shrinkwrap = true
sign-git-tag = false
spin = true
strict-ssl = true
tag = "latest"
tag-version-prefix = "v"
tmp = "/tmp"
umask = 18
unicode = true
unsafe-perm = true
usage = false
user = 1000
; user-agent = "npm/{npm-version} node/{node-version} {platform} {arch}" (overridden)
userconfig = "/home/forge/.npmrc"
version = false
versions = false
viewer = "man"

--

Potentially relevant config differences reported are:

- group (1013 / 1000)
- shell (/bin/bash / bash) - I've tried using /bin/bash -c "npm install" but it seems to make no difference.
- umask (2 / 18)
- user (1013 / 1000) (user 1000 is "forge", user 1013 is myself)

I'm all out of ideas. If you have any idea as to why the introduction of nginx/php-fpm causes this issue, your input would be greatly appreciated.

Many thanks.

like image 944
Ian Stanley Avatar asked Oct 29 '22 23:10

Ian Stanley


1 Answers

It appears that $PATH doesn't include /bin when called as an npm script so it fails to find /bin/sh per error file sh.

The solution is to symlink /bin/sh to /usr/bin/sh:

ln -s /bin/sh /usr/bin/sh
like image 167
Kaspars Avatar answered Nov 09 '22 15:11

Kaspars