How to Make Your First PHP Extension in C on Linux

Mike McKee
If you are a PHP web developer, you may find that you wish to improve the performance of your websites once they grow big. Now you've probably heard of performance tips like xdebug, yslow, web farms, and so on, but one option still available to you is to take certain code bottlenecks and rewrite them in the C programming language, and then call them from within PHP as functions. Of course, this isn't suitable if you haven't exhausted other low cost options, but just might be the ticket to getting the performance boost you need. Also, if you don't know the C language, you can take these steps and give them to an outsource partner who can build the functions you need and then call them within your project. The steps here will show you how to make a PHP extension on the Linux operating system platform. In particular I have chosen the Ubuntu Linux platform, which is Debian-based, but using your own Linux platform support forums I'm sure you can convert these instructions for your own particular platform, such as switching from using the 'apt' tools on Linux to using 'yum' if your platform uses that.

The Hello World Example Steps

1. Open a command prompt and run this:

$ sudo apt-get install gcc php-pear php5-dev

2. Now make a folder somewhere and copy this into it. The /* FILE */ is the filename you should make.

/* config.m4 */
PHP_ARG_ENABLE(hello, whether to enable Hello World support,
[ --enable-hello Enable Hello World support])
if test "$PHP_HELLO" = "yes"; then
AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi

/* php_hello.h */
#ifndef PHP_HELLO_H
#define PHP_HELLO_H 1
#define PHP_HELLO_WORLD_VERSION "1.0"
#define PHP_HELLO_WORLD_EXTNAME "hello"
PHP_FUNCTION(hello_world);
extern zend_module_entry hello_module_entry;
#define phpext_hello_ptr &hello_module_entry
#endif

/* hello.c */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_hello.h"
static function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
{NULL, NULL, NULL}
};
zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_HELLO_WORLD_EXTNAME,
hello_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_HELLO_WORLD_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif

PHP_FUNCTION(hello_world) {
zval *zvar;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zvar) == FAILURE) {
RETURN_NULL();
}

convert_to_string(zvar);

char output[255] = "Hello ";
strcat(output, Z_STRVAL_P(zvar));

RETURN_STRING(output,1);
}

3. Now run these commands in the same directory as where you put those files:

$ phpize
$ ./configure --enable-hello
$ make
$ cd modules
$ ls *.so

4. Now find out where your other PHP .so files are on your computer. This might take a forum support query. In my case I found mine here:

/usr/lib/php5/20060613+lfs/

5. Copy the hello.so file from step # 3 to the path in step # 4. As in:

$ sudo cp -i hello.so /usr/lib/php5/20060613+lfs

6. Now tell your php.ini file(s) to load this new extension you made. Note that if you have Apache AND a command line (cli) version of PHP5 (I do), then you'll need to edit both php.ini files. In my case, I had to edit these two files:

/etc/php5/apache2/php.ini
/etc/php5/cli/php.ini

Find the section regarding Dynamic Extensions and tack this on:

extension=hello.so

7. Now bounce your Apache web server or whatever web server you are running. In my case I had to do:

$ sudo /etc/init.d/apache2 stop
# wait 3 seconds
$ sudo /etc/init.d/apache2 start

8. Finally, you can either compose a PHP file and test it, or we can test this at command line like so:

$ php -r '$s = hello_world("my friend");echo "test--" . $s . "--test";

test--Hello my friend--test

Note that it automatically applied trim() on the result for you, which is why I included the test phrases so that you could see this.

Next Steps

From this example, you should be able to get a small, simple book on C, plus this resource, and then apply small changes to copies of these files and get new results, such as trying:

  • pass multiple strings as input variables
  • pass other kinds of PHP data types as input variables
  • output other kinds of PHP data types
  • pass in PHP arrays and output arrays back
  • pass in a PHP object variable (such as an object of array) and then output an object variable back
  • have more than one function

Resources

Extension Writing Part I: Introduction to PHP and Zend
http://devzone.zend.com/node/view/id/1021

Extension Writing Part II: Parameters, Arrays, and ZVAL
http://devzone.zend.com/node/view/id/1022

Extension Writing Part III: Resources
http://devzone.zend.com/node/view/id/1024

Published by Mike McKee

Mike McKee is owner of Volo, LLC (http://volomike.com/). He is a freelance PHP developer living in Myrtle Beach, USA.  View profile

To comment, please sign in to your Yahoo! account, or sign up for a new account.