Chinaunix
标题:
编写过PHP模块的朋友请进来指导一下!
[打印本页]
作者:
maya1982
时间:
2007-03-02 12:51
标题:
编写过PHP模块的朋友请进来指导一下!
系统信息:
Debian Etch (Kernel 2.6.18-3-686 )
5.0.32-Debian_3-log Debian etch distribution
PHP 5.2.0-8
问题:用php 源代码树下的ext_skel 创建了一个新的模块基本骨架。添加了一个模块函数。在php脚本中调用
sample_passport函数,没有任何输出。
原来的连接数据库的代码工作正常。我想把数据库的代码放到php模块函数中。
mysql代码:
query.h
// system header files
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// mysql header files
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
static void print_error(MYSQL *mysql, char *message);
复制代码
query.c
/*
* shell> gcc -o firstquery firstquery.c -lmysqlclient
*/
#include "firstquery.h"
static void print_error(MYSQL *mysql, char *message)
{
fprintf (stderr, "%s\n", message);
if (mysql != NULL)
{
#if MYSQL_VERSION_ID >= 40101
fprintf(stderr,"MYSQL ERROR:[ERRNO] %u [SQLSTATE] %s [MESSAGE] %s\n",
mysql_errno(mysql), mysql_error(mysql),mysql_sqlstate(mysql));
#else
fprintf(stderr,"MYSQL ERROR:[ERRNO] %u [MESSAGE] %s\n",
mysql_errno(mysql), mysql_error(mysql));
#endif
}
}
int main(int argc, char *argv[]) {
/* MYSQL DATA TYPES*/
MYSQL mysql;
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *fields;
/* VARIABLES */
unsigned int numrows, numcols, i;
/* init connection data structure
conn = mysql_init (NULL);
if (conn == NULL)
{
fprintf (stderr, "mysql_init() failed (probably out of memory)\n");
exit (1);
}
*/
mysql_init(&mysql); // init connection data structure protoype: MYSQL *mysql_init(MYSQL *mysql)
if(&mysql == NULL){
fprintf (stderr, "mysql_init() failed (probably out of memory)\n");
exit(EXIT_FAILURE);
}
/* Establish a database connection
MYSQL *mysql_real_connect(
MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long client_flag // CLIENT_COMPRESS | CLIENT_FOUND_ROWS |CLIENT_IGNORE_SPACE
// | CLIENT_INTERACTIVE | CLIENT_LOCAL_FILES
// | CLIENT_MULTI_STATEMENTS
// | CLIENT_MULTI_RESULTS | CLIENT_NO_SCHEMA
// | CLIENT_ODBC | CLIENT_SSL
)
*/
if (!mysql_real_connect(
&mysql, // connect handle
"localhost", // hostname
"develop", // mysql username
"**********", // password
"passport", // database name
3306, // port
"/var/run/mysqld/mysqld.sock", // unix socket
0)
){
print_error(&mysql,"mysql_real_connect():Can not connect to mysql database");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
/* Execute a query */
/*char query[] = "SELECT book_id, cond, title FROM book";*/
char query[] = "SELECT username,usertypeid,email,status,ipaddr_registered FROM passport";
if (mysql_query(&mysql, query) != 0)
{
print_error(&mysql,"mysql_query():failed query to database");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
/* Assign the result handle */
result = mysql_use_result(&mysql);
if (!result){
print_error(&mysql,"mysql_use_result():Can not get the result set");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
/* Find the number of columns in the result */
numcols = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
/* Loop through the result set to display it */
printf("\n");
printf("----------------------------------------------------------------------\n");
for(i = 0; i < numcols; i++){
printf("%s\t",fields[i].name);
}
printf("\n");
while (row = mysql_fetch_row(result)) {
for(i=0; i < numcols; i++) {
printf("%s\t", row[i]);
}
printf("\n");
}
printf("\n");
exit(EXIT_SUCCESS);
}
复制代码
php代码:
php_sample.h
#ifndef PHP_SAMPLE_H
/* Prevent double inclusion */
#define PHP_SAMPLE_H
/* Define Extension Properties
* 定义扩展属性,名称和版本号
*/
#define PHP_SAMPLE_EXTNAME "sample"
#define PHP_SAMPLE_EXTVER "1.0"
/*
* Import configure options when building outside of the PHP source tree
* 在php源代码树外构建时导入配置选项
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Include PHP Standard Header
* 包含php标准头文件
*/
#include "php.h"
/* Define the entry point symbol
* Zend will use when loading this module
* 定义入口点符号,Zend将在加载此模块时使用
*/
extern zend_module_entry sample_module_entry;
#define phpext_sample_ptr &sample_module_entry
/* 本模块在phpinfo() 用户空间函数输出函数的原型定义 */
static ZEND_MINFO_FUNCTION(sample);
/* 模块(扩展)函数原型声明 */
ZEND_FUNCTION(sample_long);
ZEND_FUNCTION(sample_hello_world);
ZEND_FUNCTION(sample_array_range);
ZEND_FUNCTION(sample_hello_greeting);
ZEND_FUNCTION(sample_hello_optional);
ZEND_FUNCTION(sample_onearg);
ZEND_FUNCTION(sample_getlong);
ZEND_FUNCTION(sample_variable_arguments);
ZEND_FUNCTION(sample_var_dump);
ZEND_FUNCTION(sample_return_array);
ZEND_FUNCTION(sample_array);
ZEND_FUNCTION(sample_array_passport);
ZEND_FUNCTION(sample_passport);
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
ZEND_FUNCTION(sample_reference_a);
static
ZEND_BEGIN_ARG_INFO_EX(php_sample_retref_arginfo, 0, 1, 0)
ZEND_END_ARG_INFO ()
#endif /* PHP >= 5.1.0 */
#endif /* PHP_SAMPLE_H */
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
static void print_error(MYSQL *mysql, char *message);
复制代码
sample.c
#include "php_sample.h"
static function_entry php_sample_functions[] = {
ZEND_FE(sample_long, NULL)
ZEND_FE(sample_hello_world, NULL)
ZEND_FE(sample_hello_greeting, NULL)
ZEND_FE(sample_hello_optional, NULL)
ZEND_FE(sample_array_range, NULL)
ZEND_FE(sample_onearg, NULL)
ZEND_FE(sample_getlong, NULL)
ZEND_FE(sample_variable_arguments, NULL)
ZEND_FE(sample_var_dump, NULL)
ZEND_FE(sample_return_array, NULL)
ZEND_FE(sample_array, NULL)
ZEND_FE(sample_array_passport, NULL)
ZEND_FE(sample_passport, NULL)
{ NULL, NULL, NULL }
};
zend_module_entry sample_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_SAMPLE_EXTNAME,
php_sample_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_SAMPLE_EXTVER,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_SAMPLE
ZEND_GET_MODULE(sample)
#endif
ZEND_FUNCTION(sample_long)
{
ZVAL_LONG(return_value, 42);
return;
}
ZEND_FUNCTION(sample_hello_world)
{
char *name;
int name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
RETURN_NULL();
}
php_printf("Hello ");
PHPWRITE(name, name_len);
php_printf("!<br/>");
// ZVAL_STRING(return_value, "<br/>Hello World!<br/>",1);
// return;
}
/*
function sample_hello_world($name, $greeting) {
echo "Hello $greeting $name!\n";
}
sample_hello_world('John Smith', 'Mr.');
*/
ZEND_FUNCTION(sample_hello_greeting)
{
if(ZEND_NUM_ARGS() != 2){
WRONG_PARAM_COUNT;
}
char *name;
int name_len;
char *greeting;
int greeting_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&name, &name_len, &greeting, &greeting_len) == FAILURE) {
RETURN_NULL();
}
php_printf("Hello ");
PHPWRITE(greeting, greeting_len);
php_printf(" ");
PHPWRITE(name, name_len);
php_printf("!\n");
}
// 解析可选参数
/*function sample_hello_world($name, $greeting='Mr./Ms.') {
echo "Hello $greeting $name!\n";
}
sample_hello_world('Ginger Rogers','Ms.');
sample_hello_world('Fred Astaire');*/
ZEND_FUNCTION(sample_hello_optional)
{
if(ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2){
WRONG_PARAM_COUNT;
}
char *name;
int name_len;
char *greeting = "Mr./Mrs.";
int greeting_len = sizeof("Mr./Mrs.") - 1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",&name, &name_len, &greeting, &greeting_len) == FAILURE) {
RETURN_NULL();
}
php_printf("Hello ");
PHPWRITE(greeting, greeting_len);
php_printf(" ");
PHPWRITE(name, name_len);
php_printf("!\n");
}
ZEND_FUNCTION(sample_array_range)
{
if (return_value_used) {
int i;
array_init(return_value);
for(i = 0; i < 1000; i++) {
add_next_index_long(return_value, i);
}
return;
} else {
php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Static return-only function called without processing output");
RETURN_NULL();
}
}
ZEND_FUNCTION(sample_onearg)
{
zval *firstarg;
if (zend_get_parameters(ZEND_NUM_ARGS(), 1, &firstarg) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,"Expected at least 1 parameter.");
RETURN_NULL();
}
}
ZEND_FUNCTION(sample_getlong)
{
long foo;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"l", &foo) == FAILURE) {
RETURN_NULL();
}
php_printf("The integer value of the parameter you "
"passed is: %ld\n", foo);
RETURN_TRUE;
}
ZEND_FUNCTION(sample_variable_arguments)
{
}
ZEND_FUNCTION(sample_var_dump)
{
int i, argc = ZEND_NUM_ARGS();
zval ***args;
args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
if (ZEND_NUM_ARGS() == 0 ||
zend_get_parameters_array_ex(argc, args) == FAILURE) {
efree(args);
WRONG_PARAM_COUNT;
}
for (i=0; i<argc; i++) {
php_var_dump(args[i], 1 TSRMLS_CC);
}
efree(args);
}
//ZEND_FUNCTION(sample_arg_fullnull)
//{
//}
//ZEND_FUNCTION(sample_arg_nullok)
//{
//}
ZEND_FUNCTION(sample_return_array)
{
zval *my_long;
// Declaring and allocating return_value to be an array
array_init(return_value);
//Creates and assign the long element at (long)42
MAKE_STD_ZVAL(my_long);
ZVAL_LONG(my_long, 42);
//Make this our $array[0] I do not use add_index_long to
//to show a "by-hand" assignation
zend_hash_index_update(HASH_OF(return_value), 0, (void *)&my_long, sizeof(zval *), NULL);
//Returns nothing to satisfy the void prototype
return ;
}
//ZEND_FUNCTION(sample_return_object){}
ZEND_FUNCTION(sample_array)
{
zval *subarray;
array_init(return_value);
/* Add some scalars */
add_assoc_long(return_value, "life", 42);
add_index_bool(return_value, 123, 1);
add_next_index_double(return_value, 3.1415926535);
/* Toss in a static string, dup'd by PHP */
add_next_index_string(return_value, "Foo", 1);
/* Now a manually dup'd string */
add_next_index_string(return_value, estrdup("Bar"), 0);
/* Create a subarray */
MAKE_STD_ZVAL(subarray);
array_init(subarray);
/* Populate it with some numbers */
add_next_index_long(subarray, 1);
add_next_index_long(subarray, 20);
add_next_index_long(subarray, 300);
add_next_index_long(subarray, 1);
/* Place the subarray in the parent */
add_index_zval(return_value, 444, subarray);
}
ZEND_FUNCTION(sample_array_passport){
array_init(return_value);
add_assoc_long(return_value, "passport_id", 1);
add_assoc_string(return_value, "passport_name", "hezhiqiang", 1);
add_assoc_string(return_value, "passport_email", "developerworks@163.com", 1);
}
ZEND_FUNCTION(sample_passport){
MYSQL mysql;
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *fields;
unsigned int numrows, numcols, i;
// zval *rrow;
// MAKE_STD_ZVAL(rrow);
// array_init(return_value);
// array_init(rrow);
mysql_init(&mysql); // init connection data structure protoype: MYSQL *mysql_init(MYSQL *mysql)
if(&mysql == NULL){
fprintf (stderr, "mysql_init() failed (probably out of memory)\n");
exit(EXIT_FAILURE);
}
if (!mysql_real_connect(
&mysql, // connect handle
"localhost", // hostname
"develop", // mysql username
"**********", // password
"passport1", // database name
3306, // port
"/var/run/mysqld/mysqld.sock", // unix socket
0)
){
print_error(&mysql,"mysql_real_connect():Can not connect to mysql database");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
/* Execute a query */
char query[] = "SELECT passportid,username,usertypeid,email,status,ipaddr_registered FROM passport WHERE passportid = 1";
if (mysql_query(&mysql, query))
{
print_error(&mysql,"mysql_query():failed query to database");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
result = mysql_use_result(&mysql); // get result set
if (!result){
print_error(&mysql,"mysql_use_result():Can not get the result set");
mysql_close(&mysql);
exit(EXIT_FAILURE);
}
numcols = mysql_num_fields(result); // get the number of columns in the result
fields = mysql_fetch_fields(result); // get fields infomation
// for(i = 0; i < numcols; i++){
// printf("%s\t",fields[i].name); // print field name
// }
// while (row = mysql_fetch_row(result)) {
// int j = 0;
// for(i=0; i < numcols; i++) {
// printf("%s\t", row[i]);
// add_assoc_string(rrow,fields[i].name,row[i],1);
// }
// add_index_zval(return_value, j, rrow);
// j++;
// }
/* Loop through the result set to display it */
printf("\n");
printf("----------------------------------------------------------------------\n");
for(i = 0; i < numcols; i++){
printf("%s\t",fields[i].name);
}
printf("\n");
while (row = mysql_fetch_row(result)) {
for(i=0; i < numcols; i++) {
printf("%s\t", row[i]);
}
printf("\n");
}
printf("\n");
}
static void print_error(MYSQL *mysql, char *message)
{
fprintf (stderr, "%s\n", message);
if (mysql != NULL)
{
#if MYSQL_VERSION_ID >= 40101
fprintf(stderr,"MYSQL ERROR:[ERRNO] %u [SQLSTATE] %s [MESSAGE] %s\n",
mysql_errno(mysql), mysql_error(mysql),mysql_sqlstate(mysql));
#else
fprintf(stderr,"MYSQL ERROR:[ERRNO] %u [MESSAGE] %s\n",
mysql_errno(mysql), mysql_error(mysql));
#endif
}
}
复制代码
[
本帖最后由 maya1982 于 2007-3-4 13:22 编辑
]
作者:
maya1982
时间:
2007-03-04 15:34
怎么没有人回答一些呢?
作者:
Neil
时间:
2007-03-04 17:32
我前段时间整理的一些文字,希望对你能有些帮助
http://bbs.nettf.net/forums/index.php?showtopic=60320
作者:
maya1982
时间:
2007-03-04 18:53
虽然没有我需要的,但是还是感谢你的关注,我大概是知道问题出在什么地方了。
我在代码中直接使用了MYSQL数据类型,但是在Zend中数据库连接是作为资源类型使用的对资源数据类型的变量要求作特殊的处理,我直接使用了声明的
MYSQL mysql;
连接数据库肯定就没有任何输出了,虽然编译没有任何错误。
作者:
Neil
时间:
2007-03-04 22:48
你可以把原来的数据库连接的代码编译成动态库,然后在php模块里面用函数指针调用
这个方法我试过,比把原来的动态库在php模块里面重新实现要简单许多
另外,如果你实在想重新实现的话,建议参看php的ext目录下的mysq目录下的l源码
作者:
maya1982
时间:
2007-03-05 11:06
还有,我能直接在C api层次上直接调用ext/mysql提供的api函数?
作者:
Neil
时间:
2007-03-05 21:00
那你不如直接调用mysql提供的 C API了
作者:
maya1982
时间:
2007-03-06 15:28
我研究了两天还是不能成功,望提供一些代码来研究一下。
在php模块中调用mysql api 总是没有输出。不知道问题出在什么地方。。
作者:
netkiller
时间:
2007-03-06 18:35
关注,我也想这么搞
作者:
Neil
时间:
2007-03-06 23:26
下面是我程序里的部分代码,是调用我自己的一个工程用DLL的,懒得在php的模块里面重写了(要考虑一堆的内存分配、多线程等,不想折腾了),用函数指针调用的
.h 文件中:
//long __stdcall nsms_ctrl_SendMsg( const char * ump, const char * msg )
typedef long (__stdcall * pFunSendMsg)( const char *, const char * );
pFunSendMsg funSendMsg;
复制代码
.c 文件中:
/* {{{ proto long nsms_ext_init( void )
Return long to test that the module is init done. */
PHP_FUNCTION(nsms_ext_init)
{
long lngRet = 1;
hNsmsCtrl = LoadLibrary( "nsms_ctrl.dll" );
if( hNsmsCtrl ) {
funSendMsg = (pFunSendMsg)GetProcAddress( hNsmsCtrl, "nsms_ctrl_SendMsg" );
if( funSendMsg ) {
lngRet = 0;
} else {
lngRet = 3;
}
} else {
lngRet = 2;
}
RETURN_LONG( lngRet );
}
/* }}} */
/* {{{ proto long nsms_ext_release( void )
Return long to test that the module is init done. */
PHP_FUNCTION(nsms_ext_release)
{
long lngRet = 4;
if( hNsmsCtrl ) {
lngRet = ( FreeLibrary( hNsmsCtrl ) > 0 ) ? 0 : 4;
hNsmsCtrl = NULL;
} else {
lngRet = 0;
}
RETURN_LONG( lngRet );
}
/* }}} */
/* {{{ proto long nsms_ext_send(string mp, string msg)
*/
PHP_FUNCTION(nsms_ext_send)
{
char *mp = NULL;
char *msg = NULL;
int argc = ZEND_NUM_ARGS();
int mp_len;
int msg_len;
long lngPort = -1;
long lngRet = ERR_UNKNOWN;
if (zend_parse_parameters(argc TSRMLS_CC, "ss", &mp, &mp_len, &msg, &msg_len) == FAILURE)
RETURN_LONG( ERR_PARAMETERS );
//char * szTmp = estrdup( NSMS_EXT_G(com_port) );
if( ! stricmp( NSMS_EXT_G(com_port), "COM1" ) ) {
lngPort = 0;
} else if( ! stricmp( NSMS_EXT_G(com_port), "COM2" ) ) {
lngPort = 1;
} else if( ! stricmp( NSMS_EXT_G(com_port), "COM3" ) ) {
lngPort = 2;
} else if( ! stricmp( NSMS_EXT_G(com_port), "COM4" ) ) {
lngPort = 3;
} else {
RETURN_LONG( ERR_COM_PORT );
}
if( funSendMsg ) {
lngRet = funSendMsg( mp, msg );
} else {
lngRet = ERR_BASE;
}
RETURN_LONG( lngRet );
}
/* }}} */
复制代码
其中函数 nsms_ctrl_SendMsg 就是在DLL里面exports出来的__stdcall函数
原型就是在头文件里面注释的那个
//long __stdcall nsms_ctrl_SendMsg( const char * ump, const char * msg )
希望对你能有帮助
Good Luck
作者:
maya1982
时间:
2007-03-07 13:28
这里是我这几天来研究PHP扩展的一些体会,和解决掉的错误
PHP_FUNCTION(passport_register){
// 和之前的代码比较,我没有为*connection分配内存,显然,内存是由Zend进行管理的。必须用Zend的内存管理函数来分配和回收内存资源。
MYSQL *connection = (MYSQL*)emalloc(sizeof(MYSQL));
MYSQL_RES *resultset = (MYSQL_RES*)emalloc(sizeof(MYSQL_RES));
// MYSQL_ROW row = (MYSQL_ROW)emalloc(sizeof(MYSQL_ROW));
// MYSQL_FIELD *fields = (MYSQL_FIELD*)emalloc(sizeof(MYSQL_FIELD));
unsigned int numrows, numcols, i;
mysql_init(connection);
if(connection == NULL){
RETURN_FALSE;
}
if (mysql_real_connect(connection,"localhost","develop","********","passport",3306,NULL,0) == NULL){
RETURN_FALSE;
}
zval *rconn;
MAKE_STD_ZVAL(rconn);
// 要注册资源类型。之前却没有注册。
ZEND_REGISTER_RESOURCE(rconn, connection, le_sample_connection);
array_init(return_value);
add_index_zval(return_value, 0, rconn);
char query[] = "SELECT username,usertypeid,email,status,ipaddr_registered FROM passport";
// 要在此使用资源数据类型,要从Zend内部的HashTable 中取回资源。
ZEND_FETCH_RESOURCE(connection, MYSQL*, &rconn, -1, "mysql connection", le_sample_connection);
if (mysql_query(connection, query) != 0)
{
RETURN_FALSE;
}
resultset = mysql_use_result(connection);
if (resultset == NULL){
RETURN_FALSE;
}
zval *rresult;
MAKE_STD_ZVAL(rresult);
ZEND_REGISTER_RESOURCE(rresult, resultset, le_sample_result);
add_index_zval(return_value, 2, rresult);
}
复制代码
php 测试代码:
$passport = passport_register();
var_dump($passport);
复制代码
输出结果:
array(2) {
[0]=>
resource(3) of type (mysql connection)
[2]=>
resource(4) of type (mysql result)
}
复制代码
作者:
Neil
时间:
2007-03-07 13:44
Congratulations
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2