1

I've trying the following examples such as:

$ php -r 'require_once($argv[1]);' <(echo "hello")

or:

$ php -r 'file_get_contents($argv[1]);' <(echo "hello")

both fails like:

PHP Warning: require_once(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1

PHP Warning: file_get_contents(/dev/fd/63): failed to open stream: No such file or directory in Command line code on line 1

or:

$ php -r 'file_get_contents($argv[0]);' < <(echo "hello")

which fails with:

PHP Fatal error: require_once(): Failed opening required '-' (include_path='.:/usr/share/pear:/usr/share/php') in Command line code on line 1

The above attempts were inspired by drush command, for example:

$ drush --early=<(echo print 123';') ""
[warning] require_once(/dev/fd/63): failed to open stream: No such file or directory preflight.inc:58

where I could inject the dynamic PHP code from the file descriptor (without creating a separate file each time) in order to execute the code before bootstrapping the main code.


Other similar command tools works correctly:

$ cat <(echo "hello")
hello

or:

$ python -c "import sys; print sys.stdin.readlines()" < <(echo "hello")
['hello\n']

I've found this PHP bug and this one, but these has been fixed long time ago and I'm using 5.6.22.

Is there any way that I can trick PHP into reading data from the process substitution (to read from file descriptor , e.g. /dev/fd) when called from CLI, by using some simple one-liner?

Community
  • 1
  • 1
kenorb
  • 155,785
  • 88
  • 678
  • 743

1 Answers1

1

The error message gives a good hint: PHP cannot find the given file.

But wait, what file? Well, let's remember what process substitution is:

Process substitution is a form of redirection where the input or output of a process (some sequence of commands) appear as a temporary file.

And so you see when you print the argument you are providing this way:

$ php -r 'print $argv[1];' <(echo "a")

To me it returns the following temporary file:

/dev/fd/63

So yes, you can use process substitution with PHP, but not for this.

If what you want is to use the output of the command as an argument, just use $() to expand it:

$ php -r 'print $argv[1];' "$(echo "hello man")"
hello man
Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • `$argv[1]` is returning file descriptor (`/dev/fd/63`), so that's correct, but I don't know why it cannot read it. Your last example is using _command substitution_, not _process substitution_. So I'm rather interested to see the example with _process substitution_. – kenorb Aug 08 '16 at 14:32
  • @kenorb the thing is that process substitution here is providing a file descriptor from which it reads the string "a". You cannot predetermine the content of a file descriptor so that it will contain the data you want. What is exactly what you want to do? Provide a variable file name? – fedorqui Aug 08 '16 at 14:37
  • I was playing with drush: `drush --early=<(echo print 123) ""` which gave me `require_once(/dev/fd/63)` error, so I was wondering if there is alternative syntax I could use, because using command substitution won't work in this case. It could be thing for another question, but on the other hand would be too similar to this. Basically it's not specifically to drush, but I wanted to find out whether PHP can support file descriptions, whether it's a bug or by design. – kenorb Aug 08 '16 at 14:43
  • @kenorb I see. I don't think using process substitution here makes much sense, since it is generally a way to circumvent pipelines. Check [Process substitution](http://wiki.bash-hackers.org/syntax/expansion/proc_subst) for good examples. I would focus on why `--early="$(echo 123)"` is not working, since command substitution seems to be more convenient for this case: you want the output of a command to be used as a parameter. – fedorqui Aug 08 '16 at 14:51
  • Yes, please, `$(echo 123)` will look for the file 123 in that syntax, not the content. – kenorb Aug 08 '16 at 14:54
  • @kenorb I think the key here is: _If a process substitution is expanded as an argument to a function, expanded to an environment variable during calling of a function, or expanded to any assignment within a function, the process substitution will be "held open" for use by any command within the function or its callees, until the function in which it was set returns. If the same variable is set again within a callee, unless the new variable is local, the previous process substitution is closed and will be unavailable to the caller when the callee returns_ That is, it is temporary. – fedorqui Aug 08 '16 at 15:04