【php 扩展开发】扩展生成器

什么是扩展生成器

每个php扩展都包含一些非常公共的并且非常单调的结构和文件,这些文件对所有扩展来说都是通用的。当开始一个新扩展开发的时候,如果这些公共的结构已经存在,而不需要费力去复制每个文件的内容, 我们只需考虑填充功能代码那心情一定会愉快很多。

扩展生成器就是实现这些功能的脚本,帮助我们完成初始化工作。 PHP 源码中提供一个自带的生成器 ext_skel。他在 ext 目录下。

ext_skel

它是一个 shell 脚本,仅有 300 多行。我们来看下关键部分代码

# 生成 config.m4 配置文件

cat >config.m4 <<eof
dnl \$Id\$
dnl config.m4 for extension $extname

dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH($extname, for $extname support,
dnl Make sure that the comment is aligned:
dnl [  --with-$extname             Include $extname support])

dnl Otherwise use enable:

PHP_ARG_ENABLE($extname, whether to enable $extname support,
dnl Make sure that the comment is aligned:
[  --enable-$extname           Enable $extname support])

..... 省略一大串
eof

# 生成核心文件

$ECHO_N " $extname.c$ECHO_C"
echo "s/extname/$extname/g" > sedscript
echo "s/EXTNAME/$EXTNAME/g"  >> sedscript
echo '/__function_entries_here__/r function_entries'  >> sedscript
echo '/__function_stubs_here__/r function_stubs'  >> sedscript
echo '/__header_here__/r ../../header'  >> sedscript
echo '/__footer_here__/r ../../footer'  >> sedscript
echo '/__function_entries_here__/D'  >> sedscript
echo '/__function_stubs_here__/D'  >> sedscript
echo '/__header_here__/D'  >> sedscript
echo '/__footer_here__/D'  >> sedscript
if [ ! -z "$no_help" ]; then
    echo "/confirm_$extname_compiled/D" >> sedscript
    echo '/Remove the following/,/^\*\//D' >> sedscript
    echo 's/[[:space:]]\/\*.\+\*\///' >> sedscript
    echo 's/^\/\*.*\*\/$//' >> sedscript
    echo '/^[[:space:]]*\/\*/,/^[[:space:]]*\*\//D' >> sedscript
fi

sed -f sedscript < $skel_dir/skeleton.c > $extname.c

帮助说明

./ext_skel --help

它提示了我们脚本的命令行格式和支持的参数

./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]
           [--skel=dir] [--full-xml] [--no-help]

  --extname=module   扩展名称,全为小写字母的标识符,仅包含字母和下划线,保证在 php 源码 ext 目录下的文件夹名唯一
  --proto=file       允许开发人员指定一个头文件,由此创建一系列 PHP 函数,表面上看就是要开发基于一个函数库的扩展,很少用
  --stubs=file       仅生成文件中的函数存根,生成 IDE 提示文件可能有用
  --xml              generate xml documentation to be added to phpdoc-svn 没用
  --skel=dir         path to the skeleton directory 指定扩展骨架目录,如果你想在 ext 目录以外的地方生成,那这个有用
  --full-xml         generate xml documentation for a self-contained extension (not yet implemented) 没用
  --no-help          don't try to be nice and create comments in the code and helper functions to test if the module compiled 去除生成测试函数和注释等内容,除非你很熟练,不建议操作

示例

