LinuxFreeBSD下用C语言开发PHP的so扩展模块例解

xiaoxiao2026-10-04  14

我从 97 年接触互联网的 web 开发,至今已经过去 9 年了,从最初的 frontpage 做 html 页面到学会 ASP+access+IIS 开始,就跟 web 开发干上了,后来又依次使用了 ASP+SQLServer+IIS 、 JSP+Oracle+Jrun(Resin/Tomcat) 、 PHP+Syabse(MySQL)+Apache … 最后我定格到了 PHP+MySQL+Apache+Linux(BSD) 的架构上,也就是大家常说的 LAMP 架构,这说来有很多理由,网上也有很多人讨论各种架构和开发语言之间的优劣,我就不多说了,简单说一下我喜欢 LAMP 的几个主要原因: 1 、全开放的免费平台; 2 、简单易上手、各种资源丰富; 3 、 PHP 、 MySQL 、 Apache 与 Linux(BSD) 系统底层以及彼此间无缝结合,非常高效; 4 、均使用最高效的语言 C/C++ 开发,性能可靠; 5 、 PHP 语言和 C 的风格基本一致,还吸取了 Java 和 C++ 的诸多架构优点; 6 、这是最关键的一点,那就是 PHP 可以非常方便的使用 C/C++ 开发扩展模块,给了 PHP 无限的扩张性!

基于以上原因,我非常喜欢基于 PHP 语言的架构,其中最关键的一点就是最后一点,以前在 Yahoo 和 mop 均推广使用这个平台,在 C 扩展 php 方面也有一些经验,在此和大家分享一下,希望可以抛砖引玉。 用 C 语言编写 PHP 的扩展模块的方法有几种,根据最后的表现形式有两种,一种是直接编译进 php ,一种是编译为 php 的 so 扩展模块来被 php 调用,另外根据编译的方式有两种,一种使用 phpize 工具( php 编译后有的),一种使用 ext_skel 工具( php 自带的),我们使用最多,也是最方便的方式就是使用 ext_skel 工具来编写 php 的 so 扩展模块,这里也主要介绍这种方式。 我们在 php 的源码目录里面可以看到有个 ext 目录(我这里说的 php 都是基于 Linux 平台的 php 来说的,不包括 windows 下的),在 ext 目录下有个工具 ext_skel ,这个工具可以让我们简单的开发出 php 的扩展模块,它提供了一个通用的 php 扩展模块开发步骤和模板。下面我们以开发一个在 php 里面进行 utf8/gbk/gb2312 三种编码转换的扩展模块为例子进行说明。在这个模块中,我们要最终提供以下几个函数接口:

(1) string toplee_big52gbk(string s) 将输入字符串从 BIG5 码转换成 GBK (2) string toplee_gbk2big5(string s) 将输入字符串从 GBK 转换成 BIG5 码 (3) string toplee_normalize_name(string s) 将输入字符串作以下处理:全角转半角, strim ,大写转小写 (4) string toplee_fan2jian(int code, string s) 将输入的 GBK 繁体字符串转换成简体 (5) string toplee_decode_utf(string s) 将 utf 编码的字符串转换成 UNICODE (6) string toplee_decode_utf_gb(string s) 将 utf 编码的字符串转换成 GB (7) string toplee_decode_utf_big5(string s) 将 utf 编码的字符串转换成 BIG5 (8) string toplee_encode_utf_gb(string s) 将输入的 GBKf 编码的字符串转换成 utf 编码

首先,我们进入 ext 目录下,运行下面命令: #./ext_skel –extname=toplee 这时, php 会自动在 ext 目录下为我们生成一个目录 toplee ,里面包含下面几个文件 .cvsignore CREDITS EXPERIMENTAL config.m4 php_toplee.h tests toplee.c toplee.php

 

其中最有用的就是 config.m4 和 toplee.c 文件 接下来我们修改 config.m4 文件 #vi ./config.m4 找到里面有类似这样几行

