php exec:不返回输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9114574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 06:12:08  来源:igfitidea点击:

php exec: does not return output

phpwindowsiisexec

提问by albanx

I have this problem: On a ISS web server, windows 7 x64 professional, zend server installed. Running this command under php:

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

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

$output is empty, $err=1.So exec is not returing the output, it seems has some errors. Php disable_functionsis empty, php is not on safe mode, is standard, I check all option. It seems to be a general errors, even search on google do not give results.

$output is empty, $err=1.所以 exec 没有返回输出,它似乎有一些错误。Phpdisable_functions是空的,php 不在安全模式下,是标准的,我选中所有选项。这似乎是一个普遍的错误,即使在谷歌上搜索也不给出结果。

Please write every one his experince and eventual solutions or workarounds.

请写下每个人的经验和最终的解决方案或变通方法。

回答by Treffynnon

There are a few posts to the relevant sections of the PHP Manual such as this one:

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

I was having trouble using the PHP exec command to execute any batch file. Executing other commands (i.e., "dir") works fine). But if I executed a batch file, I receieved no output from the exec command.

The server setup I have consists of Windows Server 2003 server running IIS6 and PHP 5.2.3. On this server, I have:

  1. Granted execute permissions to the Internet User on c:\windows\system32\cmd.exe.
  2. Granted Everyone->Full Control to the directory in which the batch file is written.
  3. Granted Everyone->Full Control on the entire c:\cygwin\bin directory and its contents.
  4. Granted the Internet User "log on as batch" permissions.
  5. Specified the full path to each file being executed.
  6. Tested these scripts running from the command line on the server and they work just fine.
  7. Ensured that %systemroot%\system32 is in the system path.

It turns out that even with all of the above in place on the server, I had to specify the full path to cmd.exe in the exec call.

When I used the call: $output = exec("c:\\windows\\system32\\cmd.exe/c $batchFileToRun");

then everything worked fine. In my situation, $batchFileToRunwas the actual system path to the batch file (i.e., the result of a call to realpath()).

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

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

  1. 授予 Internet 用户在 c:\windows\system32\cmd.exe 上的执行权限。
  2. 授予Everyone->完全控制写入批处理文件的目录。
  3. 授予 Everyone-> 对整个 c:\cygwin\bin 目录及其内容的完全控制权。
  4. 授予 Internet 用户“批量登录”权限。
  5. 指定正在执行的每个文件的完整路径。
  6. 测试了从服务器上的命令行运行的这些脚本,它们工作得很好。
  7. 确保 %systemroot%\system32 在系统路径中。

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

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

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

There are a few more on both the execand shell_execmanual pages. Perhaps following through them will get it up and working for you.

手册页execshell_exec手册页上还有一些内容。也许遵循它们会得到它并为您工作。

回答by Westie

The main reason you get zero output from a command such as diris because dirdoesn't exist. It's part of the command prompt, and the solution to this particular problem is well, in this page somewhere.

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

You can find this out by pressing WIN + R, and typing in diror startfor that matter - an error message appears!

您可以通过按WIN + R,然后输入dirstart为此找到此信息 - 出现错误消息!

However perverse this may sound, I've found that the most reliable way to do anything process related in Windows is with using the Component Object Model. You said for us to share our experiences, right?

不管这听起来多么不合常理,我发现在 Windows 中执行任何相关过程的最可靠方法是使用组件对象模型。你说让我们分享我们的经验,对吗?

$me hears people laughing

$me 听到人们在笑

Regained your composure yet?

镇定下来了吗?

So, first we'll create the COM object:

因此,首先我们将创建 COM 对象:

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

Then, we'll just run what ever needs to be run.

然后,我们将只运行需要运行的内容。

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

Cool! Now, that'll hang until everything's finished in that binary. So, what we need to do now is grab the output.

凉爽的!现在,这将挂起,直到该二进制文件中的所有内容都完成。所以,我们现在需要做的是获取输出。

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

There's some other things you can do - find out what was the process ID, error code, etc. Although this exampleis for Visual Basic, it's based on the same scheme.

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

回答by Florian Klein

EDIT: After a few researchs, the only way i see to execute the DIR command is like that:

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

cmd.exe /c dir c:\

So you can try my solution using:

因此,您可以使用以下方法尝试我的解决方案:

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

You can use proc_open function too, which gives you access to stderr, return status code and stdout.

您也可以使用 proc_open 函数,它使您可以访问 stderr、返回状态代码和 stdout。

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

The interesting part with proc_open, compared to other functions like popen or exec, is that it provides options specific to windows platform like:

与 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

回答by albanx

I know I have choosen an answer as I must do it but I still do not understand why it wont work on my macchine but I found a fallback (using proc_open) solution using another method:

我知道我选择了一个答案,因为我必须这样做,但我仍然不明白为什么它不能在我的机器上工作,但我使用另一种方法找到了后备(使用 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;
}

Hope this helps someone.

希望这可以帮助某人。

回答by Alejandro Bautista

I was the same problem and after spend a lot of hours and cup of coffee

我遇到了同样的问题,花了很多时间喝了杯咖啡

Just Disabling User Account Control (UAC) in Windows 7 short path :P C:\Windows\System32\UserAccountControlSettings.exe and select "Never notify"

只需在 Windows 7 短路径中禁用用户帐户控制 (UAC) :PC:\Windows\System32\UserAccountControlSettings.exe 并选择“从不通知”

and php exec() works fine!

和 php exec() 工作正常!

I use: Apache Version : 2.2.11
PHP Version : 5.2.8
Windows 7 SP1 32bit

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

Best regards! :D

此致!:D

回答by anisite

Try this:

尝试这个:

shell_exec('dir 2>&1');

It works fine on Windows 8.1 64bits with UAC enabled.

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

回答by developer

If you are on Windows machine and trying to run an executable like this:

如果您在 Windows 机器上并尝试运行这样的可执行文件:

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

and there is no output or your file isn't started, then you should try this:

并且没有输出或者你的文件没有启动,那么你应该试试这个:

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

It should work.

它应该工作。

This is particularly handy if one is using relative path from folder where script currently is being located, for example:

如果使用当前脚本所在文件夹的相对路径,这将特别方便,例如:

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

And don't forget to chdir() back to originating folder if you need to run other programs.

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

回答by Giannis

For security purposes, your server may have restricted access to "exec" command. In this case, maybe you should contact the hosting company to remove this restriction (if there is one).

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

回答by li-on

You can check permisssions of IIS User to cmd.exe

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

cacls C:\WINDOWS\system32\cmd.exe

If in output is line like (COMPUTERNAME=your computer name):

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

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

It means that user has no rights to execute cmd.

这意味着用户没有执行 cmd 的权限。

You can add execute permissions with command:

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

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

回答by Milan Babu?kov

Take a look at Apache error_log, maybe you'll find the error message.

看看Apache error_log,也许你会发现错误信息。

Also, you can try using popen instead of exec. It gives more control because you can separate process start from output read:

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

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