PHP学会网 php培训网 PHP暑期培训 PHP寒假培训 PHP假期培训 » 入门和基础知识 » 用C语言扩展PHP功能
本页主题: 用C语言扩展PHP功能 打印 | 加为IE收藏 | 收藏主题 | 上一主题 | 下一主题

meiwang12363

该用户目前不在线
级别: 中级程序员
精华: 1
发帖: 1069
威望: 0 点
金钱: 0 PYMB
贡献值: 0 点
在线时间:8(小时)
注册时间:2007-04-26
最后登录:2007-09-04

用C语言扩展PHP功能


用C语言扩展[url=javascript:;]PHP[/url]功能
建议读者群:熟悉c,linux,php
  PHP经过最近几年的发展已经非常的流行,而且PHP也提供了各种各样非常丰富的函数。
但有时候我们还是需要来扩展PHP。比如:我们自己开发了一个[url=javascript:;]数据库[/url]系统,而且有自己的
库函数来操作数据库,这时候,如果想在PHP中来操作我们自己的数据库的话,就必须自己
扩展PHP了,像[url=javascript:;]mysql[/url],postgresql,之所以PHP能够提供这些数据库操作函数,也都是扩展了
PHP的结果。
    先看看PHP的源[url=javascript:;]代码[/url]结构:
    $ cd php-4.4.2/ext
    $ ls
    会显示出目前该PHP发行版本中所有的扩展模块。
    如果想深入[url=javascript:;]学习[/url]的话,可以去看看mysql或者postgresql的PHP扩展实现。
 
    下面,我们通过一个简单的模块(mypg)来实现对postgresql的数据库操作。
    $ cd php-4.4.2/ext
    $ ./ext_skel –extname=mypg
    该程序会自动生成mypg目录
    $ cd mypg
    $ ls
    config.m4  CREDITS  EXPERIMENTAL  mypg.c  mypg.php  php_mypg.h  tests
 
    PHP已经自动为我们生成了一些必要的文件和示范代码。
    我们需要作一些修改才能正常的编译和使用该mypg模块。
    $ vi config.m4
    修改成如下内容:
PHP_ARG_ENABLE(mypg, whether to enable mypg support,
              [  –enable-mypg          Enable mypg support])
if test “$PHP_MYPG” != “no”; then
  dnl Write more examples of tests here…
  dnl # –with-mypg -> check with-path
  dnl SEARCH_PATH=”/usr/local /usr”    # you might want to change this
  dnl SEARCH_FOR=”/include/mypg.h”  # you most likely want to change this
  dnl if test -r $PHP_MYPG/; then # path given as parameter
  dnl  MYPG_DIR=$PHP_MYPG
  dnl else # search default path list
  dnl  AC_MSG_CHECKING([for mypg files in default path])
  dnl  for i in $SEARCH_PATH ; do
  dnl    if test -r $i/$SEARCH_FOR; then
  dnl      MYPG_DIR=$i
  dnl      AC_MSG_RESULT(found in $i)
  dnl    fi
  dnl  done
  dnl fi
  dnl
  dnl if test -z “$MYPG_DIR”; then
  dnl  AC_MSG_RESULT([not found])
  dnl  AC_MSG_ERROR([Please reinstall the mypg distribution])
  dnl fi
  dnl # –with-mypg -> add include path
  dnl PHP_ADD_INCLUDE($MYPG_DIR/include)
  dnl # –with-mypg -> check for lib and symbol presence
  dnl LIBNAME=mypg # you may want to change this
  dnl LIBSYMBOL=mypg # you most likely want to change this
  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl  PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYPG_DIR/lib, MYPG_SHARED_LIBADD)
  dnl  AC_DEFINE(HAVE_MYPGLIB,1,[ ])
  dnl ],[
  dnl  AC_MSG_ERROR([wrong mypg lib version or lib not found])
  dnl ],[
  dnl  -L$MYPG_DIR/lib -lm -ldl
  dnl ])
  dnl
  dnl PHP_SUBST(MYPG_SHARED_LIBADD)
  PHP_NEW_EXTENSION(mypg, mypg.c, $ext_shared)
fi

dnl开头的为注释,其实我们也只是把某些注释去掉了。
  然后修改php_mypg.h,内容为:
