PHP拡張モジュールの動作原理
OSS推進センター 海外浩平 <kaigai@ak.jp.nec.com>
PECL (PHP Extension Community Library)
PHPからSELinuxを
呼び出すための
インターフェース群
PHPからSELinuxを
呼び出すための
インターフェース群
PHPスクリプトの実行
/usr/bin/php -q
<?
:
:
my_function();
:
:
?>
スクリプト
/usr/bin/php
インタープリタ my_module.so
my_function()
pgsql.so
pq_query()
拡張モジュール
拡張モジュール
Zend APIZend API
ビルトイン
関数
zend_module_entry 構造体 (1/2)
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
:
const char *name;
const struct _zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
int (*request_startup_func)(INIT_FUNC_ARGS);
int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
const char *version;
:
};
zend_module_entry 構造体 (2/2)
/* SELinux module entry */
zend_module_entry selinux_module_entry = {
STANDARD_MODULE_HEADER,
"selinux",
selinux_functions,
NULL, /* module_startup_func */
NULL, /* module_shutdown_func */
NULL, /* request_startup_func */
NULL, /* request_shutdown_func */
NULL, /* info_func */
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES,
};
#ifdef COMPILE_DL_SELINUX
ZEND_GET_MODULE(selinux)
#endif
zend_module_entry *
get_module(void) {
return &name##_module_entry;
}
zend_module_entry *
get_module(void) {
return &name##_module_entry;
}
zend_function_entry構造体 (1/2)
#define INTERNAL_FUNCTION_PARAMETERS ¥
int ht, zval *return_value, zval **return_value_ptr, ¥
zval *this_ptr, int return_value_used TSRMLS_DC
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_arg_info *arg_info;
zend_uint num_args;
zend_uint flags;
} zend_function_entry;
zval構造体
zend_function_entry構造体 (2/2)
ZEND_BEGIN_ARG_INFO(arginfo_selinux_setenforce, 0)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
:
zend_function_entry selinux_functions[] = {
/* global state API */
PHP_FE(selinux_is_enabled, arginfo_selinux_is_enabled)
PHP_FE(selinux_getenforce, arginfo_selinux_getenforce)
PHP_FE(selinux_setenforce, arginfo_selinux_setenforce)
:
};
:
PHP_FUNCTION(selinux_setenforce)
{
:
}
PHP関数はどう定義されるか?
PHP_FUNCTION(selinux_setenforce)
{
long mode;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"l", &mode) == FAILURE)
return;
if (!security_setenforce(mode))
RETURN_TRUE;
RETURN_FALSE;
}
void zif_selinux_setenforce(INTERNAL_FUNCTION_PARAMETERS)
{ return_value->type = IS_BOOL;
return_value->value.lval = false;
return; }
int ht, zval *return_value, zval **return_value_ptr, ¥
zval *this_ptr, int return_value_used TSRMLS_DC
引数の受け渡し (1/2)
zend_parse_parameters() 関数
可変長引数を持ち、変換仕様に応じて、スタックに積まれた
PHP関数の引数を解釈する
変換仕様の一例
s … 文字列 (string)
l … 整数値 (long)
b … 論理値 (bool)
d … 浮動小数点型 (double)
z … zval
| … 次のパラメータは省略可能 (optional)
ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC,
char *type_spec, ...)
【使用例】
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sb",
&name, &length, &new_value);
引数の受け渡し (2/2)
Thread Safe Resource Manager
#ifdef ZTS
#define TSRMLS_DC , void ***tsrm_ls
#define TSRMLS_CC , tsrm_ls
#else
#define TSRMLS_DC
#define TSRMLS_CC
#endif
Thread-1: zend_executor_globals->argument_stack
Thread-N: zend_executor_globals->argument_stack
:
マルチスレッドが有効なビルドでは、
PHP関数にTSRMへのポインタが渡される
マルチスレッドが有効なビルドでは、
PHP関数にTSRMへのポインタが渡される
zval *の配列を内包
配列を返す関数
方針
return_value に配列 (IS_ARRAY) をセットしてリターン
配列オブジェクトを作る方法
array_init(zval *zval, uint size); で初期化
add_assoc_xxx(zval *zval, const char *key, xxx value);
add_index_xxx(zval *zval, ulong idx, xxx value);
で、配列要素を追加 (xxxの部分はデータ型)
配列として構築された zval を配列の要素としてセットする
ことで、多次元配列を表現する事ができる。
array_init(return_value);
for (i=0; contexts[i]; i++)
{
add_index_string(return_value, i, contexts[i], 1);
}
参考資料
PHP Manual - A Hacker's Guide to the Zend Engine
http://usphp.com/manual/en/internals2.php
PHP Extension Development
http://www.somabo.de/talks/200510_zend_conf_php_e
xtension_development.pdf

OSS開発勉強会-03