php扩展实战 ------ 获得ip的来源地址

| No Comments

1 前言

  • 主要目的让大家了解一下怎么做PHP语言的扩展,仍然以上次叙述的Perl的扩展的例子——获得IP来源地址为例。

2 前提条件

  • 假设你已经拥有了 LAMP (Linux+Apache+Mysql+PHP的缩写),并假设其安装路径分别是:
Apache:/usr/local/apache
Mysql:/usr/local/mysql
PHP:/usr/local/php
  • 目前所叙述的实例可能与 mysql 没有太多的关系,所以无关紧要,但是 PHP 是必须安装的;
  • 另外,需要 PHP 的源码,如果你没有,可以去 http://www.php.net 获取 PHP 源码,其源码路径位:
PHPSrc:/usr/local/php/src
  • 末了说句,本实例完全在 Linux 64 位平台下演示,若有出入,可以随时联系笔者。

3 流程及步骤

  • 其实制作PHP扩展非常简单, ext_skel 命令的帮助已说明得非常详细,如下所示:
[Cnangel@localhost ~]$cd /usr/local/php/src/ext
[Cnangel@localhost ext]$ext_skel --help
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]
[--skel=dir] [--full-xml] [--no-help]

--extname=module module is the name of your extension
--proto=file file contains prototypes of functions to create
--stubs=file generate only function stubs in file
--xml generate xml documentation to be added to phpdoc-cvs
--skel=dir path to the skeleton directory
--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
  • 尝试着创建一个扩展 getaddress
[Cnangel@localhost ext]$ext_skel --extname=getaddress
Creating directory getaddress
Creating basic files: config.m4 config.w32 .cvsignore getaddress.c php_getaddress.h CREDITS EXPERIMENTAL tests/001.phpt getaddress.php [done].

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

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

Repeat steps 3-6 until you are satisfied with ext/getaddress/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.
  • 上面的后续的帮助步骤已经说得比较清楚,一共 8 个步骤;

4 详细过程描述

4.1 建立扩展目录

  • 方便的 ext_skel 命令能帮助建立一个扩展模型 getaddress ,系统会自动建立一个 getaddress 目录,其文件会相应的生成在 getaddress 目录内;

4.2 描述及编辑config.m4

  • ext_skel 建立的目录里面一般有 config.m4 这个文件,这里面有一些基础的宏定义:
    • dnl 是注释;
    • PHP_ARG_WITH 或者 PHP_ARG_ENABLE 指定了PHP扩展模块的工作方式;
    • PHP_REQUIRE_CXX 用于指定这个扩展用到了C++;
    • PHP_ADD_INCLUDE 指定PHP扩展模块用到的头文件目录;
    • PHP_CHECK_LIBRARY 指定PHP扩展模块PHP_ADD_LIBRARY_WITH_PATH定义以及库连接错误信息等;
    • PHP_SUBST 用于说明这个扩展编译成动态链接库的形式;
    • PHP_NEW_EXTENSION 用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开;
  • 这里指定PHP扩展模块的工作方式为 PHP_ARG_ENABLE ,需要修改config.m4文件为:
[Cnangel@localhost getaddress]vim config.m4
找到里面有类似几行:
    dnl PHP_ARG_WITH(getaddress, for getaddress support,
dnl Make sure that the comment is aligned:
dnl [ --with-getaddress Include getaddress support])

dnl Otherwise use enable:

dnl PHP_ARG_ENABLE(getaddress, whether to enable getaddress support,
dnl Make sure that the comment is aligned:
dnl [ --enable-getaddress Enable getaddress support])
修改成:
    dnl PHP_ARG_WITH(getaddress, for getaddress support,
dnl Make sure that the comment is aligned:
dnl [ --with-getaddress Include getaddress support])

dnl Otherwise use enable:

PHP_ARG_ENABLE(getaddress, whether to enable getaddress support,
Make sure that the comment is aligned:
[ --enable-getaddress Enable getaddress support])
  • 除了修改 config.m4 外,还需要修改的文件有 getaddress.cphp_getaddress.h 两个文件,下面会说到该文件的修改。

4.3 创建configure文件

  • 源码修改:进入源代码根目录,使用工具 buildconf 创建 configure 文件,其命令如下:
