PHP扩展编写方法

本方案中采用的PHP扩展方式为:

Ø下载PHP对应版本的源码,在其中加入、生成扩展(如smsupport.so);

Ø然后针对安装同一版本的PHP(注意,不需要是源码安装的,可以通过yum install,apt-get install安装的),将smsupport.so放置到extension_dir中;在php.ini最后一行加入extension = smsupport.so;

Ø重启apached服务

Ø此后,在php文件中直接调用smsupport.so提供的方法即可。

注意点

Ø在进行扩展及测试的过程中我们需要设置PHP的SAFE_MODE为OFF,否则可能无法完成扩展或测试。SAFE_MODE默认为OFF。

Ø编译php扩展的环境和运行环境需要一致!

Ø建议先使用PHP执行脚本,此时提供错误信息较为丰富。

PHP扩展开发

1.从http://php.net/releases/ php中下载对应目标的PHP版本;

2.由于php依赖libxml2-dev,为此,首先通过apt-get install libxml2-dev或者yum install libxml2-dev(注libxml2-dev在不同Linux下名称不同,baidu下)

3.解压缩1中下载的php包,进入目录,运行./configure完成配置,此时会生成编写extension所需的一些文件

4.进入到php源码中的ext目录,执行./ext_skel --extname=smsupport,其会自动生成一系列目录及目录内的文件

5.在ext/smsupport目录中

a)在.c文件中找到const zend_function_entry cqwei_functions[] = {,在其后添加自己定义的函数

注意:自动生成的为c文件,由于本扩展中要用到cpp,强行将其改为cpp,在编译时在后端加上-lstdc++,使得编译成功

PHP_FE(testadd,NULL)/*For testing, remove later. */

PHP_FE(dcsSM2Verify,arg_dcsSM2Verify)

PHP_FE(dcsSM4Decrypt,arg_dcsSM4Decrypt)

注意点:

ü将PHP_FE的名称改成自己的函数,可以同时包含多个;

ü如果PHP_FE中包含的函数需要参数,则应加入参数信息,如arg_Verify,其中arg_Verify包含4个参数,arg_Decrypt包含2个参数。

nZEND_BEGIN_ARG_INFO_EX(arg_Verify,

0, 0, 1)

ZEND_ARG_INFO(0,user)

ZEND_ARG_INFO(0,pubKey)

ZEND_ARG_INFO(0,ticket)

ZEND_ARG_INFO(0,sig)

ZEND_END_ARG_INFO()

nZEND_BEGIN_ARG_INFO_EX(arg_Decrypt,0, 0, 1)

ZEND_ARG_INFO(0,key)

ZEND_ARG_INFO(0,cipher)

ZEND_END_ARG_INFO()

b)PHP_FUNCTION(testadd)在定义自定义函数testadd的函数体,如下所示为最简单的内容

PHP_FUNCTION(testadd)

{

zend_printf("testadd00");

}

c)PHP_FUNCTION(Verify),稍微复杂,因为有参数和返回值,示例如下

PHP_FUNCTION(Verify)

{

char * user;

char * pubKey;

char* ticket;

char * sig;

intuserLen,pubKeyLen,ticketLen,sigLen;

charpubKeyArray[64];

if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"ssss",&user,&userLen,&pubKey,&pubKeyLen,&ticket,&ticketLen,&sig,&sigLen)== FAILURE)

{//解析参数,参数为4个char *,s表示char

*,其他格式见下文中的表格

RETURN_FALSE;

return;

}

if(pubKeyLen != 128 || sigLen !=64)

{

zend_printf("the sm2 parameter isincorrect\n");

RETURN_FALSE;

return;

}

CECCPublicKey *verify = new CECCPublicKey();

loadHexStr(pubKey,(unsigned char *)pubKeyArray,64);

if(verify->SetPublicKey((constunsigned char*)pubKeyArray, 64) == 0)

{

zend_printf("the public key isincorrect\n");

delete verify;

RETURN_FALSE;//表示返回false

return;

}

if(verify->VerifyMessage((constunsigned char *)ticket, ticketLen, (const unsigned char *)sig, sigLen, (constchar *)user, userLen) != 1)

{

zend_printf("the signature is incorrect\n");

delete verify;

RETURN_FALSE;

return;

}

delete verify;

RETURN_TRUE;//表示返回true

return;

}

d)char *plain = emalloc(cipherLen);

efree (plain);//动态分配内存和释放

e)返回string变量RETVAL_STRINGL(plain, cipherLen, 1); plain为char *,cipherLen为长度

f)在.h文件中加入如下内容

PHP_FUNCTION(testadd);

PHP_FE(Verify);

PHP_FE(Decrypt);

