This guide is for the programmer who needs to write a quick and dirty PHP extension. A PHP extension is a module for PHP written in C. You may wish to write such a module to expose library functionality only available in C, or to optimize certain key sections in your execution path.
As I have done before, I will attempt to make a terse summary. I assume you have or confidently can acquire knowledge of PHP and C. I’m a big fan of simple cookbook ‘recipe’ like guides, so here we go. Hold on to your hat.
Step 1: Compile PHP With Debugging Enabled
When developing your own module, you’ll want to enable debugging in PHP. This will generate error messages which may contain additional information beyond an unhelpful ‘segmentation fault’ when your module crashes.
In FreeBSD, just go into your ports, and do make config
. Turn on the ‘debugging’ option and recompile PHP and its modules. Other platforms are similar; if you’re compiling from source by hand, take a look at the output of ./configure --help
and you’ll find the right option for your version.
Before you start working on your module, make sure everything is in order with your server and that your extensions.ini
file looks good. In my experience, rebuilding PHP under FreeBSD sometimes causes modules to appear twice in the extensions.ini
file, and you may wish to be wary of this.
Step 2: Set up a project skeleton
PHP comes with great support for developing your module. There are a couple of scripts and configure related tools that automate almost all the work for you.
First, create a config.m4
file in your new project. (There’s even a tool that does this for you – ext_skel
– but we’ll do it by hand for the purposes of this guide.) Here’s a bare bones config.m4
file for an extension named “pwwext”:
dnl config.m4 for extension pww PHP_ARG_ENABLE(pwwext, whether to enable pww support, [ --enable-pwwext Enable pww support]) if test "$PHP_PWWEXT" != "no"; then PHP_NEW_EXTENSION(pwwext, pwwext.c, $ext_shared) fi
You’ll also need some source code. Lets begin with the header file, which we’ll call pwwext.h
. Lets write a minimal header:
#ifndef PHP_PWWEXT_H #define PHP_PWWEXT_H #define PHP_PWWEXT_EXTNAME "pwwext" #define PHP_PWWEXT_EXTVER "0.1" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" extern zend_module_entry pwwext_module_entry; #define phpext_pwwext_ptr &pwwext_module_entry #endif /* PHP_PWWEXT_H */
In my experience, it’s often a waste of time to learn things before you need them. This is a good example of that: the header code does pretty much what it appears to do, and more in depth knowledge is not strictly needed. In short it exposes the entry point of the module and brings in the most important header files.
Step 3: The Actual Source
Finally, we’ll need the file we referred to in config.m4
previously. It’s the main source file, pwwext.c
:
/* * This extension enables cool pww functionality. */ #include "pwwext.h" PHP_FUNCTION(pwwext_calculate) { long a, b; /* Get some params. */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FAILURE) { RETURN_NULL(); } if (a < = 0) { zend_throw_exception(zend_exception_get_default(), "First argument can't be negative nor zero.", 0 TSRMLS_CC); RETURN_NULL(); } /* PHP preallocates space for return values, so its important to use these return macros. */ RETVAL_LONG(a+b); return; } static function_entry php_pwwext_functions[] = { PHP_FE(pwwext_calculate, NULL) { NULL, NULL, NULL } }; zend_module_entry pwwext_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_PWWEXT_EXTNAME, php_pwwext_functions, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ #if ZEND_MODULE_API_NO >= 20010901 PHP_PWWEXT_EXTVER, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PWWEXT ZEND_GET_MODULE(pwwext) #endif
There are a couple of important structures here. The variable php_pwwext_functions
lists all the functions we wish to expose from the module. In our example, we’re only exporting a single function.
Then we have the pwwext_module_entry
structure which truly is the entry point into your module. If you would look near the sixth line in the structure you’d see a pointer to our list of functions, for instance.
Step 4: Compiling and Running
Finally, we’ll want to build the actual module. The command phpize
will get everything in order for a compilation based on your configuration. After phpize is done, the normal configure make dance is all we need. Make note of the ‘--enable-pwwext
‘ argument to configure.
[~/pwwext]$ phpize
./configure --enable-pwwext
make
That’s all there is to it. Your module should now be built and almost ready to go. To wrap up, you’ll need to install the module in your PHP extensions folder. If you don’t know it already, run php -i
to find the right folder. For me, the result is,
$ php -i|grep extension_dir extension_dir => /usr/local/lib/php/20060613-debug => /usr/local/lib/php/20060613-debug
so I’ll go ahead and copy the module into /usr/local/lib/php/20060613-debug:
# cp modules/pwwext.so /usr/local/lib/php/20060613-debug/
There’s one last step we’ll have to do. We need to add the module to the list of extensions in your php.ini
or extensions.ini
file. Locate the section with multiple lines beginning with extension=...
and add your own line. For me, this line would do it:
extension=pwwext.so
Step 5: Does it work?
Finally, we can test our new module. Run,
$ php -m
and make sure your new module is in the list.
If all is well you should be able to use your new function from any PHP script. For me, this was the final result:
$php -r'echo pwwext_calculate(1, 2);' 3 $ php -r'echo pwwext_calculate(-1, 2);' Fatal error: Uncaught exception 'Exception' with message 'First argument can't be negative.' in Command line code:1 Stack trace: #0 Command line code(1): pwwext_calculate(-1, 2) #1 {main} thrown in Command line code on line 1
Now you have a bare bones module that does something. All that remains now is to change that one function to do something useful and you’re well on your way.
You’ll undoubtedly need more reference material going forward. Php.net is the logical starting point: The Zend API. If that’s not enough, Sara Golemon wrote a whole book about the subject: ‘Extending and Embedding PHP’.
Good luck, and don’t forget to turn off PHP debugging when you’re done.
Author: Alexander Ljungberg Tags: guide, open source, PHP