2012-08-30 105 views
11

exec命令在我的服务器上不起作用,它什么都不做,我已经关闭了safe_mode,并且验证了所有的控制台命令正在工作,我尝试过使用绝对路径。我已经检查了应用程序的权限以及我需要的所有应用程序的执行权限。我不知道还有什么可以做的,这里是我试过的代码的简要介绍。如何调试exec()问题?

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命令不能正常工作。 原谅我英语不好。

+0

你是什么意思“不工作”?任何错误输出? – Touki

+0

您是否尝试过error.log? – Rolice

+0

错误设置'display_errors = 1'和'error_report = E_ALL'? (请注意,您不应该在实时系统上显示错误,如果完成,请将其禁用) – KingCrunch

回答

10

看看/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只是为了测试。

+0

'disable_functions'在我的'php.ini'中是空的,我按照你的建议运行脚本,控制台不显示任何东西。 – carcargi

+0

@Necroside答案已更新。 – Kuf

+0

非常感谢,这是一个窍门,问题在于某种程度上(因为我的客户可以访问服务器,他认为他是专家XD),他复制并更改了应用程序的权限。我已经将它们移回原始文件夹并重新配置路径,现在一切正常,我在测试应用程序的权限时发现了这一点。 谢谢。 – carcargi

4

可以retreive输出和返回exec命令的代码,放入系统的威力包含可以解释这个问题的信息...

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

刚刚将代码添加到问题中,没有注意到这个答案,它只是显示了这一点。 '错误 Array()' – carcargi

+0

什么包含$ return_val变量? – YohannP

5

由于您正在将PHP上下文退出到本机shell中,因此您将遇到很多调试问题。

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

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

然后,在一个单独的shell:

tail -200f ~/debug.log 

当你执行你的PHP脚本,你的错误,并从你的shell调用输出会在你debug.log文件中显示。

0

还有一些笔记。

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

  • error_reporting(-1);应该是,因为要display_errors,作为最后的手段,即使set_error_handler("var_dump"); - 如果只看到如果PHP本身没有援引execvp否则后果不堪设想。

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

    // capture STDERR stream via standard shell 
    shell_exec("/bin/sh -c 'ffmpeg -opts 2>&1' "); 
    

    否则日志文件重定向通过@Mike作为建议是最值得推荐的做法。

  • 在各种可执行函数之间进行交替以发现错误消息。虽然他们大多是做同样的事情,输出返回路径各不相同:

    1. exec()→要么返回输出函数的结果,或通过可选的$output paramater。
      还提供了一个$return_var参数,其中包含运行应用程序或shell的errno/exit代码。你可能会得到:

      • ENOENT(2) - 没有这样的文件
      • EIO(127) - IO错误:文件未找到
    2. shell_exec()→是要大多运行壳什么式表达式。
      一定要用例如分配/打印返回值。 var_dump(shell_exec("..."));

    3. ``反引号→是相同的shell_exec

    4. system()→与exec类似,但总是返回输出作为函数结果(打印出来!)。此外允许捕获结果代码。

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

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

  • 大多数壳中的错误PHP的或阿帕奇error.log拉闸不重定向时。如果没有提供有用的错误消息,请检查您的系统日志或Apache日志。

困扰PHP/LAMP新人最常见的问题是:由于@Kuf提到

  • :过时的虚拟主机方案,你仍然可以找到safe_mode或启用disable_functions。没有一个PHP exec函数可以工作。 (最好找一个更好的供应商,否则调查 “CGI” - 但而unversed不自己安装PHP解释器)

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

  • 预期的二进制不存在。几乎没有网络主机预装了类似ffmpeg的工具。没有准备,你不能只运行任意的shell命令。 有些东西需要安装!

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

    请使用print_r($_SERVER);进行检查您的PATH包含的内容是否包含您想要运行的工具。否则,你可能需要调整服务器设置(在/ etc/apache2的/ envvars中),或者使用完整路径:

    // run with absolute paths to binary 
    var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'")); 
    

    这在一定程度上颠覆了壳的概念。我个人并不认为这是可取的。尽管如此,它对安全的目的确实有意义;此外用于使用当然的定制安装。

  • 权限

    1. 为了运行BSD/Linux系统上的二进制,它需要进行 “可执行”。这是chmod a+x ffmpeg所做的。

    2. 进一步模拟此类自定义二进制文件的路径需要可供您的PHP脚本运行的Apache用户读取。

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

  • 测试与SSH。它应该不用说,但在通过PHP运行命令之前,在真实shell中测试它将非常明智。用例如探针ldd ffmpeg如果所有的lib依赖关系都存在,并且它否则可以工作。

  • 的输入值(GET,POST,文件名,用户数据)获得在EXEC串命令参数传递需要与escapeshellarg()进行转义。

    $q = "escapeshellarg"; 
    var_dump(shell_exec("echo {$q($_GET['text'])} | wc")); 
    

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