g)在php源码/ext/smsupport下编译:cc -fpic -DCOMPILE_DL_SMSUPPORT=1 -I /usr/local/include -I../ -I../../main -I ../.. -I ../../TSRM -I ../../Zend -c smsupport.cppEllipticCurve.cpp sm3hash.cpp Mpi.cpp SMS4.cpp -lstdc++ -fpermissive-Wwrite-strings

其中除smsupport.cpp外为正常的cpp文件

h)在php源码/ext/smsupport下链接:cc -shared -L /usr/local/lib -rdynamic -o smsupport.so *.o -lstdc++

部署示例

1.在CentOS上搭建php+apache

a)Yum install php

b)Yum install httpd

c)Service httpd start

2.配置php

a)将上述生成的so文件(如smsupport.so)放置到extension_dir目录中,extension_dir路径可通过echo phpinfo()获取

b)Find / -name “php.ini”,加入extension

cqwei.so;(在较为靠后的位置加入)

c)Service httpd start

d)在php中直接调用方法即可

细节介绍

Øzend_parse_parameters

n如if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"ssss",&user,&userLen,&pubKey,&pubKeyLen,&ticket,&ticketLen,&sig,&sigLen)== FAILURE)

nZEND_NUM_ARGS()告诉Zend引擎要取得的参数的信息

nTSRMLS_CC用来确保线程安全

n返回值将被检查是SUCCESS还是FAILURE。

u通常情况下,zend_parse_parameters()将返回SUCCESS;

u然而,如果调用脚本试图传入太多或太少的参数,或者传入的参数不能被转为适当的类型,Zend会自动输出一条错误信息并优雅地将控制权还给调用脚本

n本例指定s表明此函数期望只传入一个参数,而且该参数应该被转为string数据类型并装入通过地址传入的char*变量。

n注意,还有一个int变量通过地址被传入zend_parse_parameters()。这使Zend引擎提供字符串的字节长度,如此二进制安全的函数不再需要依赖strlen(name)确定字符串的长度。实际上使用strlen(name)甚至得不到正确的结果,因为name可能在字符串结束之前包含一个或多个NULL字符。

n再比如if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ld|b", &a,&b, &return_long) == FAILURE) {

u这次你的数据类型字符串读起来像:“我要一个long(l),一个double(d)”。

u下一个管道字符表示其余的参数是可选的。如果函数调用时没有传入可选参数,那么zend_parse_parameters()将不会改变传给它的对应变量。

lb是用于Boolean。

u数据类型字符串后面的是a、b和return_long,它们按地址传递,这样zend_parse_parameters()可以将值装入它们。

u警告:在32位平台中经常不加区分地使用int和long,但是,当你的代码在64位硬件上编译时,在本该使用一个的地方使用另一个是很危险的。所以记住要把long用于整型,把int用于字符串的长度。

Ø表1显示不同的类型和对应的字母代码,以及可用于zend_parse_parameters()的C类型:

类型代码变量类型

Booleanbzend_bool

Longllong

Doubleddouble

Stringschar*, int

Resourcerzval*

Arrayazval*

Objectozval*

zvalzzval*

n你可能立刻注意到表1中的最后四个类型都是zval*。待会儿你将看到,PHP中实际使用zval数据类型存储所有的用户空间变量。三种“复杂”数据类型,资源、数组和对象,当它们的数据类型代码被用于zend_parse_parameters()时,Zend引擎会进行类型检查,但是因为在C中没有与它们对应的数据类型,所以不会执行类型转换。

Ø返回值

n返回值的设置方法,网上大多数是错误的,可以借鉴ext目录下其他的扩展。

mcrypt安装

Ø首先安装mcrypt:http://blog.csdn.net/zy112289/article/details/52840062

l先安装Libmcrypt

#tar -zxvf libmcrypt-2.5.8.tar.gz

#cd libmcrypt-2.5.8

#./configure

#make

#make install说明:libmcript默认安装在/usr/local

l安装mhash

#tar -zxvf mhash-0.9.9.9.tar.gz

#cd mhash-0.9.9.9

#./configure

#make

#make install

l安装mcrypt

#tar -zxvf mcrypt-2.6.8.tar.gz

#cd mcrypt-2.6.8

#LD_LIBRARY_PATH=/usr/local/lib ./configure//注意,在一行输入

#make

#make install

Ø安装phpize: yum install php-devel

Ø编译、安装mcrypt

ncd php-5.3.3/ext/mcrypt/

nphpize

n./configure --with-php-config=/usr/bin/php-config

nmake && make install

n提示:Installing shared extensions:/usr/lib64/php/modules/,说明安装成功

n在php.ini中加入extension = mcrypt.so以加入扩展。

�$

你可能感兴趣的:(PHP扩展编写方法)