PHP Extension API Dependancy Interface – Tutorial 2

I previously discussed how to use extension api for PHP here. To illustrate the use of it, I will discuss how it can be implemented on exif and mbstring extensions. (Exif depends on mbstring and uses functions php_mb_check_encoding_list and php_mb_convert_encoding)

As also mentioned in the previous blog post, you can find the details about the status of the project here. The source code is available at the git repository : git://github.com/vpj/PHP-Extension-API.git, and some sample test code which uses the interface : git://github.com/vpj/PHP_EXT_API_Tests.git

How to register APIs – mbstring

You should create a structure with the API functions.

1
2
3
4
static struct {
	int (*check_encoding_list)(const char * TSRMLS_DC);
	char * (*convert_encoding)(const char *, size_t, const char *, const char *, size_t * TSRMLS_DC);
} mbstring_eapi = {php_mb_check_encoding_list, php_mb_convert_encoding};

I used a global variable for this.

Then, you should register the API during module initialization. That is, following piece of code should be included in MINIT.

1
zend_eapi_register("mbstring", "1.0", (void *)&mbstring_eapi, sizeof(mbstring_eapi));

Registering the API is pretty simple, but there might be some issues when using it in exif.

Setting up callback function – exif

First we should define the structure of the API.

1
2
3
4
5
6
typedef struct {
	int (*check_encoding_list)(const char * TSRMLS_DC);
	char * (*convert_encoding)(const char *, size_t, const char *, const char *, size_t * TSRMLS_DC);
} mbstring_eapi_struct;
 
static mbstring_eapi_struct *mbstring_eapi;

Here’s the callback function.

1
2
3
4
5
6
7
8
EAPI_CALLBACK_FUNCTION(mbstring_eapi_callback)
{
	TSRMLS_FETCH();
	mbstring_eapi = pemalloc(sizeof(mbstring_eapi_struct), 1);
 
	*mbstring_eapi = *((mbstring_eapi_struct*)api);
	REGISTER_INI_ENTRIES();
}

The callback function is named mbstring_eapi_callback. We are calling REGISTER_INI_ENTRIES from the callback, since OnUpdate event handlers for INI entries use check_encoding_list function. If INIs were registered from MINIT the event handlers will be executed before the extension api callback, so we are delaying the INI registration. Since REGISTER_INI_ENTRIES require TRSMLS we fetch those threading information using TSRMLS_FETCH() at the begining of the callback function.

The callback should be registered in MINIT.

1
2
EAPI_SET_CALLBACK("mbstring", "1.0", mbstring_eapi_callback);
mbstring_eapi = NULL;

We are left with changing the mbstring function calls. I’ll include the changed code in OnUpdateEncode; rest is similar.

1
2
3
4
5
6
7
8
9
10
11
ZEND_INI_MH(OnUpdateEncode)
{
	if(mbstring_eapi)
	{
		if (new_value && strlen(new_value) && !mbstring_eapi->check_encoding_list(new_value TSRMLS_CC)) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal encoding ignored: '%s'", new_value);
			return FAILURE;
		}
	}
	return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}

Tags: , , ,