从PHP执行Bash脚本并立即将输出返回到网页

4
我有一系列的bash和Perl脚本,用于开发Linux环境下所需的目录结构,并可选择从svn导出代码并将其打包。这在终端中可以很好地工作。现在客户要求为此过程创建一个Web界面。例如,在某个页面上点击“创建新包”按钮将依次调用以上步骤,并将输出作为脚本回应返回给用户,而不是整个脚本执行完成后再返回结果。是否可能将bash脚本的即时输出发送到调用它的PHP脚本或者网页上,通过程序执行函数(system、exec、passthru等)实现这个过程?有什么优雅的方法可以做到这一点吗?如果可能的话,我应该采取哪些安全预防措施呢?编辑后:经过一番搜索,我已经找到了部分解决方案,但仍未能实现。
$cmd = 'cat ./password.txt|sudo  -S  ./setup.sh ';

$descriptorspec = array(
        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
        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 read from
);

flush();

$process = proc_open($cmd, $descriptorspec, $pipes, './', array());
echo "<pre>";
if (is_resource($process)) {    

    while ($s = fgets($pipes[1])) {
        print "Message:".$s;
        flush();
    }
    while ($s = fgets($pipes[2])) {
        print "Error:".$s;
        flush();
    }
}
echo "</pre>";

输出:(网页)

Error:WARNING: Improper use of the sudo command could lead to data loss
Error:or the deletion of important system files. Please double-check your
Error:typing when using sudo. Type "man sudo" for more information.
Error:
Error:To proceed, enter your password, or type Ctrl-C to abort.
Error:
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:sudo: 3 incorrect password attempts**

我现在遇到的第一个问题是如何输入 sudo 密码

请帮忙!


相关:https://dev59.com/4XM_5IYBdhLWcg3wq1CF https://dev59.com/QkXRa4cB1Zd3GeqPqk4t - clt60
6个回答

5
我会使用一种主/从设计。从机将是您的 Perl/Bash 脚本,只需执行任务(打包、编译、导出代码等),并提供日志条目。
主机将是您的 PHP 进程。因此,原理如下:主机和从机共享通信渠道,并通过该通信渠道异步通信。
您可以想象一个类似于数据库的东西:
create table tasks ( id INT primary key, status INT, argument VARCHAR(100));

您的 PHP 页面应该切换用户选择,并且过滤输入:
switch ($_GET['action']) {
   case 'export':
       $argument = sanitize($_GET['arg']);
       add_task('export', $argument);
       break;
   case '...': 
     // ...
}

"add_task" 函数可能像这样:
function add_task($action, $arg)
{
   return $db->add('tasks', array($action, NEW_TASK, $arg);
}

奴隶可以通过 cron job 运行,并查询数据库,反馈任务的进展。
优点包括:
  • 独立的系统,便于发展。
  • 如果客户端断开连接,则不会丢失作业
  • 更容易安全
缺点包括:
  • 开始时会有一些复杂。
  • 由于奴隶运行的轮询时间(例如每 5 分钟运行一次),反应时间较慢
  • 比命令的直接输出少
请注意,您随后可以实现类似 xml-rpc 的触发器来运行奴隶,而不是使用消息传递系统。

你的回答提供了一些有趣的处理系统的选项。如果你有一些可工作的代码,或者类似的脚本/系统是按照这种方式设计的,我会很感激。谢谢。 - sakhunzai
抱歉,我只在Java分布式计算项目中使用过它们,在vhffs(vhffs.org,参见bots/文件夹)中使用了Perl。 - Aif
对Alf提出的方法表示赞同。这是一种满足此类要求的标准模式。它通过将“请求和监控”域与执行域分离,有助于解决大多数安全和控制问题。您可以为这些前端和后端服务使用单独的身份验证,并通过接口的数据和过程模型规范它们的交互。 - TerryE

1

您可以使用Comet web应用程序模型来实时更新结果页面。

对于sudo问题,作为一个快速而简单的解决方案,我会使用一组受限制的命令,这些命令是Web服务器可以在没有密码的情况下执行的。例如(添加到/etc/sudoers):

apache ALL=(ALL) NOPASSWD: /sbin/service myproject *

这将允许apache运行/sbin/service myproject stop/sbin/service myproject start等等。

看看Jenkins,它可以很好地处理Web部分,您只需要在构建中添加脚本即可。

更好的解决方案是,如Aif所建议的那样,将逻辑分离。一个守护进程等待任务,一个Web应用程序可视化结果。


1

最简单的方法是使用shell_exec来实现你的目的。它通过shell执行命令并将完整的输出作为字符串返回,因此你可以在网站上显示它。

如果这不适合你的目的,因为你可能想要在等待命令完成时得到一些响应,请查看php中其他可用的程序执行函数(提示:手册页面上有一些很好的评论)。

请注意,当以这种方式调用命令行脚本时,生成的输出将具有您的Web服务器(例如wwwrun或其他)的文件所有者、组和权限。如果部署的某些部分需要单独的所有者、组和/或文件权限,则必须在脚本中手动设置它们或在调用shell_exec之后进行设置(chmodchownchgrp可以在php中处理此问题)。
关于安全性: 许多基于Web的应用程序将这种功能放入单独的安装目录中,并请求您在安装后删除此目录。我甚至记得其中一些应用程序会不断地向管理员喊叫,除非它被删除。这是一种简单的方法,可以防止错误的人在错误的时间调用此脚本。如果您的应用程序在安装后可能需要它,则必须将其放入只有授权用户可以访问的区域(例如管理区域或类似区域)。

0

在使用 PHP 执行系统命令时,始终使用 escapeshellargescapeshellcmd 以确保安全性。建议将用户限制在尽可能受限的 chroot'd 目录中。


0

使用 /etc/sudoers 的 NOPASSWD 选项为特定用户提供自动化的 sudo 权限,然后使用前缀 sudo -u THE_SUDO_USER 运行命令,以便将命令执行为该用户。这可以避免给整个 Apache 用户 sudo 权限带来的安全漏洞,但也允许在 Apache 中从脚本中执行 sudo。


0

你似乎已经通过使用proc_open解决了将stdout和stdin输出到网页的问题。现在的问题看起来是通过sudo执行脚本。

从安全角度来看,让PHP应用程序以root身份运行脚本(通过sudo)让我感到不安。在password.txt中拥有root密码是一个相当大的安全漏洞。

如果可能的话,我会进行必要的更改,使得setup.sh可以由运行Apache的Unix用户运行。(我假设你正在使用Apache运行PHP。)如果setup.sh将由Web服务器执行,它应该能够在不使用sudo的情况下运行它。

如果你真的需要以不同的用户身份执行脚本,你可以查看suPHP,它被设计为以非标准用户身份运行PHP脚本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接