开发者

Weird bug in PHP, Spaces in Paths and Windows

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?


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!


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 \"

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