php exec:不返回输出

时间:2012-02-02 15:03:21

标签: php windows iis exec

我有这个问题: 在ISS Web服务器上,安装了Windows 7 x64专业版,zend服务器。在php下运行此命令:

exec('dir',$output, $err);

$output is empty, $err=1.所以exec没有退回输出,似乎有一些错误。 Php disable_functions是空的,php不是安全模式,是标准的,我检查所有选项。 这似乎是一般性错误,即使是谷歌搜索也不会给出结果。

请写下他的经验和最终解决方案或解决方法。

10 个答案:

答案 0 :(得分:13)

PHP手册的相关部分有一些帖子,例如this one

  

我在使用PHP exec命令执行任何批处理时遇到问题   文件。执行其他命令(即“dir”)工作正常。但如果我   执行了一个批处理文件,我收到了exec命令没有输出。

     

我的服务器设置包括运行的Windows Server 2003服务器   IIS6和PHP 5.2.3。在这台服务器上,我有:

     
      
  1. 授予c:\ windows \ system32 \ cmd.exe上的Internet用户执行权限。
  2.   
  3. 授予所有人 - >完全控制写入批处理文件的目录。
  4.   
  5. 授予所有人 - >完全控制整个c:\ cygwin \ bin目录及其内容。
  6.   
  7. 授予Internet用户“以批处理方式登录”权限。
  8.   
  9. 指定正在执行的每个文件的完整路径。
  10.   
  11. 测试了从服务器上的命令行运行的这些脚本,它们工作正常。
  12.   
  13. 确保%systemroot%\ system32位于系统路径中。
  14.         

    事实证明,即使服务器上有上述所有内容,我也是   必须在exec调用中指定cmd.exe的完整路径。

         

    当我使用通话时:$output = exec("c:\\windows\\system32\\cmd.exe   /c $batchFileToRun");

         

    然后一切正常。在我的情况下,$batchFileToRun是   批处理文件的实际系统路径(即调用的结果)   真实路径())。

execshell_exec手册页上还有一些内容。也许通过它们可以得到它并为你工作。

答案 1 :(得分:9)

dir等命令获得零输出的主要原因是因为dir不存在。它是命令提示符的一部分,这个特定问题的解决方案很好,在这个页面的某个地方。

您可以按WIN + R,然后输入dirstart来查找此内容,系统会显示错误消息!

然而,这听起来有点不正常,我发现在Windows中执行任何相关过程的最可靠方法是使用组件对象模型。你说让我们分享一下我们的经历吧?

$ me听到人们大笑

恢复了你的镇静?

所以,首先我们将创建COM对象:

$pCOM = new COM("WScript.Shell");

然后,我们将运行需要运行的东西。

$pShell = $pCom->Exec("C:\Random Folder\Whatever.exe");

酷!现在,这将一直挂起,直到一切都在二进制文件中完成。所以,我们现在需要做的就是抓住输出。

$sStdOut = $pShell->StdOut->ReadAll;    # Standard output
$sStdErr = $pShell->StdErr->ReadAll;    # Error

您可以执行其他一些操作 - 找出进程ID,错误代码等等。虽然this example适用于Visual Basic,但它基于相同的方案。

答案 2 :(得分:5)

编辑:经过一些研究后,我看到执行DIR命令的唯一方法就是:

cmd.exe /c dir c:\

所以你可以尝试使用我的解决方案:

$command = 'cmd.exe /c dir c:\\';

您也可以使用proc_open函数,这样您就可以访问stderr,返回状态代码和标准输出。

    $stdout = $stderr = $status = null;
    $descriptorspec = array(
       1 => array('pipe', 'w'),  // stdout is a pipe that the child will write to
       2 => array('pipe', 'w') // stderr is a pipe that the child will write to
    );

    $process = proc_open($command, $descriptorspec, $pipes);

    if (is_resource($process)) {
        // $pipes now looks like this:
        // 0 => writeable handle connected to child stdin
        // 1 => readable handle connected to child stdout
        // 2 => readable handle connected to child stderr

        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);

        // It is important that you close any pipes before calling
        // proc_close in order to avoid a deadlock
        $status = proc_close($process);
    }

    return array($status, $stdout, $stderr);

与其他函数(如popen或exec)相比,proc_open的有趣部分是它提供了特定于Windows平台的选项,如:

suppress_errors (windows only): suppresses errors generated by this function when it's set to TRUE
bypass_shell (windows only): bypass cmd.exe shell when set to TRUE

答案 3 :(得分:1)

我知道我已经选择了一个答案,因为我必须这样做但我仍然不明白为什么它不能在我的机器上工作但是我发现了使用另一种方法的后备(使用proc_open)解决方案:

public static function exec_alt($cmd)
{
    exec($cmd, $output);
    if (!$output) {
        /**
         * FIXME: for some reason exec() returns empty output array @mine,'s machine.
         *        Somehow proc_open() approach (below) works, but doesn't work at
         *        test machines - same empty output with both pipes and temporary
         *        files (not we bypass shell wrapper). So use it as a fallback.
         */
        $output = array();
        $handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
        if (is_resource($handle)) {
            $output = explode("\n", stream_get_contents($pipes[1]));
            fclose($pipes[1]);
            proc_close($handle);
        }
    }
    return $output;
}

希望这有助于某人。

答案 4 :(得分:1)

我是同样的问题,花了很多时间和一杯咖啡后

在Windows 7中禁用用户帐户控制(UAC) 短路径:P C:\ WINDOWS \ SYSTEM32 \ UserAccountControlSettings.exe 并选择“从不通知”

和php exec()工作正常!

我用: Apache版本:2.2.11
PHP版本:5.2.8
Windows 7 SP1 32位

祝你好运! :d

答案 5 :(得分:1)

试试这个:

shell_exec('dir 2>&1');

在启用了UAC的Windows 8.1 64位上运行良好。

答案 6 :(得分:0)

出于安全考虑,您的服务器可能限制访问“exec”命令。在这种情况下,您可以联系托管公司以取消此限制(如果有)。

答案 7 :(得分:0)

您可以检查IIS用户对cmd.exe的权限

cacls C:\WINDOWS\system32\cmd.exe

如果输出中的行类似(COMPUTERNAME =您的计算机名称):

C:\WINDOWS\system32\cmd.exe COMPUTERNAME\IUSR_COMPUTERNAME:N

这意味着用户无权执行cmd。

您可以使用以下命令添加执行权限:

cacls C:\WINDOWS\system32\cmd.exe /E /G COMPUTERNAME\IUSR_COMPUTERNAME:R

答案 8 :(得分:0)

如果您使用的是Windows计算机并尝试运行这样的可执行文件:

shell_exec("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile\YourFile.exe");

并且没有输出或您的文件没有启动,那么您应该尝试这样:

chdir("C:\Programs\SomeDir\DirinDir\..\DirWithYourFile");
shell_exec("YourFile.exe");

它应该有用。

如果您正在使用当前脚本所在的文件夹中的相对路径,这将非常方便,例如:

$dir = dirname(__FILE__).'\\..\\..\\..\\web\\';

如果您需要运行其他程序,请不要忘记将chdir()返回到原始文件夹。

答案 9 :(得分:-1)

看看Apache error_log,也许你会找到错误信息。

此外,您可以尝试使用popen而不是exec。它提供了更多控制,因为您可以将进程开始与输出读取分开:

$p = popen("dir", "r");
if (!$p)
    exit("Cannot run command.\n");
while (!feof($p))
    echo fgets($p);
pclose($p);