我该如何调试exec()问题?

时间:2012-08-30 14:35:55

标签: php

exec命令在我的服务器上不起作用,它没有做任何事情,我已经关闭了safe_mode,并且验证了所有控制台命令都正常工作,我尝试过使用绝对路径。我已经检查了应用程序的权限以及我需要的所有应用程序都具有执行权限。我不知道还能做什么,这里是我尝试过的代码的简要说明。

echo exec('/usr/bin/whoami');

echo exec('whoami');

exec('whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
    echo 'Error<br>';
    print_r($output);   
}

exec('/usr/bin/whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
    echo 'Error<br>';
    print_r($output);   
}

显示最后两个代码:

Error
Array ( )

我联系了服务器服务,他们无法帮助我,他们不知道为什么exec命令不起作用。

4 个答案:

答案 0 :(得分:11)

查看/etc/php.ini,其中包含:

; This directive allows you to disable certain functions for security reasons.
; It receives a comma-delimited list of function names. This directive is
; *NOT* affected by whether Safe Mode is turned On or Off.
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-functions
disable_functions =

确保exec未列出如下:

disable_functions=exec

如果有,请将其删除并重新启动apache。

为了便于调试,我通常喜欢手动执行php文件(可以请求更多错误而无需在主要的ini中设置它)。这样做添加标题:

#!/usr/bin/php
ini_set("display_errors", 1);
ini_set("track_errors", 1);
ini_set("html_errors", 1);
error_reporting(E_ALL);

到文件的开头,使用chmod +x myscript.php为其授予权限并执行./myscript.php。它非常注意,特别是在繁忙的服务器上写了很多日志文件。

修改

听起来像权限问题。创建一个bash脚本,执行简单的echo "helo world"并尝试运行它。确保您拥有文件和包含文件的文件夹的权限。你只需要chmod 755进行测试。

答案 1 :(得分:6)

由于您要退出PHP上下文到本机shell,因此调试时会遇到很多问题。

我过去使用的最好和最简单的方法是将脚本的输出写入日志文件并在PHP执行期间将其拖尾。

<?php
shell_exec("filename > ~/debug.log 2>&1");

然后在一个单独的shell中:

tail -200f ~/debug.log

执行PHP脚本时,shell调用中的错误和输出将显示在debug.log文件中。

答案 2 :(得分:4)

您可以检索输出并返回exec命令的代码,这些命令可能包含可以解释问题的信息......

exec('my command', $output, $return);

答案 3 :(得分:3)