[Cnangel@localhost getaddress]cd /usr/local/php/src
[Cnangel@localhost src]./buildconf
  • 扩展修改:进入扩展目录,使用工具 phpize 创建 configure 文件,其目录如下:
[Cnangel@localhost getaddress]/usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519

4.4 创建Makefile文件

  • 上个步骤中创建了 configure 文件,记住,一般在类unix系统中, configure 文件是一个可执行文件,用来创建编译过程中所用到的make命令所需要的Makefile文件,其创建过程如下:
./configure --enable-getaddress --with-apxs=/usr/local/apache/bin/apxs --with-php-config=/usr/local/php/bin/php-config
  • 注意,如果你写的扩展与apache有关,则需要关联apxs,产生apache的modules。

4.5 编译过程

  • 编译过程是一个调试过程,出现错误了需要检查 config.m4getaddress.cphp_getaddress.h 这几个文件是否编写正确,编译的过程十分简单,命令如下:
make

4.6 安装扩展模块

  • 安装扩展模块一般有两种安装,一种是直接:
make install
  • 结果会安装到: /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/ 目录,然后在 php.ini 里面通过 extension_dir 将该目录设置为php的扩展目录,并在php.ini中打开这个扩展:
extension=getaddress.so
  • 另外一种是直接复制。一般经过编译过程这个步骤后,会在 getaddress 目录下生成一个目录: modules ,该目录下面有一个已经编译好的.so文件,如果是静态编译,可能是.a或.la;把该文件复制到一个目录下,比如: /usr/loca/php/ext/ ,然后直接调用函数 dl 来调用其 api。

4.7 运行测试

  • getaddress 目录下有一个 getaddress.php 文件专门用来测试你的扩展模块是否正确运行,该文件即可以作为 CGI 来运行又可以当作脚本执行,命令如下:
[Cnangel@localhost getaddress]php -f getaddress.php
Functions available in the test extension:
confirm_getaddress_compiled

Congratulations! You have successfully modified ext/getaddress/config.m4. Module getaddress is now compiled into PHP.

4.8 增添PHP扩展模块函数

  • 上述讲了这么多,这节才是最主要的。PHP扩展模块主要有三个方面的作用:
    1. 增加PHP基础函数没有的功能或更加 OOP(Object Oriented Programming) 的思想供工程调用;
    2. PHP的扩展一般是汇编、C/C++等编译性语言缩写,二进制运行消耗时间比解释性语言实现同样的功能少得多;
    3. 由于PHP扩展一般是二进制的,所以一般来说不开源,很方便的保护了版权,能够进行商业运用。
  • 默认的 getaddress.c 中, zend_function_entry 是导出函数列表, zend_module_entry 描述了模块的信息。
  • 编写代码应该注意:
    1. 如果是C++开发,记住把getaddress.c的后缀改为cpp,并用extern "C"来把c相关代码包起来;

5 Bugs

  • 在64位机器上和32位机器上会出现很大的差异,主要在QQWry.c文件;
  • 多个引用php函数会出现corp dump情况,具体原因还未查清;

6 实例代码

  • 注意,修复一处Bug:将
 Z_STRVAL_P(file) == NULL
代替
 Z_STRLEN_P(file) == 0

7 总结

  • 由于作者对C指针运用不太熟练,所以在操作指针时,往往会出现corp dump,这方面有待加强;
  • 就PHP扩展来说,涵盖的面比较广,需要丰富的知识面做铺垫才能做好一个优秀的扩展。

Leave a comment

Archives

Pages

Powered by Movable Type 5.2.2

December 2012

Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

Recent Assets

  • dish_st4.png
  • dish_m5.png
  • dish_3.png
  • dish_two.png
  • dish_6.png
  • dish_1.png.png
  • 照片1028 105.jpg
  • 照片1028 088.jpg
  • 照片1028 084.jpg
  • 照片1028 081.jpg
Creative Commons License
This blog is licensed under a Creative Commons License.

About this Entry

This page contains a single entry by Cnangel published on February 23, 2008 3:03 PM.

太帅了,3D was the previous entry in this blog.

怎样学习使用libiconv库 is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.