在 C 扩展中使用 PHP 文件指针资源
Use a PHP file pointer resource in C extension
我开始为 PHP 开发自己的小扩展。但我现在正在为资源类型而苦苦挣扎。
基本上我喜欢使用文件指针作为参数传递给我自己的函数。因此,假设以下 PHP 代码是最终结果:
<?php
$fp = fopen('file.txt', 'w');
my_ext_function($fp);
现在我喜欢在我的扩展中使用 C 中的这个文件指针:
PHP_FUNCTION(my_ext_function)
{
zval *res;
php_stream *stream;
char ch;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res) == FAILURE) {
RETURN_FALSE;
}
PHP_STREAM_TO_ZVAL(stream, res); // Not sure about that
// Do some crazy stuff here like it would be a native file pointer from C
while( ( ch = fgetc(res) ) != EOF )
php_printf("%c", res);
RETURN_TRUE;
}
我的扩展功能是基于fread
function of PHP itself.
那么我该如何实现呢?基本上问题是:如何将 php_stream
指针转换为 FILE
指针?
回溯
#0 0x000000010081b330 in zend_parse_va_args (num_args=1, type_spec=0x7fff5fbfec88 "@91[=13=]2[=13=]1", va=0x7fff5fbfec10, flags=0, tsrm_ls=0x102cdef07) at Zend/zend_API.c:790
#1 0x000000010081bc67 in zend_parse_parameters (num_args=1, tsrm_ls=0x102cdef07, type_spec=0x7fff5fbfec88 "@91[=13=]2[=13=]1") at Zend/zend_API.c:924
#2 0x0000000102cdeb2a in zif_my_ext_function (ht=1, return_value=0x102cd2d38, return_value_ptr=0x102c9e168, this_ptr=0x0, return_value_used=0, tsrm_ls=0x102d13940) at hello.c:65
#3 0x00000001008cacd5 in zend_do_fcall_common_helper_SPEC (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:558
#4 0x0000000100882252 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:2595
#5 0x0000000100869f28 in execute_ex (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:363
#6 0x000000010086a060 in zend_execute (op_array=0x102cd39f0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:388
#7 0x00000001007fde27 in zend_eval_stringl (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", str_len=41, retval_ptr=0x0,
string_name=0x100dbd1d6 "Command line code", tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1077
#8 0x00000001007fe627 in zend_eval_stringl_ex (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", str_len=41, retval_ptr=0x0,
string_name=0x100dbd1d6 "Command line code", handle_exceptions=1, tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1124
#9 0x00000001007fe6ff in zend_eval_string_ex (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", retval_ptr=0x0, string_name=0x100dbd1d6 "Command line code",
handle_exceptions=1, tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1135
#10 0x00000001008f96ab in do_cli (argc=3, argv=0x102d13840, tsrm_ls=0x102d13940) at sapi/cli/php_cli.c:1034
#11 0x00000001008f8172 in main (argc=3, argv=0x102d13840) at sapi/cli/php_cli.c:1378
PHP_STREAM_TO_ZVAL
不能直接使用,因为它是在ext/standard/file.c
的实现中声明的;你需要改用这个:
php_stream_from_zval(stream, &res);
您可以使用 php_stream_cast()
:
将流投射到您需要的内容
{
FILE *f;
if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&f, REPORT_ERRORS)) {
RETURN_FALSE;
}
/* do what you want with f */
}
我开始为 PHP 开发自己的小扩展。但我现在正在为资源类型而苦苦挣扎。
基本上我喜欢使用文件指针作为参数传递给我自己的函数。因此,假设以下 PHP 代码是最终结果:
<?php
$fp = fopen('file.txt', 'w');
my_ext_function($fp);
现在我喜欢在我的扩展中使用 C 中的这个文件指针:
PHP_FUNCTION(my_ext_function)
{
zval *res;
php_stream *stream;
char ch;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res) == FAILURE) {
RETURN_FALSE;
}
PHP_STREAM_TO_ZVAL(stream, res); // Not sure about that
// Do some crazy stuff here like it would be a native file pointer from C
while( ( ch = fgetc(res) ) != EOF )
php_printf("%c", res);
RETURN_TRUE;
}
我的扩展功能是基于fread
function of PHP itself.
那么我该如何实现呢?基本上问题是:如何将 php_stream
指针转换为 FILE
指针?
回溯
#0 0x000000010081b330 in zend_parse_va_args (num_args=1, type_spec=0x7fff5fbfec88 "@91[=13=]2[=13=]1", va=0x7fff5fbfec10, flags=0, tsrm_ls=0x102cdef07) at Zend/zend_API.c:790
#1 0x000000010081bc67 in zend_parse_parameters (num_args=1, tsrm_ls=0x102cdef07, type_spec=0x7fff5fbfec88 "@91[=13=]2[=13=]1") at Zend/zend_API.c:924
#2 0x0000000102cdeb2a in zif_my_ext_function (ht=1, return_value=0x102cd2d38, return_value_ptr=0x102c9e168, this_ptr=0x0, return_value_used=0, tsrm_ls=0x102d13940) at hello.c:65
#3 0x00000001008cacd5 in zend_do_fcall_common_helper_SPEC (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:558
#4 0x0000000100882252 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:2595
#5 0x0000000100869f28 in execute_ex (execute_data=0x102c9e1c0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:363
#6 0x000000010086a060 in zend_execute (op_array=0x102cd39f0, tsrm_ls=0x102d13940) at Zend/zend_vm_execute.h:388
#7 0x00000001007fde27 in zend_eval_stringl (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", str_len=41, retval_ptr=0x0,
string_name=0x100dbd1d6 "Command line code", tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1077
#8 0x00000001007fe627 in zend_eval_stringl_ex (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", str_len=41, retval_ptr=0x0,
string_name=0x100dbd1d6 "Command line code", handle_exceptions=1, tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1124
#9 0x00000001007fe6ff in zend_eval_string_ex (str=0x102d138a0 "$fp = fopen(\"test.txt\", \"r\"); my_ext_function($fp);", retval_ptr=0x0, string_name=0x100dbd1d6 "Command line code",
handle_exceptions=1, tsrm_ls=0x102d13940) at Zend/zend_execute_API.c:1135
#10 0x00000001008f96ab in do_cli (argc=3, argv=0x102d13840, tsrm_ls=0x102d13940) at sapi/cli/php_cli.c:1034
#11 0x00000001008f8172 in main (argc=3, argv=0x102d13840) at sapi/cli/php_cli.c:1378
PHP_STREAM_TO_ZVAL
不能直接使用,因为它是在ext/standard/file.c
的实现中声明的;你需要改用这个:
php_stream_from_zval(stream, &res);
您可以使用 php_stream_cast()
:
{
FILE *f;
if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&f, REPORT_ERRORS)) {
RETURN_FALSE;
}
/* do what you want with f */
}