还有一些注释

  • 对于调试,请始终将您的exec / shell_exec函数包装在var_dump()中。

  • error_reporting(-1);应该是display_errors,应该是最后的手段set_error_handler("var_dump"); - 如果只是为了看看PHP本身是否没有调用{{1}或者其他。

  • 使用2>&1(将shell STDERR合并到STDOUT流)以查看调用失败的原因。 在某些情况下,您可能需要将命令包装在另外的shell调用中:

    execvp

    除了@Mike建议的日志文件重定向,这是最值得推荐的方法。

  • 在各种exec函数之间交替显示错误消息。虽然它们主要做同样的事情,但输出返回路径会有所不同:

    1. exec()→或者将输出作为函数结果返回,或者通过可选的// capture STDERR stream via standard shell shell_exec("/bin/sh -c 'ffmpeg -opts 2>&1' "); 参数返回。
      还提供了一个$output参数,其中包含运行应用程序或shell的errno / exit代码。你可能会得到:

      • $return_var(2) - 没有这样的文件
      • ENOENT(127) - IO错误:找不到文件
    2. shell_exec()→您希望主要针对shell样式表达式运行 请务必使用例如分配/打印返回值。 EIO

    3. `` 内联反引号→与var_dump(shell_exec("..."));相同。

    4. system()→与shell_exec类似,但始终将输出作为函数结果返回(打印出来!)。另外还允许捕获结果代码。

    5. passthru()→是另一个exec替代方案,但始终将任何STDOUT结果发送到PHP输出缓冲区。这通常使它成为最合适的exec包装。

    6. popen()或更好proc_open()→允许分别捕获STDOUT和STDERR。

  • 未重定向时,大多数shell错误都会在PHP或Apaches exec 中出现。如果没有产生有用的错误消息,请检查您的syslog或Apache日志。

最常见的问题

  • 正如@Kuf所述:对于过时的虚拟主机计划,您仍然可以找到 error.log safe_mode 。 PHP exec函数都不起作用。 (最好找一个更好的提供者,否则调查&#34; CGI&#34; - 但安装你自己的PHP解释器,而不用。)

  • 同样可以 AppArmor / SELinux / Firejail 。这限制了每个应用程序产生新进程的能力。

  • 目标二进制文件不存在。几乎没有虚拟主机确实预装了disable_functions之类的工具。您无需准备就可以运行任意shell命令。 需要安装一些东西!

    ffmpeg
  • // Check if `ffmpeg` is actually there: var_dump(shell_exec("which ffmpeg")); 已关闭。如果您安装了自定义工具,则需要确保它们可以访问。使用PATH将搜索所有常见路径 - 或者已经告知/约束Apache(通常只是var_dump(shell_exec("ffmpeg -opts")))。

    使用/bin:/usr/bin检查PATH包含的内容以及是否包含您要运行的工具。否则,您可能需要调整服务器设置(/ etc / apache2 / envvars),或使用完整路径:

    print_r($_SERVER);

    这有点颠覆了shell的概念。就个人而言,我并不认为这是可取的。但它确实有助于安全目的;此外,当然还要使用自定义安装。

  • <强>权限

    1. 为了在BSD / Linux系统上运行二进制文件,需要制作&#34;可执行文件&#34;。这是// run with absolute paths to binary var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'")); 的作用。

    2. 进一步模式这些自定义二进制文件的路径需要由运行PHP脚本的 Apache用户读取。

    3. 更现代的设置使用PHP内置FPM模式(suexec + FastCGI),其中您的虚拟主机帐户等于PHP运行的帐户。

  • 使用 SSH 进行测试。应该不言而喻,但在通过PHP运行命令之前,在真正的shell中测试它将是非常明智的。例如探测chmod a+x ffmpeg如果所有的lib依赖项都存在,那么它是否正常工作。

  • 作为exec 字符串中的命令参数传递的输入值(GET,POST,FILE名称,用户数据)需要使用escapeshellarg()进行转义。

    ldd ffmpeg

    否则你很容易得到shell语法错误;并且可能会利用稍后安装的代码......

  • 注意不要将反引号与任何$q = "escapeshellarg"; var_dump(shell_exec("echo {$q($_GET['text'])} | wc")); 函数结合使用:

    *exec()

    Backticks将运行该命令,并将shell_exec保留为已运行命令的输出。使用常规引号包装命令参数。

  • 同时检查shell会话中预期程序如何与其他帐户一起使用:

    $null = shell_exec(`wc file.txt`);
                       ↑           ↑
    

    值得注意的是,PHP-FPM设置使用相应的用户ID进行测试。 sudo -u www-data gpg -k / www-data大多只是由旧的mod_php设置使用。

    许多cmdline工具依赖于某些每用户配置。此测试通常会揭示缺失的内容。

在Windows上

  • CMD调用通常不会很好地与STDERR流一起使用。

  • 绝对尝试使用Powershell脚本运行其他任何CLI应用程序,或使用如下命令行:

    apache
  • 使用完整路径,并且如果路径包含空格,则优先使用正斜杠(system("powershell -Command 'pandoc 2>&1'"); 和其他引号)。

      自从它们在MS-DOS 2.0中引入以来,

    正斜杠也在Windows上工作

  • 找出which service and SAM account IIS / Apache和PHP运行为。验证它是否具有执行权限。

  • 您通常无法运行GUI应用。 (典型的解决方法是taskscheduler或WMI调用。)