Extension을 제작하다보면 PHP에 이미 정의되어 있는 함수를 이용해야 할 때가 있다.
방법은 2가지다.
하나는 PHP 소스 내에서 관련 함수들을 조합해서 호출하는 방법이고,
나머지 하나는 PHP의 정의된 함수가 모여있는 EG(function_table)을 이용하는 방법이다.
다음은 2가지 방법을 이용해 md5() 함수를 호출하는 예제이다.
(functions.h, functions.c 파일을 추가했다.)
config.m4
PHP_ARG_ENABLE(myext, whether to enable myext support,
[ --enable-myext enable myext support])
if test "$PHP_TEST" = "yes"; then
AC_DEFINE(HAVE_MYEXT, 1, [whether you have myext])
PHP_NEW_EXTENSION(myext, myext.c functions.c, $ext_shared)
fi
[ --enable-myext enable myext support])
if test "$PHP_TEST" = "yes"; then
AC_DEFINE(HAVE_MYEXT, 1, [whether you have myext])
PHP_NEW_EXTENSION(myext, myext.c functions.c, $ext_shared)
fi
php_myext.h
#ifndef PHP_MYEXT_H
#define PHP_MYEXT_H
#define PHP_MYEXT_VERSION "1.0" // 버전
#define PHP_MYEXT_EXTNAME "myext" // 이름
// Thread Safe Resource Manager
#ifdef ZTS
#include "TSRM.h"
#endif
// MD5
PHP_FUNCTION(myext_md5_1);
PHP_FUNCTION(myext_md5_2);
// 모듈엔트리
extern zend_module_entry myext_module_entry;
#define phpext_myext_ptr &myext_module_entry
#endif
#define PHP_MYEXT_H
#define PHP_MYEXT_VERSION "1.0" // 버전
#define PHP_MYEXT_EXTNAME "myext" // 이름
// Thread Safe Resource Manager
#ifdef ZTS
#include "TSRM.h"
#endif
// MD5
PHP_FUNCTION(myext_md5_1);
PHP_FUNCTION(myext_md5_2);
// 모듈엔트리
extern zend_module_entry myext_module_entry;
#define phpext_myext_ptr &myext_module_entry
#endif
myext.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_myext.h"
#include "ext/standard/info.h"
#include "functions.h"
// function entry
static function_entry myext_functions[] = {
PHP_FE(myext_md5_1, NULL)
PHP_FE(myext_md5_2, NULL)
{NULL, NULL, NULL}
};
zend_module_entry myext_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_MYEXT_EXTNAME,
myext_functions, // function_entry
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_MYEXT_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_MYEXT
ZEND_GET_MODULE(myext)
#endif
// MD5
PHP_FUNCTION(myext_md5_1)
{
char *p1;
int p1_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p1, &p1_len)==FAILURE) {
RETURN_NULL();
}
RETURN_STRING(md5_1(p1), 1);
}
PHP_FUNCTION(myext_md5_2)
{
char *p1;
int p1_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p1, &p1_len)==FAILURE) {
RETURN_NULL();
}
RETURN_STRING(md5_2(p1), 1);
}
#include "config.h"
#endif
#include "php.h"
#include "php_myext.h"
#include "ext/standard/info.h"
#include "functions.h"
// function entry
static function_entry myext_functions[] = {
PHP_FE(myext_md5_1, NULL)
PHP_FE(myext_md5_2, NULL)
{NULL, NULL, NULL}
};
zend_module_entry myext_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_MYEXT_EXTNAME,
myext_functions, // function_entry
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_MYEXT_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_MYEXT
ZEND_GET_MODULE(myext)
#endif
// MD5
PHP_FUNCTION(myext_md5_1)
{
char *p1;
int p1_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p1, &p1_len)==FAILURE) {
RETURN_NULL();
}
RETURN_STRING(md5_1(p1), 1);
}
PHP_FUNCTION(myext_md5_2)
{
char *p1;
int p1_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p1, &p1_len)==FAILURE) {
RETURN_NULL();
}
RETURN_STRING(md5_2(p1), 1);
}
functions.h
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include "php.h"
char *_md5_1(char *msg, zend_bool raw_output TSRMLS_DC);
char *_md5_2(char *msg, zend_bool raw_output TSRMLS_DC);
#define md5_1(msg) _md5_1(msg, 0 TSRMLS_CC)
#define md5_2(msg) _md5_2(msg, 0 TSRMLS_CC)
#endif
#define FUNCTIONS_H
#include "php.h"
char *_md5_1(char *msg, zend_bool raw_output TSRMLS_DC);
char *_md5_2(char *msg, zend_bool raw_output TSRMLS_DC);
#define md5_1(msg) _md5_1(msg, 0 TSRMLS_CC)
#define md5_2(msg) _md5_2(msg, 0 TSRMLS_CC)
#endif
functions.c
#include "functions.h"
#include "ext/standard/md5.h"
char *_md5_1(char *msg, zend_bool raw_output TSRMLS_DC)
{
unsigned char digest[16];
char md5str[33];
PHP_MD5_CTX context;
PHP_MD5Init(&context);
PHP_MD5Update(&context, (unsigned char*)msg, strlen(msg));
PHP_MD5Final(digest, &context);
if (raw_output) {
return (char*)digest;
}
else {
md5str[0] = '\0';
make_digest_ex(md5str, digest, 16);
char *result = NULL;
spprintf(&result, 0, "%s", md5str);
return result;
}
}
char *_md5_2(char *msg, zend_bool raw_output TSRMLS_DC)
{
zval *funcname, *p1, *p2, *args[2], *ret;
MAKE_STD_ZVAL(funcname);
ZVAL_STRING(funcname, "md5", 1);
// 각 파라메터 세팅
MAKE_STD_ZVAL(p1);
MAKE_STD_ZVAL(p2);
ZVAL_STRING(p1, msg, 1);
ZVAL_BOOL(p2, 0);
// 각 파라메터를 args 배열에 대입
args[0] = p1;
args[1] = p2;
// 리턴값 초기화
MAKE_STD_ZVAL(ret);
// 함수 호출
call_user_function(EG(function_table), NULL, funcname, ret, 2, args TSRMLS_CC);
zval_dtor(funcname);
zval_dtor(p1);
zval_dtor(p2);
return Z_STRVAL_P(ret);
}
#include "ext/standard/md5.h"
char *_md5_1(char *msg, zend_bool raw_output TSRMLS_DC)
{
unsigned char digest[16];
char md5str[33];
PHP_MD5_CTX context;
PHP_MD5Init(&context);
PHP_MD5Update(&context, (unsigned char*)msg, strlen(msg));
PHP_MD5Final(digest, &context);
if (raw_output) {
return (char*)digest;
}
else {
md5str[0] = '\0';
make_digest_ex(md5str, digest, 16);
char *result = NULL;
spprintf(&result, 0, "%s", md5str);
return result;
}
}
char *_md5_2(char *msg, zend_bool raw_output TSRMLS_DC)
{
zval *funcname, *p1, *p2, *args[2], *ret;
MAKE_STD_ZVAL(funcname);
ZVAL_STRING(funcname, "md5", 1);
// 각 파라메터 세팅
MAKE_STD_ZVAL(p1);
MAKE_STD_ZVAL(p2);
ZVAL_STRING(p1, msg, 1);
ZVAL_BOOL(p2, 0);
// 각 파라메터를 args 배열에 대입
args[0] = p1;
args[1] = p2;
// 리턴값 초기화
MAKE_STD_ZVAL(ret);
// 함수 호출
call_user_function(EG(function_table), NULL, funcname, ret, 2, args TSRMLS_CC);
zval_dtor(funcname);
zval_dtor(p1);
zval_dtor(p2);
return Z_STRVAL_P(ret);
}
test.php
var_dump(md5('abcd'));
var_dump(myext_md5_1('abcd'));
var_dump(myext_md5_2('abcd'));
var_dump(myext_md5_1('abcd'));
var_dump(myext_md5_2('abcd'));
위처럼 호출하면 아래와 같이 동일한 결과물이 나올 것이다.
string 'e2fc714c4727ee9395f324cd2e7f331f' (length=32)
string 'e2fc714c4727ee9395f324cd2e7f331f' (length=32)
string 'e2fc714c4727ee9395f324cd2e7f331f' (length=32)
_md5_1() 함수는 ext/standard/md5.h 에 정의되어 있는 C 소스를 그대로 이용하는 방법이고,
_md5_2() 함수는 EG(function_table)에 정의되어 있는 md5()를 호출하는 방법이다.
사용하고자 하는 built-in 함수들이 각자 지 맘대로의 형태를 가지고 있으므로 적절하게 사용하자.
_md5_2() 의 경우 call_user_function()을 이용해서 함수를 호출하여 결과값을 zval *ret 에 담는 것이 포인트이다.
call_user_function()
정의는 다음과 같다.
int
call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC)
파라메터 설명
파라메터 | 설명 |
HashTable *function_table | 함수들이 들어있는 HashTable |
zval **object_pp | 함수가 정의된 scope. 만약 클래스의 멤버함수를 호출할 경우 이 자리를 NULL로 할 수 없다. |
zval *function_name | 호출할 함수의 이름 |
zval *reval_ptr | 함수의 리턴값이 저장될 zval* |
zend_uint param_count | 함수호출시 넘길 파라메터의 수 |
zval *params[] | 파라메터를 담고 있는 zval* 의 배열 |
TSRMLS_DC | Thread Safety를 위한 변수 매크로 |
'PHP' 카테고리의 다른 글
[PHP] PHP Core - PHP interpreter (0) | 2010.09.14 |
---|---|
[PHP] mod_php5 (SAPI for Apache) (0) | 2010.09.14 |
[PHP Extension] Super Globals (0) | 2010.09.13 |
[PHP Extension] C++로 제작하기 위한 config.m4 (0) | 2010.09.09 |
[PHP Extension] 클래스 (Class) (0) | 2010.08.06 |