php添加拓展

[root@iZ25jw3825lZ ext]# 
[root@iZ25jw3825lZ ext]# ./ext_skel --extname=sjext
Creating directory sjext
Creating basic files: config.m4 config.w32 .cvsignore sjext.c php_sjext.h CREDITS EXPERIMENTAL tests/001.phpt sjext.php [done].


To use your new extension, you will have to execute the following steps:


1.  $ cd ..
2.  $ vi ext/sjext/config.m4
3.  $ ./buildconf
4.  $ ./configure --[with|enable]-sjext
5.  $ make
6.  $ ./php -f ext/sjext/sjext.php
7.  $ vi ext/sjext/sjext.c
8.  $ make


Repeat steps 3-6 until you are satisfied with ext/sjext/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing

code and repeat the last two steps as often as necessary.




/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2010 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | [email protected] so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/


/* $Id: header 297205 2010-03-30 21:09:07Z johannes $ */


#ifndef PHP_SJEXT_H
#define PHP_SJEXT_H


extern zend_module_entry sjext_module_entry;
#define phpext_sjext_ptr &sjext_module_entry


#ifdef PHP_WIN32
#       define PHP_SJEXT_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#       define PHP_SJEXT_API __attribute__ ((visibility("default")))
#else
#       define PHP_SJEXT_API
#endif


#ifdef ZTS
#include "TSRM.h"
#endif


PHP_MINIT_FUNCTION(sjext);
PHP_MSHUTDOWN_FUNCTION(sjext);
PHP_RINIT_FUNCTION(sjext);
PHP_RSHUTDOWN_FUNCTION(sjext);
PHP_MINFO_FUNCTION(sjext);


PHP_FUNCTION(confirm_sjext_compiled);   /* For testing, remove later. */


/*
        Declare any global variables you may need between the BEGIN
        and END macros here:


ZEND_BEGIN_MODULE_GLOBALS(sjext)
        long  global_value;
        char *global_string;
ZEND_END_MODULE_GLOBALS(sjext)



vi config,m4


dnl PHP_ARG_WITH(myext, for myext support,
dnl Make sure that the comment is aligned:
dnl [ --with-myext Include myext support])
//去掉dnl


修改头文件php_myext.h:
//PHP_FUNCTION(confirm_myext_compiled); /* For testing, remove later. */
//修改为
PHP_FUNCTION(myext); /* For testing, remove later. */
修改myext.c:
//将
//zend_function_entry myext_functions[] = {
// PHP_FE(confirm_myext_compiled, NULL) /* For testing, remove later. */
// {NULL, NULL, NULL} /* Must be the last line in myext_functions[] */
//};
//修改为
zend_function_entry myext_functions[] = {
PHP_FE(myext, NULL) /* For testing, remove later. */
{NULL, NULL, NULL} /* Must be the last line in myext_functions[] */
};
//在文件底部添加自己的函数
PHP_FUNCTION(myext)
{
zend_printf("Hello World!\n");
}
安装自己的php扩展myext:
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install


php.ini中添加

extension=sjext.so




一直以来对于PHP的扩展编写都比较感兴趣但是却没有什么更深的接触,正好最近要研究一下,做个记录吧。

参考: http://www.laruence.com/2009/04/28/719.html http://www.walu.cc/phpbook/5.md

首先我们从头安装一个PHP环境,现在最新的稳定版的PHP是5.6.12。

以下在Linux(centos)下完成

  1. 下载src: wget http://cn2.php.net/get/php-5.6.12.tar.bz2/from/this/mirror wget 下载的文件可能被命名为mirror,需要重命名一下 mv mirror php-5.6.12.tar.bz2
  2. 解压: tar xjvf php-5.6.12.tar.bz2
  3. cd php-5.6.12 编译安装: ./configure --prefix=/home/wuxu/data/php5.6/ --enable-debug --enable-maintainer-zts
  4. make
  5. make install
  6. make clean

这样一个新的php安装在了家目录下(/home/wuxu/data/php5.6)。

首先要理解为PHP内核编写的扩展的两个工作方式,一种是编译为动态共享对象/可装载模块,也就是常见的.so扩展,这种扩展可以在php的配置文件中方便的开启或者关闭;另外一种方式是静态编译到PHP中,使用静态方法编译比较容易上手,鸟哥的文章中也是使用的静态编译方式,所以我们也使用静态编译方式来练习。

PHP在源码中提供了一个扩展骨架构造脚本: ext_skel,脚本放在php-5.6.12/ext目录下。它的使用方式如下:

  
  
  
  
  1. ./ext_skel --extname=mfs --proto=mfs.def

解释一下,--extname明显就是我们要创建的扩展的名称,--proto的proto是prototype的缩写,也就是扩展对外提供的函数原型,可以在这个文件中添加要导出的函数签名,每个函数做一行,这样ext_skel脚本可以自动创建它们的骨架代码。比如鸟哥的例子中的字符串复制函数:

  
  
  
  
  1. string self_concat(string str, int n)