/usr/local/src/php-7.2.15/ext/ext_skel --extname=twinkle_log --skel=/usr/local/src/php-7.2.15/ext/skeleton/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果用PHP不能再满足你的需求,最好的办法就是开发PHP扩展。这有一些好处: 1、增加自己的特殊功能。 2、保护自己的专利代码。 这是几年前的一篇英文文章,现在已被翻译成中文版的。 作者应该是hshq_cn。 链接是:http://bbs3.chinaunix.net/thread-1028798-1-1.html。 现我将此转变为PDF文件,仅有兴趣者参阅。同时非常感谢 原作者及hshq_cn,给我们带来的这么好的资料。里面还有一个幻灯片的,也是很有帮助的文档。另外,再提供一篇相关的文章(http://www.programbbs.com/doc/4083.htm): 编写php的extension实例的方法 所属类别:JSP 推荐指数:★★☆ 文档人气:161 本周人气:1 发布日期:2008-7-3 一、说明 前端时间因为客户的原因折腾了一下asp的扩展,在ATL的帮助下写一个asp的模块还是很容易的。不巧的时刚刚折腾完asp的COM就碰到另一个客户的问题。客户想给系统集成ICBC的接口,但是用ICBC的接口需要用他们的提供的库函数去 1. sign对发送的数据进行签名 2. getcertid获取用户证书的版本 3. verifySign对签名后的数据进行验证 问题是ICBC只给了现成的COM组件,意味在只能在Win的主机上使用。俺们公司只有linux的主机,在*nix上就要自己想办法调用ICBC给的静态库了。对此我们有两个想法 1.用ICBC的静态库做一个独立的执行文件,用PHP的系统调用函数来执行这个独立的执行文件 2.将ICBC的静态库做出一个PHP扩展 方法一应该比较简单,但是远不如方法二的灵活。搞成PHP扩展,只要服务器编译一次,服务器上的所有客户都可以用的。 有ASP的前科,俺觉得搞个PHP的也不是什么难事。操起google搜了一通,结果发现Zend已经写了一个如何编写php extension的教程: http://devzone.zend.com/article/1021-Extension-Writing-Part-I-Introduction-to-PHP-and-Zend 浏览完牛人的大作,更是信心十足,php扩展其实很简单,分七步走: 1. 制作编译配置文件:config.m4 2. 执行phpize生成扩展的框架 3. 在生成的php_xxx.h中声明自己写的函数 4. 在xxx.c中实现自己的函数 5. 编译自己的扩展 6. 将生成的xxx.so拷贝到php.ini中指定的extensions_dir 7. 在php.ini中打开xxx.so的调用 此问题问题唯一搞的地方就是在config.m4中折腾出正确的Makefile,因为Zend的教程中没有提到,俺自己也折腾了好久,才搞出来。 二、实际操作 1.建立工作环境 将php源码包解开,我的版本的php-4.4.4,转到源码包中的ext目录建立一个新的目录叫icbc,然后在icbc目录下touch三个文件config.m4、php_icbc.h、icbc.c 2.建立config.m4 内容如下: PHP_ARG_ENABLE(icbc, whether to enable ICBC support, [ --enable-icbc Enable ICBC support]) if test \"$PHP_ICBC\" = \"yes\"; then AC_DEFINE(HAVE_ICBC, 1, [Whether you have ICBC]) if test -f ./libicbcapi.a; then PHP_ADD_LIBRARY_WITH_PATH(icbcapi, ./, ICBCAPI_SHARED_LIBADD) PHP_SUBST(ICBCAPI_SHARED_LIBADD) AC_MSG_RESULT(checking for libicbcapi.a is OK) else AC_MSG_RESULT(libicbcapi.a not found) AC_MSG_ERROR(Please make sure the libicbcapi.a is in current directory) [Page] fi PHP_NEW_EXTENSION(icbc, icbc.c, $ext_shared) fi 第三行判断是否要启用icbc扩展, 第五行判断ICBC的静态库是否在当前目录(phpdir/ext/icbc)下 第六、七行将ICBC的静态库加入到编译环境中 3.在php_icbc.h中声明我们要导出的函数icbc_sign、icbc_vsign、icbc_getCertID #ifndef PHP_ICBC_H #define PHP_ICBC_H extern zend_module_entry icbc_module_entry; #define phpext_icbc_ptr &icbc_module_entry #ifdef PHP_WIN32 #define PHP_ICBC_API __declspec(dllexport) #else #define PHP_ICBC_API #endif #ifdef ZTS #include \"TSRM.h\" #endif PHP_MINIT_FUNCTION(icbc); PHP_MSHUTDOWN_FUNCTION(icbc); PHP_RINIT_FUNCTION(icbc); PHP_RSHUTDOWN_FUNCTION(icbc); PHP_MINFO_FUNCTION(icbc); /*Modify youself here*/ PHP_FUNCTION(icbc_sign); PHP_FUNCTION(icbc_vsign); PHP_FUNCTION(icbc_getCertID); /****End of Self control section***/ #ifdef ZTS #define ICBC_G(v) TSRMG(icbc_globals_id, zend_icbc_globals *, v) #else #define ICBC_G(v) (icbc_globals.v) #endif #endif /* PHP_ICBC_H */ 涉及到我们也就 PHP_FUNCTION(icbc_sign); PHP_FUNCTION(icbc_vsign); PHP_FUNCTION(icbc_getCertID); 其他的都是PHP各个状态的入口函数声明 4.编写这三个函数的实现: #ifdef HAVE_CONFIG_H #include \"config.h\" #endif #include \"php.h\" #include \"php_ini.h\" #include \"ext/standard/info.h\" #include \"php_icbc.h\" #include \"icbcapi.h\" static int le_icbc; zend_function_entry icbc_functions[] = { PHP_FE(icbc_sign,NULL) PHP_FE(icbc_vsign,NULL) PHP_FE(icbc_getCertID,NULL) {NULL, NULL, NULL} /* Must be the last line in icbc_functions[] */ }; zend_module_entry icbc_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif \"icbc\", icbc_functions, PHP_MINIT(icbc), PHP_MSHUTDOWN(icbc), PHP_RINIT(icbc), /* Replace with NULL if there’s nothing to do at request start */ PHP_RSHUTDOWN(icbc), /* Replace with NULL if there’s nothing to do at request end */ [Page] PHP_MINFO(icbc), #if ZEND_MODULE_API_NO >= 20010901 \"0.1\", /* Replace with version number for your extension */ #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_ICBC ZEND_GET_MODULE(icbc) #endif PHP_MINIT_FUNCTION(icbc) { return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(icbc) { return SUCCESS; } PHP_RINIT_FUNCTION(icbc) { return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(icbc) { return SUCCESS; } PHP_MINFO_FUNCTION(icbc) { php_info_print_table_start(); php_info_print_table_header(2, \"icbc support\", \"enabled\"); php_info_print_table_end(); } PHP_FUNCTION(icbc_sign) { char* src; int srclen; char* pkey; int keylen; char* keypass; int keypasslen; char* signedbuf; int signedbuflen; FILE* fp; char key[2000]; int rcc; if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\"sss\",&src,&srclen,&pkey,&keylen,&keypass,&keypasslen) == FAILURE){ return; } fp = fopen(pkey,\"rb\"); if(fp == NULL) { return; } fseek(fp,2,SEEK_SET); fread((void*)key,609,1,fp); fclose(fp); if(rcc = sign(src,srclen,key,607,keypass,&signedbuf,&signedbuflen) >= 0){ base64enc(signedbuf,signedbuflen,&signedbuf,&signedbuflen); src = estrndup(signedbuf,signedbuflen); if(signedbuf != NULL) infosec_free(signedbuf); RETURN_STRING(src,1); [Page] }else{ RETURN_LONG(rcc); } }PHP_FUNCTION(icbc_vsign) { char* src; int srclen; char* cert; int certlen; char* vsignedbuf; int vsignedbuflen; FILE* fp; char vcert[2000]; int rcc; if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\"sss\",&src,&srclen,&cert,&certlen,&vsignedbuf,&vsignedbuflen) == FAILURE){ return; } fp = fopen(cert,\"rb\"); if(fp == NULL) { return; } fread((void*)vcert,1525,1,fp); fclose(fp); base64dec(vsignedbuf,vsignedbuflen,&vsignedbuf,&vsignedbuflen); if(rcc = verifySign(src,srclen,vcert,1525,vsignedbuf,vsignedbuflen) >= 0){ if(vsignedbuf != NULL) infosec_free(vsignedbuf); RETURN_TRUE; }else{ if(vsignedbuf != NULL) infosec_free(vsignedbuf); RETURN_LONG(rcc); } } PHP_FUNCTION(icbc_getCertID) { char* arg; char* certid; int arg_len,certidlen; FILE* fp; char cert[2000]; if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\"s\", &arg,&arg_len) == FAILURE){ return; } fp = fopen(arg,\"rb\"); if(fp == NULL) { return; } fread((void*)cert,1525,1,fp); fclose(fp); [Page] if(!getCertID(cert,1525,&certid,&certidlen)) { arg = estrndup(certid,certidlen); if(certid != NULL) infosec_free(certid); RETURN_STRING(arg,1); }else{ return; } } 先在zend_function_entry icbc_functions[]数组中放入我们的要实现的函数名,然后是一堆php各个状态入口函数,详情请看Zend的教程。最后是在PHP_FUNCTION宏定义中放我们声明函数的具体实现。具体实现时难点也就是参数的传入和结果传出,还好PHP已经为我们做了很好的抽象。在Zend的教程中也有详尽的说明,俺就不啰嗦了。关键代码照搬icbc的test.c就行了。 5.编译安装我们的库 先将ICBC的头文件考到当前目录,重命名为icbcapi.php,将静态库也cp过来,重命名为*nix的标准形式libicbcapi.a,然后运行 phpize 生成configure,运行 ./configure --enable-icbc 生成Makefile,这里有一个很搞的地方,在生成的Makefile中最后一句中指定ICBC静态库的地方错了,正确的应该是(红色标记地方): $(LIBTOOL) --mode=link $(CC) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) $(LDFLAGS) -o $@ -export-dynamic -avoid-version -prefer-pic -module -rpath $(phplibdir) $(EXTRA_LDFLAGS) $(shared_objects_icbc) $(ICBCAPI_SHARED_LIBADD) 改好Makefile后就可以执行 make 如果一切顺利的话会在modules中得到我们的icbc.so,将我们的icbc.so拷贝到/usr/local/lib/php/extensions目录下,然后在php.ini中确认extensions_dir的值是/usr/local/lib/php/extensions,然后加入这句话 extension=icbc.so 重启apache后,就可以在php中直接调用这三个函数了 6.测试程序,要将测试的证书和key文件放到php测试文件的当前目录 <?php $realpath = dirname(__FILE__); $key = $realpath.\"/user.key\"; $cert = $realpath.\"/user.crt\"; $src = \"zzz\"; $passwd = \"12345678\"; echo \"The Cert file information is \"; echo icbc_getCertID($cert); echo \"<br>\"; $b64sdata = icbc_sign($src,$key,$passwd); echo \"The string \".$src.\" encrypt by icbc api is \".$b64sdata.\"(base64 encoded)<br>\"; echo \"Now we check it weather is correct....<br>\"; if(icbc_vsign(\"zzz\",$cert,$b64sdata)){ echo \"The signtrue to \".$src.\" is right!!<br>\"; [Page] }else{ echo \"The signtrue to \".$src.\" is wrong!!<br>\"; exit(); } ?>
在VSCode中,有许多有用的PHP扩展可供选择。一些常用的扩展包括: 1. PHP Intelephense:这是一个非常强大的PHP智能代码提示器,提供代码提示、查找定义、类搜索等功能。 2. PHP Debug:这是一个调试器插件,需要安装php-xdebug并进行配置才能正常使用。它可以帮助你在VSCode中进行PHP代码的调试。 3. PHP DocBlocker:这是一个基本的PHP DocBlocking扩展,可以帮助你在编写代码时自动生成文档注释。 以上是几个常用的VSCode PHP扩展,它们可以帮助提高你在编写和调试PHP代码时的效率和准确性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Visual Studio Code +PHP开发 推荐插件](https://blog.csdn.net/hbqjzx/article/details/128780280)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [vscode-php-docblocker:适用于php的简单docblocker](https://download.csdn.net/download/weixin_42153793/18328764)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值