• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

PHP7.4中FFI的介绍(代码示例)

php 搞代码 3年前 (2022-01-21) 19次浏览 已收录 0个评论
文章目录[隐藏]

本篇文章给大家带来的内容是关于PHP7.4中FFI的介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

FFI扩展已经通过RFC,正式成为PHP 7.4核心扩展。

什么是FFI

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。

FFI的使用非常简单,只用声明和调用两步就可以,对于有C语言经验,但是不了解Zend引擎的程序员来说,这简直是打开了新世界的大门,可以快速地使用C类库进行原型试验。

(此处有图:溜了溜了,要懂C的……)

下面通过3个例子,看一下FFI是怎样使用的。

Libbloom

libbloom是一个C实现的bloom filter,比较知名的用户有Shadowsocks-libev,下面看一下怎样通过FFI在PHP里调用libbloom。

第一步,从头文件bloom.h把主要的数据结构和函数声明复制出来:

 $ffi = FFI::cdef("    struct bloom    {        int entries;        double error;        int bits;        int bytes;        int hashes;        double bpe;        unsigned char * bf;        int ready;    };    int bloom_init(struct bloom * bloom, int entries, double error);    int bloom_check(struct bloom * bloom, const void * buffer, int len);    int bloom_add(struct bloom * bloom, const void * buffer, int len);    void bloom_free(struct bloom * bloom);    ", "libbloom.so.1.5");

FFI目前不支持预处理器(除了FFI_LIBFFI_SCOPE),所以宏定义要自己展开。

之后就可以通过$ffi创建已声明的数据结构和调用函数:

// 创建一个bloom结构体,然后用FFI::addr取地址// libbloom的函数都是使用bloom结构体的指针$bloom = FFI::addr($ffi->new("struct bloom"));// 调用libbloom的初始化函数$ffi->bloom_init($bloom, 10000, 0.01);// 添加数据$ffi->bloom_add($bloom, "PHP", 3);$ffi->bloom_add($bloom, "C", 1);// PHP可能存在var_dump($ffi->bloom_check($bloom, "PHP", 3));     // 1// Laravel不存在var_dump($ffi->bloom_check($bloom, "Laravel", 7)); // 0// 释放$ffi->bloom_free($bloom);$bloom = null;

Linux Namespace

Linux命名空间是容器技术的基石之一,通过FFI可以直接调用glibc的对应系统调用封装,从而通过PHP实现容器。下面是一个让bash在一个新的命名空间里运行的例子。

首先是一些常量,可以从Linux的头文件得到:

// cloneconst CLONE_NEWNS     = 0x00020000; // mount namespaceconst CLONE_NEWCGROUP =    0x02000000; // cgroup namespaceconst CLONE_NEWUTS    = 0x04000000; // utsname namespaceconst CLONE_NEWIPC    = 0x08000000; // ipc namespaceconst CLONE_NEWUSER   = 0x10000000; // user namespaceconst CLONE_NEWPID    = 0x20000000; // pid namespaceconst CLONE_NEWNET    = 0x40000000; // network namespace// mountconst MS_NOSUID  = 2;const MS_NODEV   = 4;const MS_NOEXEC  = 8;const MS_PRIVATE = 1 << 18;const MS_REC     = 16384;

接着时我们要用到的函数声明:

$cdef="    // fork进程    int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);    // 挂载文件系统    int mount(const char *source, const char *target, const char *filesystemtype,        unsigned long mountflags, const void *data);    // 设置gid    int setgid(int gid);    // 设置uid    int setuid(int uid);    // 设置hostname    int sethostname(char *name, unsigned int len);";$libc = FFI::cdef($cdef, &q<div style="color:transparent">本文来源gaodai.ma#com搞##代!^码@网*</div><pre>搞gaodaima代码

uot;libc.so.6");

定义我们的子进程:

// 生成一个容器ID$containerId = sha1(random_bytes(8));// 定义子进程$childfn = function() use ($libc, $containerId) {    usleep(1000); // wait for uid/gid map    $libc->mount("proc", "/proc", "proc", MS_NOSUID | MS_NODEV | MS_NOEXEC, null);    $libc->setuid(0);    $libc->setgid(0);    $libc->sethostname($containerId, strlen($containerId));    pcntl_exec("/bin/sh");};

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:PHP7.4中FFI的介绍(代码示例)

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址