注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

itoedr的it学苑

记录从IT文盲学到专家的历程

 
 
 

日志

 
 

PHP5调用外部命令的方式/php调用外部特权命令的方法  

2014-03-15 14:18:56|  分类: php开发技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

本文探究构建到 PHP 中的工具,让您了解 PHP 运行的底层 shell 环境和文件系统。PHP 为执行外部命令提供大量函数,其中包括 shell_exec()exec()passthru()system()。这些命令是相似的,但为您运行的外部程序提供不同的界面。所有这些命令都衍生一个子进程,用于运行您指定的命令或脚本,并且每个子进程会在命令输出写到标准输出 (stdout) 时捕捉它们。

 shell_exec()

 shell_exec() 命令行实际上仅是反撇号 (`) 操作符的变体。如果您编写过 shell 或 Perl 脚本,您就知道可以在反撇号操作符内部捕捉其他命令的输出。例如,清单 1 显示了如何使用反撇号在当前目录中获取每个文本(.txt)的单词计数。


***************************************

php的popen()函数打开进程

***************************************


原型: resource popen ( string $command , string $mode )
说明: 能够和命令进行交互。之前介绍的方法只能简单地执行命令,却不能与命令交互。有时须向命令输入一些东西,如在增加系统用户时,要调用su来把当前用户换到root用户,而su命令必须要在命令行上输入root的密码。这种情况下,用之前提到的方法显然是不行的。
popen( )函数打开一个进程管道来执行给定的命令,返回一个文件句柄,可以对它读和写。返回值和fopen()函数一样,返回一个文件指针。除非使用的是单一的模 式打开(读or写),否则必须使用pclose()函数关闭。该指针可以被fgets(),fgetss(),fwrite()调用。出错时,返回 FALSE。
<?php
error_reporting(E_ALL);
 
/* Add redirection so we can get stderr. */
$handle = popen('/path/to/executable 2>&1', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);
?>


清单 1. 使用反撇号计算单词数量

				
#! /bin/sh
number_of_words=`wc -w *.txt`
echo $number_of_words

#result would be something like:
#165 readme.txt 388 results.txt 588 summary.txt
#and so on....

 

在您的 PHP 脚本中,您可以在 shell_exec() 中运行这个简单的命令,如清单 2 所示,并获取想要的结果。这里假设在同一个目录下有一些文本文件。


清单 2. 在 shell_exec() 中运行相同的命令

命令格式:string shell_exec ( string $cmd )	 说明: 直接执行命令$cmd			
例1:
<?php $results = shell_exec('wc -w *.txt'); echo $results; ?>

例2:

<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>


在图 1 中可以看到,获得的结果与从 shell 脚本得到的一样。这是因为 shell_exec() 允许您通过 shell 运行外部程序,然后以字符串的形式返回结果。


图 1. 通过 shell_exec() 运行 shell 命令的结果

PHP5调用外部命令的方式 - itoedr - itoedr的it学苑
 注意,仅使用后撇号操作符也会得到相同的结果,如下所示。


清单 3. 仅使用后撇号操作符

				
<?php
$results = `wc -w *.txt`;
echo $results;
?>

 

清单 4 给出了一种更加简单的方法。


清单 4. 更加简单的方法

				
<?php
echo `wc -w *.txt`;
?>

 

通过 UNIX 命令行和 shell 脚本能够完成很多东西,知道这点很重要。例如,您可以使用竖线将命令连接起来。您甚至可以使用操作符在其中创建 shell 脚本,并且仅调用 shell 脚本(根据需要使用或不使用参数)。

 

例如,如果您仅希望计算该目录下的前 5 个文本文件的单词数,那么可以使用竖线 (|) 将 wchead 命令连接起来。另外,您还可以将输出结果放到 pre 标记内部,让它能够更美观地呈现在 Web 浏览器中,如下所示。


清单 5. 更加复杂的 shell 命令

				
<?php
$results = shell_exec('wc -w *.txt | head -5');
echo "<pre>".$results . "</pre>";
?>

 

图 2 演示了运行清单 5 的脚本得到的结果。


图 2. 从 shell_exec() 运行更复杂的 shell 命令得到的结果

 

PHP5调用外部命令的方式 - itoedr - itoedr的it学苑
         在本文的后面部分,您将学习如何使用 PHP 为这些脚本传递参数。现在您可以将它看作运行 shell 命令的一种方法,但要记住您只能看到标准输出。如果命令或脚本出现错误,您将看不到标准的错误 (stderr),除非您通过竖线将它添加到 stdout

 

:::passthru()

 

passthru() 允许您运行外部程序,并在屏幕上显示结果。您不需要使用 echoreturn 来查看结果;它们会显示在浏览器上。您可以添加可选的参数,即保存从外部程序返回的代码的变量,比如表示成功的 0,这为调试提供更好的机制。

 

在清单 6 中,我使用 passthru() 命令运行在前面小节运行的单词计数脚本。如您所见,我还添加一个包含返回代码的 $returnval 变量。


清单 6. 使用 passthru() 命令运行单词计数脚本

				
<?php
passthru('wc -w *.txt | head -5',$returnval);
echo "<hr/>".$returnval;
?>

 

注意,我不需要使用 echo 返回任何东西。结果会直接显示在屏幕上,如下所示。


图 3. 使用 return 代码运行 passthru() 命令的结果

PHP5调用外部命令的方式 - itoedr - itoedr的it学苑
 

 在清单 7 中,我通过删除脚本头部的 5 前面的短横线 (-) 引入一个小错误。


清单 7. 在单词计数脚本中引入一个错误

				
<?php
//we introduce an error below (removing - from the head command)

passthru('wc -w *.txt | head 5',$returnval);
echo "<hr/>".$returnval;
?>

注意,脚本未能按照预期运行。您得到的是一个空白的屏幕,一条水平线和返回值 1,如图 4 所示。这个返回代码通常表明发生了某些错误。如果能够测试返回代码,查找和修复错误就容易多了。


图 4. 使用 passthru() 时查看错误代码

PHP5调用外部命令的方式 - itoedr - itoedr的it学苑
 

 ::::exec()

       exec() 命令与 shell_exec() 相似,不同之处是它返回输出的最后一行,并且可选地用命令的完整输出和错误代码填充数组。清单 8 展示了当运行 exec() 而不捕捉数据数组中的数据时发生的事情。


清单 8. 运行 exec() 而不捕捉数据数组中的数据

				
<?php
$results = exec('wc -w *.txt | head -5');
echo $results;

#would print out just the last line or results, i.e.:
#3847 myfile.txt
?>

 

为了捕捉数组中的结果,要将该数组的名称作为第二个参数添加到 exec()。我在清单 9 中执行了这个步骤,并以 $data 作为数组的名称。


清单 9. 从 exec() 捕捉数据数组的结果

				
<?php
$results = exec('wc -w *.txt | head -5',$data);
print_r($data);

#would print out the data array:
#Array ( [0]=> 555 text1.txt [1] => 283 text2.txt) 
?>

 

在捕捉数组中的结果之后,您可以对每行进行一些处理。例如,您可以在第一个空格处进行划分,将分离的值存储在数据库表中,或对每个行应用特定的格式或标记。

 

system()

 

如清单 10 所示,system() 命令是一种混合体。它像 passthru() 一样直接输出从外部程序接收到的任何东西。它还像 exec() 一样返回最后一行,并使返回代码可用。


清单 10. system() 命令

				
<?php
system('wc -w *.txt | head -5');

#would print out:
#123 file1.txt 332 file2.txt 444 file3.txt
#and so on
?>

*********************************************************************
php执行特权命令的一些方法
*********************************************************************

php调用linux系统特权命令的一些方法 

       在php中,调用linux系统命令, 可使用php中的system()、exec()和passthru()函数实现。在php中调用只有root权限才能执行的命令,会出现权限不够的问题。下面对php中调用linux系统命令 的方法,以及解决权限问题的方法,给出一个解决办法。

1.php调用系统命令的方法

a. system()

原型:string system (string command [, int return_var])
system()函数执行给定的命令,输出和返回结果。第二个参数是可选的,用来得到命令执行后的状态码.system()返回命令执行后的最后一行结果

b. exec()

原型:string exec(string command [, string array [, int return_var]])
exec()函数与system()类似,也执行给定的命令,但不输出结果,而是返回结果的最后一行。 虽然它只返回命令结果的最后一行,但用第二个参数array 可以得到完整的结果,方法是把结果逐行追加到array的结尾处。如果array不是空的,在调用之前最好用unset()把它清除干净。只有指定了第二 个参数时,才可以用第三个参数,用来取得命令执行的状态码。

c. passthru()
原型:void passthru (string command [, int return_var])
passthru ()只调用命令,不返回任何结果,但把命令的运行结果原样输出到标准输出设备上。所以passthru()函数经常用来调用象pbmplus (Unix下的一个处理图片的工具,输出二进制的原始图片的流)这样的程序。同样它也可以得到命令执行的状态码。

d. ` `

使用单的反撇号对` `, 将shell命令写入其中,就可实现对命令的执行。

上述四种方式,执行同一命令:

<?php

echo "1 system : ";
system("whoami");

echo "2 exec : ";
exec("whoami");

echo "3 passthru : ";
passthru("whoami");

echo "4 `` : ";
`whoami`;

?>

效果如下:

1 system : apache 2 exec : 3 passthru : apache 4 `` :

system()和passthru()输出结果,exec和``不输出结果。使用echo exec() 或echo ``,可以显示命令运行结果。

2.权限问题

对于权限问题,网上有给出一些解决思路,试过一些,并不都可行,两个靠谱一些,也好理解一些的方法如下:

a. sudo

sudo是Linux中的一个命令工具,通过配置sudo的配置文件/etc/sudoers, 可以让普通用户执行某些需要root权限才能执行的命令,如chmod, iptables 等等。

编辑配置文件sudoers: # visudo

           sudoers中的注释部分介绍了sudoers的功能,并给出了配置的example。可以根据自己的需要添加配置,例如,想让piranha用户在本机上无需密码就能以root权限执行iptables命令和chmod命令,可以在sudoers最后添加如下语句:

                                 piranha   localhost    =   (root)          NOPASSWD: /sbin/iptables ,/bin/chmod

语句中各项对应:  用户      主机          执行命令的身份          无需密码                   命令列表

配置完成后,以piranha用户登录系统,可以通过sudo来以root权限执行相应命令,如:

$iptables -L       //会提示  Permission denied (you must be root)

$sudo iptables  -L       // 则会显示当前iptables规则

             示意截图:


(www-data ALL=(root) NOPASSWD:/usr/bin/traffic_line)

PHP5调用外部命令的方式/php调用外部特权命令的方法 - itoedr - itoedr的it学苑
授权web访问特权命令
 

       尽管在命令行中,sudo可使普通用户执行root权限才能执行的命令,但自己在php中做测试的时候,发现,尽管在sudoers中赋予了执行php脚本 的当前用户执行所有命令的权限,但在php中使用passthru("sudo iptables -L");命令没有执行,很是纳闷。

b. setuid()

在linux中,当执行一个具有setuid(即set user ID)权限的文件时,文件的执行过程将具有文件所有者的特权。这样,可以利用setuid,在php中执行root用户的setuid权限的程序。

例如,想要让piranha用户能在php中调用iptables命令,可以编写一个C++源程序,先setuid(0),再system(cmd), 编译生成可执行文件,将可执行文件设置setuid权限,最后在php中调用可执行文件。具体如下:

cmd.cpp:

#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string>
#include<exception>
#include<iostream>
using namespace std;
int main(int ac,char **argv)         // 获取iptables命令参数
{
 string get("");
 for(int i=1;i<ac;i++){
  string temp(argv[i]);
  get+=" ";
  get+=temp;
 }
 string cmd=get;    //命令字符串 
 setuid(0);  //将当前用户的uid设置为0 (root用户的uid为0),使其具有root权限
 system(cmd.c_str());          //执行命令
}

以root身份登录,编译cmd.cpp,生成可执行文件cmd:

           #g++ cmd.cpp -o cmd

给cmd添加setuid权限:

          #chmod u+s cmd

          (通过 #ls -l  filename 查看相应文件权限及其他信息)

在php页面中调用cmd:

<?php

$cmdstr="iptables -L";           //$cmdstr可赋值为想执行的命令字符串

system("/root/cmd $cmdstr");   //调用cmd, 执行命令

// exec("/root/cmd $cmdstr");

//passthru("/root/cmd $cmdstr");

// `/root/cmd $cmdstr`;

?>

***********************************
jquery ajax例子
***********************************
1.$.load();
2.$get();
3.$post();
5.$.getScript( url, [callback] ) : 通过 GET 方式请求载入并执行一个 JavaScript 文件。
url (String) : 待载入 JS 文件地址。
callback (Function) : (可选) 成功载入后回调函数。
  评论这张
 
阅读(343)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017