Question

I've got to fix this little bug. First, let's talk about a small fact: In CLI on Windows, you can't run a program with a space in its path, unless escaped:

C:\>a b/c.bat
'a' is not recognized as an internal or external command,
operable program or batch file.

C:\>"a b/c.bat"

C:\>

I'm using proc_open...proc_close in PHP to run a process (program), example:

function _pipeExec($cmd,$input=''){
    $proc=proc_open($cmd,array(0=>array('pipe','r'),
        1=>array('pipe','w'),2=>array('pipe','w')),$pipes);
    fwrite($pipes[0],$input);
    fclose($pipes[0]);
    $stdout=stream_get_contents($pipes[1]); // max execusion time exceeded ssue
    fclose($pipes[1]);
    $stderr=stream_get_contents($pipes[2]);
    fclose($pipes[2]);
    $rtn=proc_close($proc);
    return array(
        'stdout'=>$stdout,
        'stderr'=>$stderr,
        'return'=>(int)$rtn
    );
}

// example 1
_pipeExec('C:\\a b\\c.bat -switch');
// example 2
_pipeExec('"C:\\a b\\c.bat" -switch');
// example 3 (sounds stupid but I had to try)
_pipeExec('""C:\\a b\\c.bat"" -switch');

Example 1

  • RESULT: 1
  • STDERR: 'C:\a' is not recognized as an internal or external command, operable program or batch file.
  • STDOUT:

Example 2

  • RESULT: 1
  • STDERR: 'C:\a' is not recognized as an internal or external command, operable program or batch file.
  • STDOUT:

Example 3

  • RESULT: 1
  • STDERR: The filename, directory name, or volume label syntax is incorrect.
  • STDOUT:

So you see, either case (double quotes or not) the code fails. Is it me or am I missing something?

Was it helpful?

Solution

Most unfortunately, the fix doesn't work as expected, however Pekka's first suggestion gave me an idea:

$file='C:\a b\c';
$cmdl='/d /b /g';

if(strtolower(substr(PHP_OS,0,3))=='win') // if windows...
    $file='cd '.escapeshellarg(dirname($file)).' && '.basename($file);

_pipeExec($file.' '.$cmdl);

This is platform-specific, and I hope I don't have to fix this over linux as well. So far it works well!

OTHER TIPS

Another way of solving this is by putting additional double quotes at the beginning and the end of the command.

$process = 'C:\\Program Files\\nodejs\\node.exe';
$arg1 = 'C:\\Path to File\\foo.js';

$cmd = sprintf('"%s" %s', $process, escapeshellarg($arg1));
if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {
    $cmd = '"'.$cmd.'"';
}

_pipeExec($cmd);

I have found this solution on https://bugs.php.net/bug.php?id=49139
It looks weird, but hey - it's Windows... :D

This is strage.

Untested workaround ideas:

  • Use a temporary environment variable:

    exec('SET ENVPATH="C:\a b"');
    proc_open('%ENVPATH%\c.bat' ....
    

    (no idea whether this will work for proc_open)

  • Use the 8.3 filename if that can somehow be fetched in PHP - would certainly be doable using another exec()

  • proc_open() has an option to bypass cmd.exe - might be worth a try in case the filesystem somehow handles the quotes differently

  • Try escaping the quotes \"

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top