19

So I decided to write an extension for php. Everything seems to be fine except I'm stuck on a tiny problem.

I have php-5.4.9 source codes. There is file ext/standard/mail.c with awesome function

PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC)

In my extension, in acme.c I have includes

...
#include "php.h"
#include "ext/standard/php_mail.h"
#include "php_ini.h"
...

So php_mail feels good and works fine. But, obviously, I want to use the code from mail.c starting on line 101 and ending on 189 (http://pastie.org/5444192 5-93 corresponding lines in the paste). So I caught myself on idea (it is awkward in some point though) why not to call PHP_FUNCTION(mail)? By the moment I could not locate that macros, and actually I'd like to know the best way to implement the idea.

My inner zend engineer (which is newbie) recommends me to use call_user_function

ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);

But I can not figure it out how to call it.

The question! How (an example with mail function is very welcomed) to call functions defined by PHP_FUNCTION?

nkamm
  • 627
  • 5
  • 14
  • Can you explain elaborate on the use case for calling `php_mail()` from your extension? It sounds like your extension is trying to do too much, and that either more of it should be written in PHP or you should be compiling this to a standalone binary. Remember, PHP extensions should be generic and re-usable, not tied to a specific application. Can you explain a little more about what this extension does? – DaveRandom Nov 27 '12 at 22:06

1 Answers1

20

The easiest way to figure out how a function works is to search for it on lxr.php.net. The first example that turns up is in readline: http://lxr.php.net/xref/PHP_TRUNK/ext/readline/readline.c#474

The use for mail is analogous. Given the arguments as zvals (to_zval, from_zval, msg_zval) the call is very simple:

zval *params = { to_zval, from_zval, msg_zval };
zend_uint param_count = 3;
zval *retval_ptr;

zval function_name;
INIT_ZVAL(function_name);
ZVAL_STRING(&function_name, "mail", 1);

if (call_user_function(
        CG(function_table), NULL /* no object */, &function_name,
        retval_ptr, param_count, params TSRMLS_CC
    ) == SUCCESS
) {
    /* do something with retval_ptr here if you like */
}

/* don't forget to free the zvals */
zval_ptr_dtor(&retval_ptr);
zval_dtor(&function_name);

If you don't have the parameters as zvals already, then you can create them using MAKE_STD_ZVAL and ZVAL_STRING.

NikiC
  • 100,734
  • 37
  • 191
  • 225