Runkit with PHP on Linux (Debian Etch)
The forbidden fruit
I recently discovered runkit for PHP and thought it could be a solution for a few problems I ran into during my work on various projects.
At heart runkit allows you do to stuff with PHP you shouldn’t, but eventually want to, do. In my case this is basically Sandboxing and redefining (even PHP-internal) functions. It really adds some cool stuff to your PHP toolbox. Have a look at the function reference for the complete list.
Sadly enough the runkit PECL package does not work on Debian Etch (because Etch uses PHP 5.2.0+) so I had to build the package myself. Read on to find out how to build and install runkit on Debian etch and things to keep in mind when using runkit.
Important: If you are unsure of using runkit have a look at The sections The Caveat and Final Remarks before you walk through the hassle of installing it.
Install & Configure runkit
Obtain the sources from the runkit CVS
Obtaining the sources is pretty easy. Just open a terminal and enter the following commands (leave the password empty when prompted for it)
cvs -d:pserver:cvsread@cvs.php.net:/repository login cvs -d:pserver:cvsread@cvs.php.net:/repository co pecl/runkit
This will checkout the runkit codebase into your current working directory.
Building the Debian package from the PECL source
You need some tools for building the package so I installed them using aptitude.
sudo aptitude install dh-make-php php5-dev
Then I created a kind of fake PECL package from the CVS sources to use it with the dh-make-pecl tool. dh-make-pecl is a Debian tool which helps you building .deb from a PECL package. The PECL package is just a .tar.gz archive having the following structure:
I assembled this package by using simple mv and mkdir inside the CVS then I used tar to create the archive. I called it runkit-cvs-<date>.tar.gz but the name is basically irrelevant.
mkdir -p package/runkit-0.9 mv pecl/runkit/package*xml package/ mv pecl/runkit/* package/runkit-0.9/ cd package/; tar cfz ../runkit-cvs-`date +%Y%m%d%H%M`.tar.gz *; cd ..
After I had the fake PECL package I could start creating the .deb from it. This was fairly simple.
dh-make-pecl --only 5 runkit-cvs*tar.gz cd php-runkit-0.9 dpkg-buildpackage -rfakeroot
dpkg-buildpackage puts the created .deb parallel to the php-runkit-0.9 directory. The –only 5 parameter requests the dh-make-pecl command to only create a Debian source package for the PHP 5 module. Have a look at the manual for more information.
Installing the package
Installing runkit is now just a matter of typing sudo aptitude install php5-runkit_0.9-1_i386.deb and letting APT do it’s work. After that you have to create a configuration file under /etc/php5/apache2/conf.d called runkit.ini with the following contents:
extension=runkit.so # comment out the following line to disable the overloading # of PHP internal functions. runkit.internal_override=1
After that restart your Apache server and you are done with the installation. You can check if runkit was installed sucessfull by just creating a phpinfo() file and look if runkit is listed in the modules section.
The Caveat (Renaming PHP internal functions)
I was quite happy to have all this stuff running but as we all know nothing is less predictable than solutions in information technology (apart from visiting relatives appearing out of nowhere). My first little project was to add some logging to the PHP built in mail() function. This may be useful to track down the spam sending contact form one of your customers build for his website on your server. I wrote a small script for testing purposes and just threw it in my public_html directory.
// Simple function to ouput a log message
function do_log($message) {
echo 'LOG:'.$message;
}
// Wrapper for the PHP mail() function.
// Logs the mail parameters.
function logging_mail($to, $subject, $message, $headers = null, $params = null) {
do_log('Sending mail to '.$to.' by '.__FILE__);
php_mail($to, $subject, $message, $headers, $params);
}
// Interchange the built in function with my own
runkit_function_rename('mail','php_mail');
runkit_function_rename('logging_mail','mail');
mail('mymail@nodomain.xyz','Subject','message');
It all seemed nice and logical but when I first opened my webbrowser and accessed the page I got a blank screen. My Apache error log revealed a child pid 10051 exit signal Segmentation fault (11) and commenting out the mail() and a quick page refresh even added a Fatal error: Cannot redeclare do_log() to the table. This looks really bad. It seems that renaming PHP internal functions and replacing them doesn’t work with runkit and the resulting crash of the PHP interpreter left the library of this interpreter in a corrupted state (user-defined functions where not removed because the script didn’t exit properly).
So as always: The part of a library you really need has a nasty bug. Although renaming user defined functions works great with runkit the part I really wanted doesn’t work out of the box.
I already have a solution in mind but this will be the topic of another blog post.
Final remarks
Runkit in theory is really great stuff. The problem with this library in realty is that it’s still beta (even after several years) and doesn’t seem to be actively maintained. Just a short look at the CVS repository and the bugtracker revealed that there hasn’t been much activety in the last year or so. This is a pitty because having the additional flexibilty that runkit provides really would be a killer feature for PHP developers. Other scripting languages (Python, Groovy and more) already bring these features to the table natively which allows you to write extremly elegant code.
If you are willing to dig into this extension prepare to do some work and be eventually disappointed because the solution you had in mind won’t work because of bugs. If you are willing to take this risk and invest some time and energy go for it. Maybe future versions of PHP will make runkit obsolete or a good-willing developer will take care of the bugs. Till then runkit remains black magic, it can make you incredibly powerful but also is a serious risk for your mental stability.
More information
- http://gabriel.e-radical.ro/blog1.php/2008/09/25/runkit – An alternative way to build runkit
- http://en.php.net/runkit – The runkit function reference



May 11th, 2009 at 5:57 am
What you wanted to can be done with pecl/apd extension. The function “rename_function”.
I run into the exact problem you had with runkit with Segfault. But with the apd it works fine.
Implementation wise think runkit is too complex, where as apd does this very straight forward.