dedecms织梦内容管理系统    
首页 | java | C/C++ | PHP | 操作系统 | ajax | 脚本编程 | 安全技术 | 本站下载页 | flex | CRM | 专题 | QQ群 | 测试中心 | 会员中心 | 积分规则
  当前位置:主页>PHP>文章内容
用C语言扩展PHP功能
来源: 作者:
 from: http://www.loveopensource.com/?p=15

用C语言扩展PHP功能

建议读者群:熟悉c,linux,php
PHP经过最近几年的发展已经非常的流行,而且PHP也提供了各种各样非常丰富的函数。
但有时候我们还是需要来扩展PHP。比如:我们自己开发了一个数据库系统,而且有自己的
库函数来操作数据库,这时候,如果想在PHP中来操作我们自己的数据库的话,就必须自己
扩展PHP了,像mysql,postgresql,之所以PHP能够提供这些数据库操作函数,也都是扩展了
PHP的结果。
先看看PHP的源代码结构:
$ cd php-4.4.2/ext
$ ls
会显示出目前该PHP发行版本中所有的扩展模块。
如果想深入学习的话,可以去看看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的兄弟一个大概的方向!
 
上一篇:设计模式(下)   下一篇:用C语言写PHP扩展的步骤
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
用户名: 新注册) 密码: 匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论
  热点文章
·php开发
·C语言数组排序小结
·通过对PHP服务器端特性的配置加
·php与mysql三日通
·大家所使用的PHP开发环境
·Python 与 C++ 程序的简单实例对
·c++ 数组与指针
·C++中的内存管理(new、delete、
·PHP缓存的实现
·针对PHP新手总结的PHP基础知识
·一个简单实现多条件查询的例子
·PHP串行化变量和序列化对象
  相关文章
·用C语言写PHP扩展的步骤
·php实用函数
·推荐阅读:php技术生成静态页面
·PHP表单
·PHP串行化变量和序列化对象
·一个简单实现多条件查询的例子
·针对PHP新手总结的PHP基础知识
·PHP缓存的实现
·大家所使用的PHP开发环境
·php与mysql三日通
·通过对PHP服务器端特性的配置加
·php生成随机数
  相关信息
copy right @ 百家拳软件项目研究室 2007 辽ICP备07011763