PHP如何执行命令

Posted

技术标签:

【中文标题】PHP如何执行命令【英文标题】:PHP how to execute a command 【发布时间】:2012-03-06 23:46:44 【问题描述】:

我正在尝试使用 LibreOffice 将电子表格转换为另一种格式,当我从控制台执行命令时它工作正常,但是当我使用 exec() 或 system() 从 php 执行它时它不起作用。 它没有显示任何错误或任何东西,它只是默默地失败,如果我尝试执行一些简单的命令,如“ls”,它就可以正常工作。

这是我正在使用的命令:

<?php
system("libreoffice --headless -convert-to ooxml '/home/www/path_to_app/file.xlsx' -outdir /home/www/path_to_app/");

我已经尝试将 /opt/lampp/etc/httpd.conf 上的 apache 用户和组更改为与我相同的登录用户。

我想知道问题是否在于 www 文件夹是 /home 而不是我的用户内部,这会导致权限问题,但到目前为止无法使其工作。

任何帮助将不胜感激。

【问题讨论】:

尝试在你的命令中指定libreoffice的完整路径,例如/usr/local/bin/libreoffice 或安装它的任何地方,看看是否能让你走得更远。 有愚蠢的风险 - exec() 不会返回错误消息,您确定它会默默地失败吗?你试过 passthru() 吗? 【参考方案1】:

我用下面的命令解决了这个问题:

system('
  export HOME=/tmp 
  libreoffice --headless --invisible --norestore --convert-to pdf --outdir /my/folder /my/file/calc.xls');

【讨论】:

这里有类似的想法 (superuser.com/questions/627266/…)。 你拯救了我的一天!神奇的是 -> HOME=/tmp ,我认为这是因为 apache 用户没有任何 $HOME 文件夹。【参考方案2】:

我用下面的命令解决了这个问题:

exec('libreoffice --headless --invisible --norestore --convert-to pdf --outdir /my/folder /my/file/calc.xls');

只需检查权限,libreoffice 使用用户主文件夹,如果您使用 Ubuntu 的默认设置,则 PHP 运行 oenter 代码此处 www-data 权限,它的主目录是 /var/www/,但默认此目录归 root.enter 所有代码在这里

在 PHP 中 - 你可以看到 rigths:

exec('whoami', $arr);
print_r($arr);

在控制台中 - 您可以看到您的 HOME 并提供正确的权限:

su wwww-data
echo $HOME
exit;
chown www-data:www-data /var/www -R

【讨论】:

这在 CentOS 下的 nginx 上对我有用:chown apache:apache /var/www -R。你拯救了我的一天。谢谢。 CentOS 6.3 x86_64 libreoffice4.2 上也为我工作......最重要的是非常感谢你先生......【参考方案3】:

尽管你提到了draw010 的$PATH,但我不会这样做。

LibreOffice 是一个非常大的程序,有很多你不知道的代码,它会在你的 $HOME 目录中生成和更新文件,而且你肯定不能运行更多的东西一次一份。

因此,与其让您的 Web 服务器启动 LibreOffice,并通过以比“www-data”或“nobody”更高的用户身份运行它来破坏 Apache 的安全性,不如创建一个处理程序。

首先,确认您可以从终端运行libreoffice ... 命令行。为了更加确定您没有任何 X11 依赖项,请在测试命令行之前在 xterm 中运行 unset DISPLAY(对于 bash)或 unsetenv DISPLAY(对于 tcsh)。它会破裂吗?先解决这个问题。它有效吗?很好,然后继续使用处理程序。

你的处理程序,最简单的形式,可以是一个永远循环的脚本,检查假脱机目录中的“要处理的文件”,如果找到它们,使用 libreoffice 转换它们并将生成的文件放在它可能的位置由您的网络应用找到。

#!/bin/sh

while sleep 10; do
  if [ `ls /var/tmp/myspool/ | grep -c '\.xlsx$'` -gt 0 ]; then
    ls /var/tmp/myspool/*.xlsx | while read file; do
      /usr/local/bin/libreoffice --headless -convert-to ooxml "$file" yadda yadda
      if [ $? = 0 ]; then
        mv "$file" "/var/tmp/myspool/done/
      fi
    done
  fi
done

如果您不希望“轮询”(每 10 秒检查一次假脱机目录)的开销,那么您可以让您的 PHP 脚本在日志中添加一行,由您的处理程序监视。例如:

<?php

// process form, save file to spool dir
syslog(LOG_NOTICE, "Saved: " . $filename);

?>

确保您已配置 syslog 以将这些消息存储在例如 /var/log/filelog 中,然后您的处理程序就可以跟踪日志。

#!/bin/sh

tail -F /var/log/filelog | while read line; do
  filename="`echo \"$line\" | sed 's/.*Saved: //'`"
  /usr/local/bin/libreoffice --headless -convert-to ooxml "$file" yadda yadda
  # etc ... error handling and mv as in the other script
done

明白了吗?

【讨论】:

谢谢,这似乎是个好方法。我已经很久没有解决这个问题了,但下次我会试试这个。【参考方案4】:

我之前也遇到过同样的问题.....

这个解决方案似乎对我有用...

function execInBackground($cmd)  
    if (substr(php_uname(), 0, 7) == "Windows") 
        pclose(popen("start /B ". $cmd, "r"));  
     
    else  
        exec($cmd . " > /dev/null &");   
     
 

$mainFile = "YOUR FILE";     
$cmd2 = "export HOME=/tmp
             libreoffice --headless --invisible --norestore --convert-to pdf " .
                    "'$mainFile'";



        $saved = getenv("LD_LIBRARY_PATH");        // save old value 
        $newld = "/usr/lib";  // extra paths to add 
        if ($saved) 

            putenv("LD_LIBRARY_PATH=" . $newld);
                   
                // set new value 
        //


        // command is loaded using 
        // libs in the new path list 
        execInBackground($cmd2);
        putenv("LD_LIBRARY_PATH=$saved");        // restore old value 

【讨论】:

以上是关于PHP如何执行命令的主要内容,如果未能解决你的问题,请参考以下文章

php执行外部命令,如何不等待返回结果

求教,如何在PHP上执行iptables的命令

如何从命令行执行 PHP 代码?

如何解决php执行exec函数ffmpeg命令不生效的问题

php如何执行linux的curl指令

如何使用Laravel命令执行外部PHP脚本?