代码之家  ›  专栏  ›  技术社区  ›  Christian

PHP中的奇怪错误,路径和窗口中的空间

  •  7
  • Christian  · 技术社区  · 14 年前

    我得去修理这个小虫子。首先,我们来谈谈一个小事实: 在Windows上的CLI中,不能运行路径中有空格的程序,除非转义:

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

    我在php中使用proc ou open…proc ou close来运行一个进程(程序),例如:

    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');
    

    实施例1

    • 结果:1
    • stderr:未将“c:\a”识别为内部或外部命令, 可操作程序或批处理文件。
    • 标准输出:

    实施例2

    • 结果:1
    • stderr:未将“c:\a”识别为内部或外部命令, 可操作程序或批处理文件。
    • 标准输出:

    实施例3

    • 结果:1
    • stderr:文件名、目录名或卷标签语法不正确。
    • 标准输出:

    所以你看,不管是不是双引号,代码都会失败。 是我还是我错过了什么?

    3 回复  |  直到 8 年前
        1
  •  4
  •   Christian    12 年前

    最不幸的是,修复并不像预期的那样有效,但是Pekka的第一个建议给了我一个想法:

    $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);
    

    这是平台特定的,我希望我不必在Linux上解决这个问题。到目前为止效果很好!

        2
  •  1
  •   stollr DanielM    8 年前

    解决这个问题的另一种方法是在命令的开头和结尾加上额外的双引号。

    $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);
    

    我在上找到了这个解决方案 https://bugs.php.net/bug.php?id=49139
    看起来很奇怪,但嘿-是窗户…D

        3
  •  0
  •   Pekka    14 年前

    这是斯特拉奇。

    未经测试的变通方案:

    • 使用临时环境变量:

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

      (不知道这是否适用于proc\u open)

    • 使用8.3文件名,如果它能以某种方式在PHP中获取,那么使用另一个文件名肯定是可行的。 exec()

    • proc_open() 可以选择绕过 cmd.exe -可能值得一试,以防文件系统以某种方式处理引号

    • 尝试转义引号 \"