Invoke a program using argument vector in PHP

one text

Solution:

This method is limited to PHP running on POSIX systems

The functions such as system, popen, whether in the context of PHP or C & POSIX, are never meant to take synthesized command strings. So the thinking process of designing such a function should begin with a constant-valued command string.

Next, PHP does provide the capability to set individual environment variables like C (though not unsetting them afterwards), and this capability is largely immune to injection-related attacks. So we can build a command that takes environment variables, assemble a command vector, then invoke exec shell built-in command.

Here's the full code:

<?php
 $spawncmd = <<<'EOF'
set --
n=0
while [ $n -lt $execargc ] ; do
    eval "set -- \"\$@\" \"\$execarg$n\""
    unset -v execarg$n
    n=$((n+1))
done
unset -v execargc
exec "$@"
EOF;

 // Invokes external program and return its output.
 function spawn($args)
 {
   global $spawncmd;
   
   putenv("execargc=".count($args));
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=".$args[$i]);

   $ret = shell_exec($spawncmd);
   
   putenv("execargc=");
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=");

   return $ret;
 }

 // Invokes external program and return its exit status.
 function catspawn($args)
 {
   global $spawncmd;
   
   putenv("execargc=".count($args));
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=".$args[$i]);

   $ret = null;
   passthru($spawncmd, $ret);
   
   putenv("execargc=");
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=");

   return $ret;
 }

 // Argument vector version of popen.
 function pspawn($args, $mode)
 {
   global $spawncmd;
   
   putenv("execargc=".count($args));
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=".$args[$i]);

   $ret = popen($spawncmd, $mode);
   
   putenv("execargc=");
   for($i=0; $i<count($args); $i++)
     putenv("execarg$i=");

   return $ret;
 }

Source