1.       dnl PHP_ARG_WITH(toplee, for toplee support, 2.       dnl Make sure that the comment is aligned: 3.       dnl [ --with-toplee Include toplee support]) 4.         5.       dnl Otherwise use enable: 6.         7.       dnl PHP_ARG_ENABLE(toplee, whether to enable toplee support, 8.       dnl Make sure that the comment is aligned: 9.       dnl [ --enable-toplee Enable toplee support]) 上面的几行意思是说告诉 php 编译的使用使用那种方式加载我们的扩展模块 toplee ,我们使用 –with-toplee 的方式,于是我们修改为下面的样子 1.       PHP_ARG_WITH(toplee, for toplee support, 2.       Make sure that the comment is aligned: 3.       [ --with-toplee Include toplee support]) 4.         5.       dnl Otherwise use enable: 6.         7.       dnl PHP_ARG_ENABLE(toplee, whether to enable toplee support, 8.       dnl Make sure that the comment is aligned: 9.       dnl [ --enable-toplee Enable toplee support]) 然后我们要做的关键事情就是编写 toplee.c ,这个是我们编写模块的主要文件,如果您什么都不修改,其实也完成了一个 php 扩展模块的编写,里面有类似下面的几行代码 1.       PHP_FUNCTION ( confirm_toplee_compiled ) 2.       { 3.               char * arg = NULL ; 4.               int arg_len , len ; 5.               char string [ 256 ] ; 6.         7.               if ( zend_parse_parameters ( ZEND_NUM_ARGS () TSRMLS_CC , " s " , & arg , & arg_len ) == FAILURE ) { 8.                       return ; 9.               } 10.     11.           len = sprintf ( string , " Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP. " , " toplee " , arg ) ; 12.           RETURN_STRINGL ( string , len , 1 ) ; 13.   } 如果我们在后面完成 php 的编译时把新的模块编译进去,那么我们就可以在 php 脚本中调用函数 toplee() ,它会输出一段字符串 “Congratulations! You have successfully modified ext/toplee/config.m4. Module toplee is now compiled into PHP.” 下面是我们对 toplee.c 的修改,让其支持我们预先规划的功能和接口,下面是 toplee.c 的源代码 1.       /* 2.         +----------------------------------------------------------------------+ 3.         | PHP Version 4                                                        | 4.         +----------------------------------------------------------------------+ 5.         | Copyright (c) 1997-2002 The PHP Group                                | 6.         +----------------------------------------------------------------------+ 7.         | This source file is subject to version 2.02 of the PHP license,      | 8.         | that is bundled with this package in the file LICENSE, and is        | 9.         | available at through the world-wide-web at                           | 10.     | http://www.php.net/license/2_02.txt.                                 | 11.     | If you did not receive a copy of the PHP license and are unable to   | 12.     | obtain it through the world-wide-web, please send a note to          | 13.     | license@php.net so we can mail you a copy immediately.               | 14.     +----------------------------------------------------------------------+ 15.     | Author:                                                              | 16.     +----------------------------------------------------------------------+ 17.     18.     $Id: header,v 1.10 2002/02/28 08:25:27 sebastian Exp $   19.   */ 20.     21.   #ifdef HAVE_CONFIG_H 22.   #include " config.h " 23.   #endif 24.     25.   #include " php.h " 26.   #include " php_ini.h " 27.   #include " ext/standard/info.h " 28.   #include " php_gbk.h " 29.   #include " toplee_util.h " 30.     31.   /* If you declare any globals in php_gbk.h uncomment this: 32.   ZEND_DECLARE_MODULE_GLOBALS(gbk) 33.   */ 34.     35.   /* True global resources - no need for thread safety here */ 36.   static int le_gbk ; 37.     38.   /* {{{ gbk_functions[] 39.   * 40.   * Every user visible function must have an entry in gbk_functions[]. 41.   */ 42.   function_entry gbk_functions [] = { 43.       PHP_FE ( toplee_decode_utf ,    NULL ) 44.       PHP_FE ( toplee_decode_utf_gb ,    NULL ) 45.       PHP_FE ( toplee_decode_utf_big5 ,    NULL ) 46.       PHP_FE ( toplee_encode_utf_gb ,    NULL ) 47.     48.       PHP_FE ( toplee_big52gbk ,    NULL ) 49.       PHP_FE ( toplee_gbk2big5 ,    NULL ) 50.       PHP_FE ( toplee_fan2jian ,    NULL ) 51.       PHP_FE ( toplee_normalize_name ,    NULL ) 52.       { NULL , NULL , NULL }     /* Must be the last line in gbk_functions[] */ 53.   } ; 54.   /* }}} */ 55.     56.   /* {{{ gbk_module_entry 57.   */ 58.   zend_module_entry gbk_module_entry = { 59.   #if ZEND_MODULE_API_NO >= 20010901 60.       STANDARD_MODULE_HEADER , 61.   #endif 62.       " gbk " , 63.       gbk_functions , 64.       PHP_MINIT ( gbk ) , 65.       PHP_MSHUTDOWN ( gbk ) , 66.       PHP_RINIT ( gbk ) ,        /* Replace with NULL if there's nothing to do at request start */ 67.       PHP_RSHUTDOWN ( gbk ) ,    /* Replace with NULL if there's nothing to do at request end */ 68.       PHP_MINFO ( gbk ) , 69.   #if ZEND_MODULE_API_NO >= 20010901 70.       " 0.1 " , /* Replace with version number for your extension */ 71.   #endif 72.       STANDARD_MODULE_PROPERTIES 73.   } ; 74.   /* }}} */ 75.     76.   #ifdef COMPILE_DL_GBK 77.   ZEND_GET_MODULE ( gbk ) 78.   #endif 79.     80.   /* {{{ PHP_INI 81.   */ 82.   /* Remove comments and fill if you need to have entries in php.ini*/ 83.   PHP_INI_BEGIN () 84.       PHP_INI_ENTRY ( " gbk2uni " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 85.       PHP_INI_ENTRY ( " uni2gbk " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 86.       PHP_INI_ENTRY ( " uni2big5 " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 87.       PHP_INI_ENTRY ( " big52uni " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 88.       PHP_INI_ENTRY ( " big52gbk " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 89.       PHP_INI_ENTRY ( " gbk2big5 " ,            "" ,        PHP_INI_SYSTEM ,    NULL ) 90.   //    STD_PHP_INI_ENTRY("gbk.global_value",      "42", PHP_INI_ALL, OnUpdateInt, global_value, zend_gbk_globals, gbk_globals)

