【问题标题】:Use a PHP file pointer resource in C extension在 C 扩展中使用 PHP 文件指针资源
【发布时间】:2015-06-10 19:06:26
【问题描述】:

我开始为 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 "@9\321\002\001", 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 "@9\321\002\001") 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

【问题讨论】:

  • 我的赌注是stream-&gt;stdiocastFILE*),但我还没试过。你能试试看它是否有效吗?
  • 至少它现在可以编译,但如果我调用my_ext_function($fp),我现在会得到一个Internal Server Error。我可以在某处看到扩展的运行时错误吗?
  • 我会检查 PHP 和 Web 服务器的错误日志。此外,如果您使用的是 Mac/Linux 并且gdb 可用,请尝试sudo gdb -ex run --args php -a,然后输入$fp = fopen('file.txt', 'w'); my_ext_function($fp); 并按回车键。如果它崩溃了,您应该会收到一条错误消息,并且您可以使用bt 获取到崩溃位置的堆栈跟踪(并不意味着那里的代码对崩溃负责)。
  • 我安装了gdb,但是当我在php &gt; 之后输入代码时没有任何反应。我什至可以输入无效的 PHP 代码,例如 xyz;,但什么也没有发生。如果我按 Enter 键,则只是另一个 php &gt;
  • 如果你真的在最后放了一个分号并且它的行为是这样的,那么这听起来很糟糕 o.0

标签: php c php-extension


【解决方案1】:

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_stream_from_zval(stream, &amp;res);,因为现在它告诉我:我不能隐式声明PHP_STREAM_TO_ZVAL
  • @TiMESPLiNTER 没问题!不过,我不确定这会如何影响流;但是,如果您不从扩展名之外的文件中读取,应该没问题:)
  • @TiMESPLiNTER 是的,我没有检查该宏的声明位置:) 更新了我的答案。
  • 完美。只是因为我对……你在哪里找到解决方案感兴趣?您在 PHP 扩展开发方面的技能是否很强,或者您是否在互联网的某个地方找到了我的问题的解决方案?
  • @TiMESPLiNTER 两者兼而有之;我是一名核心开发人员,我使用互联网的this part 来查找与此类问题有关的答案:)
猜你喜欢
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
  • 2021-11-06
  • 2020-03-24
  • 2010-12-13
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多