#ifndef PHP_MYPG_H
#define PHP_MYPG_H
extern zend_module_entry mypg_module_entry;
#define phpext_mypg_ptr &mypg_module_entry
#ifdef PHP_WIN32
#define PHP_MYPG_API __declspec(dllexport)
#else
#define PHP_MYPG_API
#endif
//模块初始化时调用函数
PHP_MINIT_FUNCTION(mypg);
//我们的数据库连接函数
PHP_FUNCTION(mypg_connect);
//我们的数据库操作函数
PHP_FUNCTION(mypg_execute);
//我们的数据库关闭函数
PHP_FUNCTION(mypg_close);
#ifdef ZTS
#include “TSRM.h”
#endif
#endif  /* PHP_MYPG_H */ 
继续修改mypg.c,内容改为:
#ifdef HAVE_CONFIG_H
#include “config.h”
#endif
#include “php.h”
#include “php_ini.h”
#include “ext/standard/info.h”
#include “php_mypg.h”
#include “libpq-fe.h”
int le_link;
function_entry mypg_functions[] = {
        PHP_FE(mypg_connect,                                                    NULL)
        PHP_FE(mypg_execute,                                                    NULL)
        PHP_FE(mypg_close,                                                      NULL)
        {NULL, NULL, NULL}
};
zend_module_entry mypg_module_entry = {
        STANDARD_MODULE_HEADER,
        “mypg”, mypg_functions, PHP_MINIT(mypg), NULL, NULL, NULL,
        NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(mypg)
//数据库链接关闭函数
static void _close_mypg_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
        PGconn *link = (PGconn *)rsrc->ptr;
        PQfinish(link);
}
PHP_MINIT_FUNCTION(mypg)
{
    //注册资源回收函数,如果没有显示用mypg_close关闭数据库连接的化,PHP会自动调用该函数释放资源
    le_link = zend_register_list_destructors_ex(_close_mypg_link, NULL, “mypg link”, module_number);
    return SUCCESS;
}
//连接数据库
static void php_mypg_do_connect(INTERNAL_FUNCTION_PARAMETERS)
{
        PGconn *link;
        //只接受一个函数参数
        if(ZEND_NUM_ARGS() != 1)
        {
            WRONG_PARAM_COUNT;
        }
        zval **connect_info;
        /* get the connection information string */
        if (zend_get_parameters_ex(1, &connect_info) == FAILURE) {
            RETURN_FALSE;
        }
        /* create our resource hash key */
        convert_to_string_ex(connect_info);
        //调用libpq, 执行数据库连接
        if ((link=PQconnectdb(Z_STRVAL_PP(connect_info))) && PQstatus(link)!=CONNECTION_OK) {
            RETURN_FALSE;
        }
     
        //将return_value注册为得到的数据库连接
        /* add it to the list */
        ZEND_REGISTER_RESOURCE(return_value, link, le_link);
}
PHP_FUNCTION(mypg_connect)
{
    php_mypg_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
//我们自己定义的数据库操作函数
PHP_FUNCTION(mypg_execute)
{
        zval **query, **link = NULL;
        int id;
        PGconn *conn;
        PGresult *res;
        //参数为2, 1:执行的sql  2:数据库链接句柄
        switch(ZEND_NUM_ARGS()) {
                case 2:
                        if (zend_get_parameters_ex(2, &query, &link)==FAILURE) {
                                WRONG_PARAM_COUNT;
                        }
                        break;
                default:
                        WRONG_PARAM_COUNT;
                        break;
        }
     
        //取得数据库链接
        ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1, “mypg link”,  le_link);
        convert_to_string_ex(query);
     
        //通过libpq执行SQL
        res = PQexec(conn, Z_STRVAL_PP(query));
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
                RETURN_FALSE;
        }
        PQclear(res);
       
        RETURN_TRUE;
}
PHP_FUNCTION(mypg_close)
{
        zval **link;
        int id;
        PGconn *conn;
        switch (ZEND_NUM_ARGS()) {
                case 1:
                        if (zend_get_parameters_ex(1, &link)==FAILURE) {
                                RETURN_FALSE;
                        }
                        break;
                default:
                        WRONG_PARAM_COUNT;
                        break;
        }
        if(link == NULL)
        {
                RETURN_FALSE;
        }
        //根据资源句柄取得资源
        ZEND_FETCH_RESOURCE(conn, PGconn *, link, -1,”mypg link”,  le_link);
     
        //删除该资源,PHP自动调用前面注册的函数来关闭数据库链接
        zend_list_delete(Z_RESVAL_PP(link));
        RETURN_TRUE;
}
    mypg模块就基本开发完成了,我们需要重新为php生成configure文件。
 
    $ cd php-4.4.2
    $ rm -rf autom4te.cache/; rm -f configure
    $ ./buildconf  –force
    此时PHP会读取所有ext/子目录下的config.m4,并集成到新生成的configure脚本中。
    如果没有意外,运行如下命令会得到如下结果:
    $ ./configure –help | grep mypg
      –enable-mypg          Enable mypg support
    编译PHP:
    $ ./configure —enable-mypg
    由于要链接libpq.so,可以vi Makefile
    在EXTRA_LIBS后面加上:-lpq 来把libpq编译进去,当然也可以通过修改mypg的config.m4来实现,
    这里不在啰嗦。
    $ make
    $ make install
 
    编写我们的模块测试脚本:testmypg.php
/*
* this is the sample php code
* to invoke our module: mypg
*/
$link = mypg_connect(”hostaddr=172.16.19.8 dbname=pgsql user=pgsql password=12345″);
if($link)
{
        echo “Successfully connected  to PostgreSQL.\n”;
}
else
{
        die(”Connect error.\n”);
}
$sql = “insert into test values(’12345′,’23145′)”;
mypg_execute($sql, $link);
$link2 = $link;
mypg_execute($sql, $link2);
mypg_execute($sql, $link);
mypg_close($link);
echo “Database query ok.\n”;
?>
运行该PHP程序,如果在postgresql的pgsql库中有table: test (col1 varchar(100), col2 varchar(100))
里面应该已经有2条记录了。    编写php模块扩展需要很多PHP源码的知识,可以通过参考其他module或者直接阅读PHP代码来逐步提高自己
的开发能力。
    php官方的站点上也有一些文章可供参考:http://cn2.php.net/manual/en/internals2.php
    希望这篇文章能够给想扩展PHP的兄弟一个大概的方向!
顶端 Posted: 2007-08-20 09:40 | [楼 主]
PHP学会网 php培训网 PHP暑期培训 PHP寒假培训 PHP假期培训 » 入门和基础知识

时:11-23 04:42 Copyright © 2006 phpwhy.com 权
ICP05060669

曳息 -