Writing a simple PHP extension
This is somewhat dated now - I doubt the same instructions apply to PHP 4 - so you'd probably do better to look elsewhere now. It's been useful to a few people in the past, though.
I wanted to add a C function to PHP 3, and couldn't find a simple, practical, introduction on how to do it.
Here, then, is a list of the step I took to add a command called 'foo' which simply returns the word 'foo'. You can build on it from there! I'm not sure if this is the 'right' way to do things, but it worked for me! I'm assuming you know how to configure your Apache to use PHP etc. See the PHP site if not.
I'm using RedHat 6.1 at the time of writing, which comes with Apache and precompiled PHP libraries. It doesn't, however, have the PHP development tree, so you need to download a copy of PHP and build it. Your system may not need all of the steps below.
First, on my RedHat, I needed to edit the Apache configuration script at /usr/sbin/apxs to set
my $CFG_LIBEXECDIR = '/usr/lib/apache';
as described in http://www.php.net/FAQ.php3#6.11-
Then I was ready to build PHP. I used:
./configure --with-mysql --with-apxs=/usr/sbin/apxs \ --with-xml --with-config-file-path=/etc/httpdThe config-file-path is simply for consistency because the standard RedHat installation of PHP expects to find the php3.ini configuration file in /etc/httpd. It gets confusing if you have more than one.I did a make and make install, which overwrites the old libphp3.so. All being well, you should now have a PHP which works with your Apache much like the old one did. But you also have a source tree you can point to when building your new module.
- I created a new directory with the following files:
foo.h #ifndef _FOO_H #define _FOO_H extern php3_module_entry foo_module_entry; #define foo_module_ptr &foo;_module_entry /* foo.c functions */ extern int php3_minit_foo(INIT_FUNC_ARGS); extern void php3_foo(INTERNAL_FUNCTION_PARAMETERS); extern void php3_info_foo(void); #else #define foo_module_ptr NULL #endif /* _FOO_H */
foo.c #if COMPILE_DL #include "dl/phpdl.h" #endif #include "php.h" #include "internal_functions.h" #include "foo.h" function_entry foo_functions[] = { {"foo", php3_foo, NULL}, {NULL, NULL, NULL} }; php3_module_entry foo_module_entry = { "Foo", foo_functions, php3_minit_foo, NULL, NULL, NULL, php3_info_foo, STANDARD_MODULE_PROPERTIES }; #if COMPILE_DL DLEXPORT php3_module_entry *get_module(void) { return &foo;_module_entry; } #endif int php3_minit_foo(INIT_FUNC_ARGS) { return SUCCESS; } /* php3_foo returns Foo */ void php3_foo(INTERNAL_FUNCTION_PARAMETERS) { char *outstring; outstring="Foo"; RETVAL_STRING(outstring,1); } void php3_info_foo() { PUTS("Compiled with FOO Support."); }Makefile PHPDIR=/home/qsf/php-3.0.16 PHPEXTDIR=/usr/lib/apache CC=gcc INCLUDES=-I$(PHPDIR) -I/usr/include/apache CFLAGS=$(INCLUDES) -DCOMPILE_DL LDFLAGS = -shared -fPIC -ldl SOURCES = foo.c OBJS = $(SOURCES:.c=.o) all:: foo.so foo.so: foo.o $(LD) $(LDFLAGS) -o foo.so foo.o install: cp foo.so $(PHPEXTDIR)
- You will need to change some of the paths in the Makefile, but you should then be able to make foo.so . The PHPEXTDIR is the extension directory defined in your php3.ini, or you can find it by inserting <? phpinfo() ?> in a PHP page. You need to install your foo.so into that directory if PHP is to find it.
- Finally, you need to tell PHP to load your extension. You can either do this by adding it to php3.ini :
extension=foo.so
or by dynamically loading it from within the PHP page, using the PHP command:dl("foo.so") -
If all has gone well, you should now be able to call print foo() within your PHP code, with the exciting result that the word "Foo" appears on the page.
If you specified the module as an extension in your php3.ini, then the phpinfo() command should also tell you (under 'Extensions') that your PHP is 'compiled with FOO support', which will make you the envy of your neighbours.
Comments and feedback welcome, but please don't ask me difficult questions - I'm really not an expert on this stuff, I just managed to make it work! This is basically the sum total of my experience, since the facilities I needed this for were provided when I switched to PHP 4 and I have never tried, nor needed, to build any extensions since then.
Quentin Stafford-Fraser
17 May 2000
Nick Barnes adds:
If you want this extension, or ones like it, to work, when you build your mod_php3 you must not say --enable-versioning to ./configure.
If you say --enable-versioning, almost all the symbols in libphp3.so get hidden, and your little example can't find php3_puts, because it gets made into an internal symbol (along with everything else apart from php3_module; see php.map in the PHP3 sources). Argh. It took me several hours of tweaking runtime linkers, figuring out how RTLD_GLOBAL works etc etc to find this.
The FreeBSD ports/packages collection turns on --enable-versioning by default.