91.   //    STD_PHP_INI_ENTRY("gbk.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_gbk_globals, gbk_globals)

92.   PHP_INI_END () 93.     94.   /* }}} */ 95.     96.   /* {{{ php_gbk_init_globals 97.   */ 98.   /* Uncomment this function if you have INI entries 99.   static void php_gbk_init_globals(zend_gbk_globals *gbk_globals) 100.    { 101.        gbk_globals->global_value = 0; 102.        gbk_globals->global_string = NULL; 103.    } 104.    */ 105.    /* }}} */ 106.      107.    char gbk2uni_file [ 256 ] ; 108.    char uni2gbk_file [ 256 ] ; 109.    char big52uni_file [ 256 ] ; 110.    char uni2big5_file [ 256 ] ; 111.    char gbk2big5_file [ 256 ] ; 112.    char big52gbk_file [ 256 ] ; 113.      114.    //utf file init flag 115.    static int initutf = 0 ; 116.      117.    /* {{{ PHP_MINIT_FUNCTION 118.    */ 119.    PHP_MINIT_FUNCTION ( gbk ) 120.    { 121.        /* If you have INI entries, uncomment these lines 122.        ZEND_INIT_MODULE_GLOBALS(gbk, php_gbk_init_globals, NULL);*/ 123.        REGISTER_INI_ENTRIES () ; 124.        memset ( gbk2uni_file , 0 , sizeof ( gbk2uni_file )) ; 125.        memset ( uni2gbk_file , 0 , sizeof ( uni2gbk_file )) ; 126.        memset ( big52uni_file , 0 , sizeof ( big52uni_file )) ; 127.        memset ( uni2big5_file , 0 , sizeof ( uni2big5_file )) ; 128.        memset ( gbk2big5_file , 0 , sizeof ( gbk2big5_file )) ; 129.        memset ( big52gbk_file , 0 , sizeof ( big52gbk_file )) ; 130.        131.        strncpy ( gbk2uni_file , INI_STR ( " gbk2uni " ) , sizeof ( gbk2uni_file ) - 1 ) ; 132.        strncpy ( uni2gbk_file , INI_STR ( " uni2gbk " ) , sizeof ( uni2gbk_file ) - 1 ) ; 133.        strncpy ( big52uni_file , INI_STR ( " big52uni " ) , sizeof ( big52uni_file ) - 1 ) ; 134.        strncpy ( uni2big5_file , INI_STR ( " uni2big5 " ) , sizeof ( uni2big5_file ) - 1 ) ; 135.        strncpy ( gbk2big5_file , INI_STR ( " gbk2big5 " ) , sizeof ( uni2big5_file ) - 1 ) ; 136.        strncpy ( big52gbk_file , INI_STR ( " big52gbk " ) , sizeof ( uni2big5_file ) - 1 ) ; 137.      138.        //InitMMResource(); 139.        InitResource () ; 140.        if (( uni2gbk_file [ 0 ] == '\ 0 ' ) || ( uni2big5_file [ 0 ] == '\ 0 ' ) 141.          || ( gbk2big5_file [ 0 ] == '\ 0 ' ) || ( big52gbk_file [ 0 ] == '\ 0 ' ) 142.          || ( gbk2uni_file [ 0 ] == '\ 0 ' ) || ( big52uni_file [ 0 ] == '\ 0 ' )) 143.        {   144.            return FAILURE ; 145.        } 146.      147.        if ( gbk2uni_file [ 0 ] != '\ 0 ' ) 148.        { 149.            if ( LoadOneCodeTable ( CODE_GBK2UNI , gbk2uni_file ) != NULL ) 150.            { 151.                toplee_cleanup_mmap ( NULL ) ; 152.                return FAILURE ; 153.            } 154.        } 155.      156.        if ( uni2gbk_file [ 0 ] != '\ 0 ' ) 157.        { 158.            if ( LoadOneCodeTable ( CODE_UNI2GBK , uni2gbk_file ) != NULL ) 159.            { 160.                toplee_cleanup_mmap ( NULL ) ; 161.                return FAILURE ; 162.            } 163.        } 164.      165.        if ( big52uni_file [ 0 ] != '\ 0 ' ) 166.        { 167.            if ( LoadOneCodeTable ( CODE_BIG52UNI , big52uni_file ) != NULL ) 168.            { 169.                toplee_cleanup_mmap ( NULL ) ; 170.                return FAILURE ; 171.            } 172.        } 173.      174.        if ( uni2big5_file [ 0 ] != '\ 0 ' ) 175.        { 176.            if ( LoadOneCodeTable ( CODE_UNI2BIG5 , uni2big5_file ) != NULL ) 177.            { 178.                toplee_cleanup_mmap ( NULL ) ; 179.                return FAILURE ; 180.            } 181.        } 182.        183.        if ( gbk2big5_file [ 0 ] != '\ 0 ' ) 184.        { 185.            if ( LoadOneCodeTable ( CODE_GBK2BIG5 , gbk2big5_file ) != NULL ) 186.            { 187.                toplee_cleanup_mmap ( NULL ) ; 188.                return FAILURE ; 189.            } 190.        } 191.      192.        if ( big52gbk_file [ 0 ] != '\ 0 ' ) 193.        { 194.            if ( LoadOneCodeTable ( CODE_BIG52GBK , big52gbk_file ) != NULL ) 195.            { 196.                toplee_cleanup_mmap ( NULL ) ; 197.                return FAILURE ; 198.            } 199.        } 200.        201.        initutf = 1 ; 202.        return SUCCESS ; 203.    } 204.    /* }}} */ 205.      206.    /* {{{ PHP_MSHUTDOWN_FUNCTION 207.    */ 208.    PHP_MSHUTDOWN_FUNCTION ( gbk ) 209.    { 210.        /* uncomment this line if you have INI entries*/ 211.        UNREGISTER_INI_ENTRIES () ; 212.        213.        toplee_cleanup_mmap ( NULL ) ; 214.        return SUCCESS ; 215.    } 216.    /* }}} */ 217.      218.    /* Remove if there's nothing to do at request start */ 219.    /* {{{ PHP_RINIT_FUNCTION 220.    */ 221.    PHP_RINIT_FUNCTION ( gbk ) 222.    { 223.        return SUCCESS ; 224.    } 225.    /* }}} */ 226.      227.    /* Remove if there's nothing to do at request end */ 228.    /* {{{ PHP_RSHUTDOWN_FUNCTION 229.    */ 230.    PHP_RSHUTDOWN_FUNCTION ( gbk ) 231.    { 232.        return SUCCESS ; 233.    } 234.    /* }}} */ 235.      236.    /* {{{ PHP_MINFO_FUNCTION 237.    */ 238.    PHP_MINFO_FUNCTION ( gbk ) 239.    { 240.        php_info_print_table_start () ; 241.        php_info_print_table_header ( 2 , " gbk support " , " enabled " ) ; 242.        php_info_print_table_end () ; 243.      244.        /* Remove comments if you have entries in php.ini*/ 245.        DISPLAY_INI_ENTRIES () ; 246.        247.    } 248.    /* }}} */ 249.      250.      251.    /* Remove the following function when you have succesfully modified config.m4 252.       so that your module can be compiled into PHP, it exists only for testing 253.       purposes. */ 254.      255.    /* {{{ proto  toplee_decode_utf(string s) 256.        */ 257.    PHP_FUNCTION ( toplee_decode_utf ) 258.    { 259.        char * s = NULL , * t = NULL ; 260.        int argc = ZEND_NUM_ARGS () ; 261.        int s_len ; 262.      263.        if ( zend_parse_parameters ( argc TSRMLS_CC , " s " , & s , & s_len ) == FAILURE )   264.            return ; 265.      266.        if ( ! initutf ) 267.            RETURN_FALSE 268.        t = strdup ( s ) ; 269.        if ( t == NULL ) 270.            RETURN_FALSE 271.      272.      273.        DecodePureUTF ( t , KEEP_UNICODE ) ; 274.        RETVAL_STRING ( t , 1 ) ; 275.        free ( t ) ; 276.        return ; 277.    } 278.    /* }}} */ 279.      280.    /* {{{ proto  toplee_decode_utf_gb(string s) 281.        */ 282.    PHP_FUNCTION ( toplee_decode_utf_gb ) 283.    { 284.        char * s = NULL , * t = NULL ; 285.        int argc = ZEND_NUM_ARGS () ; 286.        int s_len ; 287.      288.        if ( zend_parse_parameters ( argc TSRMLS_CC , " s " , & s , & s_len ) == FAILURE )   289.            return ; 290.      291.        if ( ! initutf ) 292.            RETURN_FALSE 293.        t = strdup ( s ) ; 294.        if ( t == NULL ) 295.            RETURN_FALSE 296.      297.        DecodePureUTF ( t , DECODE_UNICODE ) ; 298.        RETVAL_STRING ( t , 1 ) ; 299.        free ( t ) ; 300.        return ; 301.      302.    } 303.    /* }}} */ 304.      305.    /* {{{ proto  toplee_decode_utf_big5(string s) 306.        */ 307.    PHP_FUNCTION ( toplee_decode_utf_big5 ) 308.    { 309.        char * s = NULL , * t = NULL ; 310.        int argc = ZEND_NUM_ARGS () ; 311.        int s_len ; 312.      313.        if ( zend_parse_parameters ( argc TSRMLS_CC , " s " , & s , & s_len ) == FAILURE )   314.            return ; 315.      316.        if ( ! initutf ) 317.            RETURN_FALSE 318.        t = strdup ( s ) ; 319.        if ( t == NULL ) 320.            RETURN_FALSE 321.      322.      323.        DecodePureUTF ( t , DECODE_UNICODE | DECODE_BIG5 ) ; 324.        RETVAL_STRING ( t , 1 ) ; 325.        free ( t ) ; 326.        return ; 相关资源:垃圾分类数据集及代码
转载请注明原文地址: https://www.6miu.com/read-5053568.html

最新回复(0)