php exec转移,php的exec方法实现

一. 背景

我们最近有一项业务,购买百度云资源以及部署基础服务,流程是这样的根据不同用户的需求,生成用户需要购买资源的配置

调用百度云接口,购买资源,并且查询百度云实例购买的eip等信息

在我们的一台中控机上执行脚本,建立中控机和百度云购买实例之间的信任关系

信任关系建立后,可以启动部署脚本,将部署资源发送到百度云实例上

实际上,可以预先在百度云上打一个镜像,在购买实例的时候,指定镜像id,在某些时候,就可以不用传输基础服务资源到购买的实例了;但是,由于我们部署的每一个基础服务的配置不一样,还是需要一台中控机来发布服务

在发布服务的时候,需要建立信任关系,我们整个流程是通过php实现,面临的问题是两个php执行shell脚本问题,我们选择php的exec方法

建立信任关系涉及到服务之间的交互,我们选择expect来做这个交互,实际上,php也有实现交互的扩展,我们这次没有选择,主要是考虑到未来可能的php版本升级问题。

在使用中我们发现了一些问题,主要是expect的使用问题,这个在后面一篇博客上介绍一下,这篇文章,主要是关心php的exec实现,php的exec和我之前研究的php和Go语言之间的交互存在相关的地方,实际上也是跨语言的交互问题,那么php内置的exec是怎么实现调起服务的呢?

二. php的exec实现

exec是php标准方法,具体实现,在ext/standard/exec.c:250做了定义,我们通过gdb调试,打一个断点,来看看调用栈; 首先我们写了一个php脚本代码很简单,让php的源码执行一个ls -lecho exec("ls -l");

在gdb中执行

1

2

3

4

5

6

7

8

9

10

11

12(gdb) bt

#0 php_exec (type=0, cmd=0x101a5a8d8 "ls -l", array=0x0, return_value=0x101a16090) at ext/standard/exec.c:97

#1 0x00000001003c2574 in php_exec_ex (execute_data=0x101a160a0, return_value=0x101a16090, mode=0) at ext/standard/exec.c:231

#2 0x00000001003c241f in zif_exec (execute_data=0x101a160a0, return_value=0x101a16090) at ext/standard/exec.c:250

#3 0x00000001005d5538 in ZEND_DO_ICALL_SPEC_HANDLER (execute_data=0x101a16030) at Zend/zend_vm_execute.h:586

#4 0x0000000100579404 in execute_ex (ex=0x101a16030) at Zend/zend_vm_execute.h:417

#5 0x000000010057955a in zend_execute (op_array=0x101a73300, return_value=0x0) at Zend/zend_vm_execute.h:458

#6 0x0000000100515832 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at Zend/zend.c:1445

#7 0x000000010046c4a1 in php_execute_script (primary_file=0x7ffeefbff188) at main/main.c:2516

#8 0x000000010060531d in do_cli (argc=2, argv=0x7ffeefbff898) at sapi/cli/php_cli.c:977

#9 0x00000001006042b1 in main (argc=2, argv=0x7ffeefbff898) at sapi/cli/php_cli.c:1347

(gdb)

简述一下php的处理流程先解析出exec方法的输入参数,通过zend_parse_parameters()通用方法解析。

1

2

3

4

5

6

7

8

9if (mode) {

if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/", &cmd, &cmd_len, &ret_code) == FAILURE) {

RETURN_FALSE;

}

} else {

if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/z/", &cmd, &cmd_len, &ret_array, &ret_code) == FAILURE) {

RETURN_FALSE;

}

}执行php_exec方法

这里遇到一件非常有意思的事情,gdb在调试的时候,我想进VCWD_POPEN预定义的方法看一下,被IDE的代码跳转给带偏了, popen方法在unix下面是系统方法,在windows下面是要应用程序自己实现的,结果IDE一直带我进了window下的方法实现中,导致我深陷其中 ^_^

```c#define VCWD_POPEN(command, type) popen(command, type)

#ifdef PHP_WIN32

fp = VCWD_POPEN(cmd, “rb”);

#else

fp = VCWD_POPEN(cmd, “r”);

#endif

1

2

3

4

5

6

7

8对于函数是否能进入,执行一下`nm`,一般就知道了

```bash

[email protected]:~/Debug/php-7.0.29/bin$nm ./php | grep "popen"

0000000100a7ca70 s _arginfo_popen

U _popen

000000010055e6a0 T _virtual_popen

00000001003c71d0 t _zif_popenunix的popen函数执行 popen函数执行中会创建一个双向管道,然后fork一个进程,执行shell命令,之后通过pclose关闭

```bash

POPEN(3) BSD Library Functions Manual POPEN(3)

NAME

pclose, popen – process I/O

LIBRARY

Standard C Library (libc, -lc)

SYNOPSIS

#include

1

2

3

4

5- **从`pipe`中读取流信息**

```bash

stream = php_stream_fopen_from_pipe(fp, "rb");

三. 结论

相比与我们之前通过动态链接库的方式实现跨语言的调用,php的exec在实现的时候,需要创建进程和创建管道,性能的开销会大很多,当然,使用exec的优势也很明显,开发效率会高很多,一行代码解决了跨语言问题…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值