用C语言扩展PHP功能

07月 16th, 2008

转载自:http://www.phpchina.com?action_viewnews_itemid_11432.html

建议读者群:熟悉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的兄弟一个大概的方向!

标签:, ,

相关日志


This entry was posted on 星期三, 07月 16th, 2008 at 6:22 pm and is filed under MYSQL主机. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply