PHP可执行文件将在命令行中运行,但不能在浏

时间:2016-05-23 03:46:00

标签: php python raspberry-pi exec

所以使用'php index.php'在命令行中给出了我想要的输出。但是不会在网页上给出输出。 首先,我有这个python文件基本上可以做我想要的一切:

import subprocess

subprocess.call("sudo nmap -sP 192.168.1.0/24 > /home/pi/whohome.txt", shell=True)

searchfile = open("/home/pi/whohome.txt", "r")
for line in searchfile:
    if "android-5ab6eb374b5fd6" in line: print "Jeremy is home (phone)"
    if "Jeremys-MBP" in line: print "Jeremy is home (computer)"
    if "LMCMs-iPhone" in line: print "Liam is home (phone)"
    if "Liam" in line: print "Liam is home (computer)"
    if "android-4a186cbbeb2c5229" in line: print "Lara is home (phone)"
    if "LaraD" in line: print "Lara is home (computer)"
    if "KristiansiPhone" in line: print "Martin is home (phone)"
    if "Martins-MBP" in line: print "Martin is home (computer)"

searchfile.close()

其次我只有一个sh可执行文件,它将把这个python命令的输出放到另一个文本文件中:

python /home/pi/myRoomMates.py > /var/www/html/website.txt

然后我在一个运行在raspberry pi上的apache web服务器上安装了php文件,它显示为:

<?php
shell_exec('/home/pi/whoishome.sh');

echo file_get_contents ("/var/www/html/website.txt");

?>

所以,如果我没有错,每次刷新页面时都应执行该操作,等待exec完成,然后显示txt文件内容?我已经尝试了shell_exec和exec,它们都做同样的事情。

2 个答案:

答案 0 :(得分:1)

有很多权利,你必须确保:

  1. apache用户必须在sudoers组中
  2. apache用户必须写入/home/pi/whohome.txt
  3. apache用户必须写入/var/www/html/website.txt
  4. /home/pi/whoishome.sh必须是apache用户的可执行文件
  5. 对于第1点到第3点,给apache用户这些权利通常不是一个好主意。

    如果以Python CGI开始你的python脚本,你可以更轻松:

    import subprocess
    
    ADDRESS = "192.168.1.0/24"
    
    USERS = {
        "android-5ab6eb374b5fd6": ("Jeremy", "phone"),
        "Jeremys-MBP": ("Jeremy", "computer"),
        "LMCMs-iPhone": ("Liam", "phone"),
        "Liam": ("Liam", "computer"),
        "android-4a186cbbeb2c5229": ("Lara", "phone"),
        "LaraD": ("Lara", "computer"),
        "KristiansiPhone": ("Martin", "phone"),
        "Martins-MBP": ("Martin", "computer"),
    }
    
    
    nmap = subprocess.Popen(["sudo", "nmap", "-sP", ADDRESS], stdout=subprocess.PIPE)
    for line in nmap.stdout:
        for user, name in USERS.items():
            if user in line:
                print "%s is home(%s)" % name
    nmap.wait()
    

    唯一的第1点和第4点必须填满。

答案 1 :(得分:1)

我怀疑您的问题是sudo命令行的nmap部分。如果您将subprocess.call替换为subprocess.check_call,我认为您会发现该命令会引发CalledProcessError

据推测,您的用户帐户位于/etc/sudoers文件中,但Web服务器不在。

由于shell的输出重定向运算符(>)所做的第一件事是截断输出文件,因此尝试运行nmap失败会导致零字节whohome.txt。然后,Python脚本的其余部分对website.txt执行相同操作,最终您的网站上无法显示任何内容。

解决方案

不需要sudo

在我的Linux桌面上,需要以root身份运行nmap 才能执行本地ping扫描。如果您的系统上的情况属实,那么您应该可以删除sudo命令的nmap部分,并完成它。

是一个区别。当nmap运行-pS ping扫描时,root会对每个目标执行更全面的测试。从旧的nmap手册页(重点添加):

  

-sP(跳过端口扫描)。

     

[...]

     

-sP选项默认发送ICMP回送请求,TCP SYN到端口443,TCP ACK到端口80,以及ICMP时间戳请求。 由非特权用户执行时,只有SYN数据包(使用连接呼叫)发送到目标上的端口80和443。 当特权用户尝试扫描本地以太网网络上的目标时,除非指定--send-ip,否则将使用ARP请求。 [...]

