用C语言扩展PHP功能
用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
http://cn2.php.net/manual/zh/internals2.structure.php
??? 希望這篇文章能夠給想擴展PHP的兄弟一個大概的方向!
總結
以上是生活随笔為你收集整理的用C语言扩展PHP功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4K王牌电视机机配置?
- 下一篇: 在广东漂泊十年是什么歌呢