版权属于:
桑帅东的博客
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
什么是FFI?
此扩展允许在纯PHP中加载共享库(.DLL或.so),调用C函数以及访问C数据结构,而无需深入了解Zend扩展API。
这个扩展需要安装 libffi libffi-devel库,编译安装步骤具体步骤就不说了(phpize、configure、make、make install四部曲),另外此扩展要求PHP版本必须是(PHP 7 >= 7.4.0, PHP 8),安装完通过php -m就可以看到下面的模块。
FFI的API都有哪些?
FFI怎么用?
直接上例子,下面就是通过一个实例来说明FFI怎么调用C的动态库函数。
首先通过FFI::cdef创建一个FFI对象,定义我们动态库中的常量、结构体、函数、以及通过地址加载我们的动态库。
define('ECCref_MAX_BITS', 512);
define('ECCref_MAX_LEN', (ECCref_MAX_BITS + 7) / 8);
define("SGD_SM3", 0x00000001);
$this->ffi = FFI::cdef(<<<EOH
// 定义结构体
typedef struct ECCrefPublicKey_st{
unsigned int bits;
unsigned char *x;
unsigned char *y;
} ECCrefPublicKey;
// 定义打开设备函数
int SDF_OpenDevice(void **phDeviceHandle);
// 定义创建会话句柄函数
int SDF_OpenSession(void *hDeviceHandle, void **phSessionHandle);
// 定义生成随机数函数
int SDF_GenerateRandom(void *hSessionHandle, unsigned int uiLength, unsigned char *pucRandom);
// 定义杂凑运算初始化函数
int SDF_HashInit(void *hSessionHandle, unsigned int uiAlgID, ECCrefPublicKey *pucPublicKey, unsigned char *pucID, unsigned int uiIDLength);
EOH
, '/home/sangshuaidong/sdk/libcsapi.so');#加载动态库
然后,我们在方法中进行调用c函数。
public function openDevice()
{
$deviceHandlePtr = FFI::new("void*[1]");
$result = $this->ffi->SDF_OpenDevice($deviceHandlePtr);
if ($result == 0) {
$this->deviceHandle = $deviceHandlePtr[0];
return true;
} else {
return false;
}
}
public function openSession()
{
$sessionHandlePtr = FFI::new("void*[1]");
$result = $this->ffi->SDF_OpenSession($this->deviceHandle, FFI::addr($sessionHandlePtr));
if ($result == 0) {
$this->sessionHandle = $sessionHandlePtr[0];
return true;
} else {
return false;
}
}
// 获取16位随机数
public function generateRandom($length)
{
$randomBuffer = FFI::new("unsigned char[$length]");
$result = $this->ffi->SDF_GenerateRandom($this->sessionHandle, $length, $randomBuffer);
if ($result == 0) {
$randomHex = bin2hex(FFI::string($randomBuffer, $length));
return $randomHex;
} else {
return false;
}
}
// hash杂凑运算初始化
public function hashInit($algID = "SGD_SM3", $length = 0)
{
$result = 0;
if ($algID === 'SGD_SM3') {
$publicKey =$this->ffi->new("ECCrefPublicKey");
$publicKey->bits = 0;
$unsignedCharType = FFI::arrayType(FFI::type('unsigned char'), [ECCref_MAX_LEN]);
$publicKey->x = FFI::cast('unsigned char*', FFI::new($unsignedCharType));
$publicKey->y = FFI::cast('unsigned char*', FFI::new($unsignedCharType));
$result = $this->ffi->SDF_HashInit(
$this->sessionHandle,
SGD_SM3,
FFI::addr($publicKey),
FFI::addr(FFI::new("unsigned char")),
$length
);
} else {
// 其他算法的处理,根据实际情况进行设置
}
if ($result == 0) {
return true;
} else {
return false;
}
}
最后,我们通过执行可执行程序可以看到成功输出!
评论