項目做了快半年了,關於php的擴充模組開發,從完全不懂到邊查資料邊摸索,到現在的靈活運用,其間也經曆了不少的困惑期,在此以文章記錄,希望對有同樣需求的人起到一定的協助作用。
一. 產生一個簡單的php extension
我們需要兩個目錄:php src,php bin,到網上下載一個php源碼包,解壓,安裝。
php的解壓目錄記為 phpsrc(如:/home/src/php-4.4.4) ,安裝目錄記為 phpbin(如 /usr/local/php)
在shell下輸入(以後遇到有shell的地方我就用#開頭,不另陳述)
# cd phpsrc/ext
# ./ext_skel --extname=test_module
Creating directory test_module
Creating basic files: config.m4 .cvsignore test_module.c php_test_module.h CREDITS EXPERIMENTAL tests/001.phpt test_module.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/test_module/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-test_module
5. $ make
6. $ ./php -f ext/test_module/test_module.php
7. $ vi ext/test_module/test_module.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/test_module/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.
系統自動產生 test_module檔案夾;接下來我們要修改幾個檔案:config.m4, test_module.c,php_test_module.h, 如下:
1) 修改config.m4
# cd test_module
# vi config.m4
找到這幾行
dnl PHP_ARG_ENABLE(test_module, whether to enable test_module support,
dnl Make sure that the comment is aligned:
dnl [ --enable-test_module Enable test_module support])
去掉這幾行前面的dnl,改為
PHP_ARG_ENABLE(test_module, whether to enable test_module support,
Make sure that the comment is aligned:
[ --enable-test_module Enable test_module support])
這樣以後編譯php時,./configure後面加 --enable-test_module 就可以載入你的php模組了!
(接下來的2)你可以做也可以不做,直接跳到第4步也可以運行。)
2) 修改test_module.c,輸出自己想要的東西
# vi test_module.c
找到這段
PHP_FUNCTION(confirm_test_module_compiled)
{
char *arg = NULL;
int arg_len, len;
char string[256];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "test_module", arg);
RETURN_STRINGL(string, len, 1);
}
改為:
PHP_FUNCTION(confirm_test_module_compiled)
{
zend_printf("This is a test module !");
}
3)編譯連結
# cd phpsrc/ext
# cc -fpic -DCOMPILE_DL_TEST_MODULE=1 -I/usr/local/include -I. -I../main -I.. -I../TSRM -I../Zend -c -o test_module/test_module.o test_module/test_module.c
執行完之後會在 目錄下產生一個test_module.o檔案,接下來串連:
# cc -shared -L/usr/local/lib -rdynamic -o test_module/test_module.so test_module/test_module.o
4)測試:
有兩種途徑可以測試你的擴充模組是否正確,一是在phpbin目錄下運行test.php, 二是在web browser上運行test.php(如果已經安裝apache等web伺服器的話)。
這裡採用phpbin測試,不需要任何web伺服器。
拷貝test_module.so到phpbin的相應目錄下
(如果不知道是哪個目錄,或者沒有拷貝到正確的位置,在啟動並執行時候出錯資訊裡會指出應該在什麼路徑。)
# mkdir -p phpbin/lib/php/extensions/ (其實這個目錄就是看你php.ini裡設定extension_dir了)
# cp test_module/test_module.so phpbin/lib/php/extensions/
在phpbin目錄下建立一個test.php檔案,在裡面寫入
dl("test_module.so");
//調用函數
test_module();
?>
在phpbin目錄下運行
執行./php –q test.php,如果過程無誤,將會顯示:
This is a test module !
測試成功,接下來我們可以往擴充模組中添加自己的函數,實現自己的功能啦。
二. 向擴充模組中添加函數
向php擴充模組中添加函數,只需要修改test_module.c和php_test_module.h。
比如要向擴充模組中添加一個函數sayhello(),我們需要做以下工作:
1) 修改 php_test_module.h 添加函式宣告
在檔案中PHP_FUNCTION(confirm_my_module_compiled);一行前面添加下面的代碼
PHP_FUNCTION(say_hello);
儲存檔案退出
2) 修改 test_module.c
在function_entry中添加函數的entry:
function_entry my_module_functions[] = {
PHP_FE(say_hello, NULL) /* ß添加著一行代碼 */
PHP_FE(confirm_my_module_compiled, NULL) /* For testing, remove later. */
{NULL, NULL, NULL} /* Must be the last line in my_module_functions[] */
};
在檔案的最後添加函數的實現:
PHP_FUNCTION(say_hello)
{
zend_printf("hello world/n");
}
儲存檔案退出
3)重新編譯連結,產生新的.so檔案。
# cd phpsrc/ext
# cc -fpic -DCOMPILE_DL_TEST_MODULE=1 -I/usr/local/include -I. -I../main -I.. -I../TSRM -I../Zend -c -o test_module/test_module.o test_module/test_module.c
執行完之後會在 目錄下產生一個test_module.o檔案,接下來串連:
# cc -shared -L/usr/local/lib -rdynamic -o test_module/test_module.so test_module/test_module.o
三. 調用第三方C/C++庫
在PHP擴充模組中調用第三方的C/C++庫,與普通的C/C++程式調用C/C++庫一樣,只要把庫檔案的位置放對就可以了。下面舉例說明:
1. 調用動態庫a.so
需要的檔案,a.so,a.h(a.h主要做資料類型聲明和入口函式宣告),都放在 test_module目錄下。
調用a.so:
1) 在test_module.c的開頭添加a.h:
#include "php.h
#include "php_ini.h"
#include "a.h"
添加了標頭檔後,可以在test_module.c的函數中調用a.so的函數介面。
2) 重新編譯連結,連結時加入a.so:
# cd phpsrc/ext
# cc -fpic -DCOMPILE_DL_TEST_MODULE=1 -I/usr/local/include -I. -I../main -I.. -I../TSRM -I../Zend -c -o test_module/test_module.o test_module/test_module.c
執行完之後會在 目錄下產生一個test_module.o檔案,接下來串連:
# cc -shared -L/usr/local/lib -rdynamic -o test_module/test_module.so test_module/test_module.o test_module/a.so
[如果a.so內部實現是C++,連結時還應該加入參數 –lstdc++,即:
# cc –shared –lstdc++ -L/usr/local/lib -rdynamic -o test_module/test_module.so test_module/test_module.o test_module/a.so
]
3) 測試test_module.so時,把test_module.so和a.so都拷貝到phpbin/lib/php/extensions/下。
2. 調用靜態庫a.a
需要的檔案,a.so,a.h(a.h主要做資料類型聲明和入口函式宣告),都放在 test_module目錄下。
調用a.a:
1) 和2)都與調用a.so相同。
3) 測試test_module.so時,把test_module.so拷貝到phpbin/lib/php/extensions/下,a.a不需要。