1、目的
为了在php中使用C语言的扩展,本文介绍在windows系统下,将C扩展打包成dll文件,提供给php调用的方法
Linux系统下的方法见:http://c.biancheng.net/cpp/html/1400.html
2、需要安装的软件
(1)wamp server:其中包含php,本文中php版本为5.5.12
安装路径如:C:\wamp\,其中C:\wamp\bin\php\php5.5.12为php所在路径,将其加入环境变量Path
(2)Visual Studio:本文中版本为VS2013
安装路径如:C:\Program Files (x86)\Microsoft Visual Studio 12.0\
将C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin; 和 C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE; 加入环境变量Path
否则之后会报找不到C编译器的错误:MS C++ compiler is required
(3)Cygwin:本文中版本为2.738,为了在windows下模拟unix环境,下载及安装流程见:http://www.cr173.com/soft/60977.html
3、下载未编译的php源码包
官方下载地址:http://www.php.net/downloads.php,选择适当的版本和下载点下载,本文用的版本是5.5.26
下载后解压源码包,找到./ext目录,这个是负责开发扩展的目录,有两个主要用到的文件,ext_skel,ext_skel_win32.php,
ext_skel是创建扩展的shell,在windows上无法运行,所以要有Cygwin
下载后,将安装目录下的所有源码文件拷贝到C:\wamp\bin\php\php5.5.12\下
4、修改Cygwin路径
如果你的Cygwin没有安在c:\cygwin,进入./ext目录下,修改ext_skel_win32.php
将$cygwin_path = 'c:\cygwin\bin';
修改为你的cygwin安装目录
5、写C语言函数声明文件
在ext目录下新建函数声明文件,如:myfunc.def
文件内声明C语言扩展对php提供的函数原型,如:
int a(int x,int y) string b(string x, string y)
写声明文件的目的是在下一步建立骨架目录时,目录内的.c文件内会生成相应函数的部分代码,方便后续编写。
这一步也可以省略,那么需要在第7步添加额外的代码
6、建立php扩展骨架目录
打开Cygwin,cd到ext目录c:/wamp/bin/php/php5.5.12/ext,根据myfunc.def建立骨架目录:
php ./ext_skel_win32.php --extname=myfunc --proto=myfunc.def
若没有生成def文件,不需要最后一个参数
Warning: fopen(myhello/myhello.dsp): failed to open stream: No such file or directory in D:\cygwin\php-5.2.6\ext\ext_skel_win32.php on line 45 Warning: fopen(myhello/myhello.php): failed to open stream: No such file or directory in D:\cygwin\php-5.2.6\ext\ext_skel_win32.php on line 52
若执行报错php不是系统命令,将php所在路径C:\wamp\bin\php\php5.5.12加入环境变量Path并重启
执行成功显示以下信息:
$ php ./ext_skel_win32.php --extname=myfunc --proto=myfunc.def
Creating directory myfunc
awk: /cygdrive/c/wamp/bin/php/php5.5.12/ext/skeleton/create_stubs:56: w
scape sequence `\|' treated as plain `|'
Creating basic files: config.m4 config.w32 .svnignore myfunc.c php_myfu
ITS EXPERIMENTAL tests/001.phpt myfunc.php [done].
To use your new extension, you will have to execute the following steps
1. $ cd ..
2. $ vi ext/myfunc/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-myfunc
5. $ make
6. $ ./sapi/cli/php -f ext/myfunc/myfunc.php
7. $ vi ext/myfunc/myfunc.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/myfunc/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writ
code and repeat the last two steps as often as necessary.
7、添加C语言代码
修改ext/myfunc/myfunc.c文件,修改PHP_FUNCTION(a)和PHP_FUNCTION(b):
PHP_FUNCTION(a) { int argc = ZEND_NUM_ARGS(); long x; long y; if (zend_parse_parameters(argc TSRMLS_CC, "ll", &x, &y) == FAILURE) return; int z = x+y; RETURN_LONG(z); //php_error(E_WARNING, "a: not yet implemented"); } /* }}} */ /* {{{ proto string b(string x, string y) ; */ PHP_FUNCTION(b) { char *x = NULL; char *y = NULL; int argc = ZEND_NUM_ARGS(); int x_len; int y_len; if (zend_parse_parameters(argc TSRMLS_CC, "ss", &x, &x_len, &y, &y_len) == FAILURE) return; int result_length = x_len + y_len; char* result = (char *) emalloc(result_length + 1); strcpy(result, x); strcat(result, y); RETURN_STRINGL(result, result_length, 0); //php_error(E_WARNING, "b: not yet implemented"); }
设置返回值并且结束函数 | 设置返回值 | 宏返回类型和参数 |
RETURN_LONG(l) | RETVAL_LONG(l) | 整数 |
RETURN_BOOL(b) | RETVAL_BOOL(b) | 布尔数(1或0) |
RETURN_NULL() | RETVAL_NULL() | NULL |
RETURN_DOUBLE(d) | RETVAL_DOUBLE(d) | 浮点数 |
RETURN_STRING(s, dup) | RETVAL_STRING(s, dup) | 字符串。如果dup为1,引擎会调用estrdup()重复s,使用拷贝。如果dup为0,就使用s |
RETURN_STRINGL(s, l, dup) | RETVAL_STRINGL(s, l, dup) | 长度为l的字符串值。与上一个宏一样,但因为s的长度被指定,所以速度更快。 |
RETURN_TRUE | RETVAL_TRUE | 返回布尔值true。注意到这个宏没有括号。 |
RETURN_FALSE | RETVAL_FALSE | 返回布尔值false。注意到这个宏没有括号。 |
RETURN_RESOURCE(r) | RETVAL_RESOURCE(r) | 资源句柄。 |
若在第5步没有生成def文件,这里需要自己添加PHP_FUNCTION(a)和PHP_FUNCTION(b)两个函数代码,并修改PHP_FUNCTION里的zend_parse_parameters函数,这个函数用来将从php中传入的参数转换成c语言的参数类型。
zend_parse_parameters()函数大部分的代码看起来几乎都一样。ZEND_NUM_ARGS()向Zend Engine提供关于接收到的参数数量,TSRMLS_CC被用来保证线程安全,最后函数会返回SUCCESS或者FAILURE。在普通情况下zend_parse_parameters()将会返回SUCCESS;如果一个调用脚本传递的参数数量超过了函数定义的参数数量,或者传递的参数不能转换成合适的数据类型,Zend将会自动的输出一个错误信息,然后函数会优雅地把控制权返回给调用脚本。
在这个例子你使用“s”来指明这个函数参数可以被转换成string数据类型,“l”则表示long类型,数据类型指定符和对应类型如下表:
类型指定符 | 对应的C类型 | 描述 |
l | long | 符号整数 |
d | double | 浮点数 |
s | char *, int | 二进制字符串,长度 |
b | zend_bool | 逻辑型(1或0) |
r | zval * | 资源(文件指针,数据库连接等) |
a | zval * | 联合数组 |
o | zval * | 任何类型的对象 |
O | zval * | 指定类型的对象。需要提供目标对象的类类型 |
z | zval * | 无任何操作的zval |
const zend_function_entry myfunc_functions[] = { PHP_FE(confirm_myfunc_compiled, NULL) /* For testing, remove later. */ PHP_FE(a, NULL) PHP_FE(b, NULL) PHP_FE_END /* Must be the last line in myfunc_functions[] */ };
还需要在php_myfunc.h中加入函数声明:
PHP_MINIT_FUNCTION(myfunc); PHP_MSHUTDOWN_FUNCTION(myfunc); PHP_RINIT_FUNCTION(myfunc); PHP_RSHUTDOWN_FUNCTION(myfunc); PHP_MINFO_FUNCTION(myfunc); PHP_FUNCTION(confirm_myfunc_compiled); /* For testing, remove later. */ PHP_FUNCTION(a); PHP_FUNCTION(b);
8、修改config.m4
修改myfunc/config.m4文件,去掉下面两项的dnl注释:
PHP_ARG_WITH(myfunc, for myfunc support, dnl Make sure that the comment is aligned: [ --with-myfunc Include myfunc support]) dnl Otherwise use enable: PHP_ARG_ENABLE(myfunc, whether to enable myfunc support, dnl Make sure that the comment is aligned: [ --enable-myfunc Enable myfunc support])
9、编译并生成dll
(1)用VS2013打开myfunc/myfunc.dsp
(2)在BUILD -> Configuration Manager中,将Active Solution Configuration设置成Release_TS
(3)编译工程,BUILD->Build myfunc
(4)在C:\wamp\bin\php\php5.5.12\Release_TS下生成php_myfunc.dll
10、添加php5ts.lib
myfunc文件夹不能移出ext文件夹,否则编译会报缺少php.h
11、添加config.w32.h
若编译报错缺少该文件,在网上下载该文件,或新建文件拷贝如下代码:
#define SIZEOF_LONG 4 #define PHP_COMPILER_ID "VC11"
将该文件放在C:\wamp\bin\php\php5.5.12\main目录下
12、集成dll到php中
(1)将生成的php_myfunc.dll放到php环境下的ext目录下
(2)修改php.ini,添加extension=php_myfunc.dll,重启apache
(3)在C:\wamp\bin\php\php5.5.12下新建test.php,内容为
<?php echo a(3,5)."\n"; echo b("string1","string2")."\n"; ?>
maverick123@Maverick-PC /cygdrive/c/wamp/bin/php/php5.5.12 $ php test.php 8 string1string2
参考:
http://wenku.baidu.com/link?url=ZtvcBS4oChuRqrn6LaABMZqhaHZOVBUq77UKE79WT50xeptaBxkHfKAnkrAgizVjGlRlzczxZypj749dZcDM61ogWEv0Z67MpCD9FvSWEv7
http://www.laruence.com/2009/04/28/719.html
http://blog.csdn.net/a600423444/article/details/8108993
http://blog.chinaunix.net/uid-25007056-id-3781616.html
http://www.3qphp.com/index/show/index/4.html
http://www.t086.com/article/4866
http://www.kissthink.com/archive/C-Programming-PHP-call-summary-windows.html
http://www.techotaku.net/2013/09/build-php-and-extension-for-windows/