为您的Web服务器启用sudo

如果您需要这些额外信息(听起来就像这样),您需要以超级用户权限运行nmap(或调用它的Python脚本)。我从未试图强制Web服务器执行此操作,但我认为您至少必须将Web服务器的用户添加到/etc/sudoers。类似的东西:

apache    localhost=/usr/bin/nmap -sP

或:

httpd    ALL=/usr/local/bin/nmap

...依此类推,具体取决于用户名,nmap所在的位置,您希望将参数限制为nmap的严格程度等等。

创建一个SUID可执行文件,为您运行nmap

或者(我讨厌自己推荐这个 - 必须是一种更好的方法)是编写一个只执行的小型SUID(设置用户ID)程序你想要的nmap命令。这是一个可以做到的C程序:

#include <stdio.h>
#include <unistd.h>

int main(void);

int main(void) {
    int retval = 0;
    char* const error_string = "ERROR: Failed to execute \"/usr/bin/map\"";
    char* const nmap_args[] = {
      "/usr/bin/nmap",
      "-sP",
      "192.168.1.0/24",
      NULL
    };

    retval = execv("/usr/bin/nmap", nmap_args);
    /* execv returns _only_ if it fails, so if we've reached this
     * point, print an error and exit.
     */
    perror(error_string);
    return retval;
}

将上述内容保存为类似nmap_lan.c的内容,并使用以下内容进行编译:

$ gcc -Wall -o nmap_lan nmap_lan.c

然后,将其移至您保留网站脚本的任何位置,并将作为root 移动,更改其所有权和权限:

# chown root:root nmap_lan  # Or whatever group name you use.
# chmod 4555 nmap_lan

前导4设置SUID位。目录的颜色ls可能会显示该文件突出显示。权限应如下所示:

# ls -l nmap_lan
-r-sr-xr-x. 1 root root 6682 May 23 03:04 nmap_lan

任何运行nmap_lan的用户都将被暂时提升为拥有nmap_lan文件的用户(在本例中为root),直到程序退出为止。这是非常慷慨的,这就是为什么我在该程序中硬编码所有的原因......为了改变它所做的任何事情 - 即使只是扫描的IP范围 - 你将不得不编辑{ {1}}文件,重新编译和重新安装。

我在我的命令行上测试了nmap_lan.c,当由非特权用户运行时,它会产生特权用户nmap_lan输出,而这些用户通常只能获得有限的输出。

对Python脚本的评论

一般来说,Python在解析shell参数方面非常比shell更好(因为nmap的默认值是shell),所以你的Python脚本尽可能多地完成工作,包括解析shell命令,重定向输入和重定向输出。

在Python中完成工作的一个主要优点是无法打开,读取,写入或关闭任何文件将导致立即崩溃和堆栈跟踪 - 而不是您已经发生的无声失败处理。

我重写了False命令以使用明确分隔的参数列表。您可以通过将打开的文件流传递给call参数来处理输出重定向。您可以通过让Python打开输出文件并明确地写入它来消除最后一点shell重定向。

stdout

此外,除非您需要nmap_file='/home/pi/whohome.txt' with open(nmap_file, 'wt', encoding='ascii') as fout: subprocess.call( ['/usr/bin/nmap', '-sP', '192.168.1.0/24'], # Or just ['nmap_lan'] stdout=fout, universal_newlines=True, ) output_file='/var/www/html/website.txt' with open(nmap_file, 'rt', encoding='ascii') as fin: with open(output_file, 'wt', encoding='ascii') as fout: for line in fin: ... print('Output here', file=fout) # Add `file=...` to each print. 文件用于其他内容,否则可以使用check_outputwhohome.txt命令的输出存储为字符串,然后拆分,从而完全消除它它分成几行。 (nmap参数还处理将universal_newlines对象转换为bytes,至少在Python 3中。)

str

请注意,我使用lines = subprocess.check_output( ['/usr/bin/nmap', '-sP', '192.168.1.0/24'], # Or just ['nmap_lan'] universal_newlines=True ).split('\n') output_file='/var/www/html/website.txt' with open(output_file, 'wt', encoding='ascii') as fout: for line in lines: ... print('Output here', file=fout) # Add `file=...` to each print. 块来免费关闭文件。

(最后,那一系列with命令急于被重写为if循环,你正在搜索的字符串作为该字典中的键,以及你想要的输出打印为值。)