0

I'm able to call diff via exec() just fine with files, like so:

exec('diff -N -u '.escapeshellarg($oldfile).' '.escapeshellarg($newfile), $lines);

However, attempting to do this with arbitrary strings fails:

exec('diff -N -u <(echo '.escapeshellarg($oldstring).') <(echo '.escapeshellarg($newstring).')', $lines);

If I copy the command being run into bash, it works just fine. But when run in PHP I get no output. Even 2>&1 doesn't yield anything. Capturing the status code yields 1, which should indicate that diff found differences, but I still get 1 even in the case where $newstring === $oldstring.

So I'm not quite sure what's going on. I can only assume that, for some reason, exec doesn't like process substitutions? Any ideas?

5
  • exec runs the command with sh, which does not support process substitution. You'd need to run it with bash Commented Jan 21, 2018 at 18:39
  • @thatotherguy Good point, although exec('echo $SHELL'); yields /bin/bash. Commented Jan 21, 2018 at 18:53
  • @thatotherguy Interesting - I tried wrapping the whole thing in '/bin/bash -c '.escapeshellarg('diff ...') and suddenly it's working. That leaves more questions (like why $SHELL is /bin/bash) but at least it works! Commented Jan 21, 2018 at 18:56
  • $SHELL is not the currently running shell. It's the user's login shell, similar to how $EDITOR is the user's editor and $PAGER is their preferred pager. Commented Jan 21, 2018 at 20:16
  • @thatotherguy All righty, fair enough. I got it working thanks to your comment, so feel free to post as answer :) Commented Jan 21, 2018 at 20:27

2 Answers 2

1

PHP's exec runs the command with /bin/sh, which does not support process substitution (even when sh is provided by bash).

You can instead run your command explicitly with bash -c.

Sadly, PHP has no convenience functions for safe and robust execv style execution, so the easiest way to do that to build your diff command and then escape the whole thing:

exec('bash -c ' . escapeshellarg('diff -N -u <(echo '.escapeshellarg($oldstring).') <(echo '.escapeshellarg($newstring).')'), $lines);
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. As it turns out, it doesn't like longer strings anyway (worked in testing, then tried with an 80Kb string and it died spectacularly XD) so I wound up going with temporary files and back to sh.
Yep yep.. The limit is OS dependent but usually 128k-256k.
0

What shell is being used? Make sure diff is in the $PATH, otherwise command will fail.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.