把这一行保存为mfs.def文件,放在ext文件夹下。

运行上面的ext_skel命令,就会在ext文件夹下创建一个mfs的文件夹,并声称一些代码文件和配置文件。 php扩展在linux下的配置文件是 ext/mfs/config.m4;m4有自己的语法,不过我们并不需要熟悉它,只需要简单去掉一些注释就可以了。打开配置文件config.m4;大概在16行和18行,找到PHP_ARG_ENABLE(mfs, whether to enable mfs support 相关的内容,这一行是用来重新生成configure文件时起作用的,取消这一行及 它后面的第二行[ --enable-myfunctions Include myfunctions support]),中间有一行不要取消注释。这样就可以重新生成configure文件可以使用enable-mfs来静态编译扩展。

完成上面的工作后,重新生成configure文件并编译安装php。

  
  
  
  
  1. cd /path/to/php-5.6.12
  2. ./buildconf --force
  3. ./configure --enable-fms --prefix=/home/wuxu/data/php5.6 --with-config-file-path=/home/wuxu/data/etc/php.ini
  4. make
  5. make install

这样编译的php就带有了fms扩展,并可以使用在def文件中定义的原型函数。但是由于并没有编写那个函数的具体内容,所以这个是str_concat函数并不能起作用,不过ext_skel脚本还导出了一个函数: confirm_mfs_compiled(str); 可以用下面的脚本检测fms扩展是否可用了:

  
  
  
  
  1. <?php
  2. print confirm_mfs_compiled("myextension");
  3. ?>
  4. // output:
  5. // "Congratulations! You have successfully modified ext/mfs
  6. //
  7. // config.m4. Module mfs is now compiled into PHP."

表明脚本已经编译到php了。下面我们就可以开始编写self_concat的具体内容了。

先看一下有ext_skel脚本自动生成的self_concat函数代码,在ext/mfs/mfs.c:76

  
  
  
  
  1. PHP_FUNCTION(self_concat)
  2. {
  3. char *str = NULL;
  4. int argc = ZEND_NUM_ARGS();
  5. int str_len;
  6. long n;
  7. if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)
  8. return;
  9. php_error(E_WARNING, "self_concat: not yet implemented");
  10. }

这些代码是一个到处函数的基本框架了。 使用PHPFUNCTION()宏来生成一个适合于Zend引擎的函数原型。其中比较重要的是 zend_parse_parameters 函数,用来获取函数传递的参数;该函数的原型是:

  
  
  
  
  1. zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);

第一个参数是参数的个数,通常使用ZEND_NUM_ARGS()的返回值,TSRMLS_DC这个照写就可以了,第三个参数比较复杂是一个表示函数期望的参数类型的字符串,后面紧跟参数值的变量列表,这里有一个PHP的松散变量和动态类型推断到C语言类型的转换。

第三个参数根据一个参数类型对照表生成:

类型指定符 对应的C类型 描述
l long 符号整数
d double 浮点数
s char *, int 二进制字符串,长度
b zend_bool 逻辑型(1或0)
r zval * 资源(文件指针,数据库连接等)
a zval * 联合数组
o zval * 任何类型的对象
O zval * 指定类型的对象。需要提供目标对象的类类型
z zval * 无任何操作的zval

考虑上面代码的实例:

  
  
  
  
  1. if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)
  2. return;

"sl": 第一个字符s代表二进制字符串,它在后面的参数列表中对应两个值,一个 &str, 一个&strlen;第二个字符'l'(L的小写),表示整数类型参数对应 &n。

扩展中的字符串都是二进制字符串,即并不以\0作为字符串结束,而是使用一个str_len表示字符串长度,具体看_zval结构体。

下面的工作就是修改这个函数了。

将自动生成的函数更新为:

  
  
  
  
  1. PHP_FUNCTION(self_concat)
  2. {
  3. char *str = NULL;
  4. int argc = ZEND_NUM_ARGS();
  5. int str_len;
  6. long n;
  7. char *result; /* Points to resulting string */
  8. char *ptr; /* Points at the next location we want to copy to */
  9. int result_length; /* Length of resulting string */
  10. if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE) {
  11. return;
  12. }
  13. result_length = (str_len * n);
  14. result = (char *) emalloc(result_length + 1);
  15. ptr = result;
  16. while (n--) {
  17. memcpy(ptr, str, str_len);
  18. ptr += str_len;
  19. }
  20. *ptr = '\0';
  21. RETURN_STRINGL(result, result_length, 0);
  22. }

按照上面的方法,重新编译php, 就可以在php文件中直接使用slef_concat()函数拼接字符串了。

  
  
  
  
  1. <?php
  2. print self_concat("pop_", 10);

保存为confirm.php;运行:

  
  
  
  
  1. php confirm.php

会输出拼接的字符串了。


你可能感兴趣的:(php添加拓展)