run code in 300+ PHP versions simultaneously


I have been programming in PHP since 2002, and as me and my collegues used more advanced features we noticed PHP's behaviour would sometimes change without any reference in the changelog. An example of this was this parse_ini bug, which was an example where we needed to demonstrate the variation of results over time and 3v4l.org showed a clear advantage.

Since 2012 I have provided vanilla PHP binaries that make it simpler to demonstrate issues that would otherwise be harder to reproduce, and cumbersome to compare to previous version. Traffic has steadily been growing as more developers found this site to be a helpful daily tool, as the following sessions-graph shows:

user viewsnew scriptsbot views11 475973 469112 563103 2933 205 6181 507 185203 2042 873 4897 624 321314 8297 732 93910 248 788441 2398 258 45718 984 187558 5379 499 27118 213 318579 8518 442 38327 431 680709 5046 439 19318 783 313829 7877 678 56215 450 842948 82417 681 53019 969 2381 075 69511 778 08113 791 022643 89717 707 53412 823 70720122013201420152016201720182019202020212022202340 M32 M24 M16 M8 M0 M

This site is build and maintained by Sjon Hortensius.


I started in april 2012 and have been adding features ever since. If you like numbers, here are a some from the database:

Major changes

I have been adding features ever since I started. Here is a list with some major changes I made over the years:


There are a few tricks and some hidden functionality you might appreciate:




This site started out on a server with 256 MiB memory, which was enough to run one script at the time, as well as the site itself. However, when I added HHVM, it needed a lot more memory, so I upgraded to a 1 GiB machine. Because of dropping prices, the site current runs on a 4 GiB machine.

I use a setup where scripts are executed in a small virtual machine. For security reasons this machine has no network and only a minimal filesystem. Scripts are executed by a daemon (written in Golang) and results (with statistics) are reported to a PostgreSQL database. All results are stored and used to provide averages for the performance overview.

I use the following php.ini settings for the scripts:

; ini_set should be in here too if you're concerned about security
disable_functions = pcntl_fork,phpinfo
max_execution_time = 3
memory_limit = 64M
enable_dl = Off

; for consistency of older versions
allow_call_time_pass_reference = Off
html_errors = Off

; show all errors by default, if we'd lower this in the script we'll miss some parser notices
error_reporting = -1
display_errors = On
display_startup_errors = On
log_errors = Off
report_memleaks = On

date.timezone = Europe/Amsterdam

When I started in 2012, this site was nothing more than a small bash script that looped through all available PHP binaries and stored the output in /out/. For fun; here is the source-code of the script that I started with:

ulimit -f 64 -m 64 -t 2 -u 128

[[ ! -d /out/$1/ ]] && mkdir /out/$1/ || chmod u+w /out/$1/

for bin in /bin/php-*
echo $bin - $1
nice -n 15 sudo -u nobody $bin -c /etc/ -q "/in/$1" &>/out/$1/${bin##*-} & PID=$!
( sleep 3.1; kill -9 $PID 2>/dev/null ) &
wait $PID

[[ $ex -eq 0 && -f $sf ]] && rm $sf
[[ $ex -ne 0 ]] && echo -n $ex > $sf

chmod u-w /out/$1/

Because of the amount of files this generated (which did not play well with the average filesystem block-size) I replaced this with a SQLite based database with an inotify-based script that picked up changes in /out/ and imported them into the database.

For simplified connectivity to the database I replaced this with a C-based binary in 2013; and that was replaced by a Go-based program that's still in use today.


As for the website you are currently looking at, this was originally based on the TooBasic framework I build specifically for 3v4l.org. As the number of features increased I eventually migrated to another framework (which is not open-source, but it's called the Basic Framework) with an actual Model and Template-parser.

For performance reasons I strip the HTML, CSS and javascripts; but there have been a few invisible upgrades here as well. Originally I used MooTools but that has been replaced by Vanilla JS. If you'd like, you can find a human-readable version here. My work pays off, as can be seen when analyzing the performance of this site.

The layout has taken a few cues from Bootstrap but given the verboseness of both its HTML and CSS I don't actually use that. The initial layout allowed for only the input and output to be visible, which was why I did an update where I added the tabs allowing for various helpers to be included. You're currently looking at the third layout iteration, which was done specifically to allow for some global contextual links to be visible and allow for various other features.

Consistent dates and times

To get consistent output I try to eliminate as much environmental changes as possible. The chroot is rarely changed, and some methods are overloaded to provide consistent results. For example, php_uname will always return the same output.

This is to keep the number of unique results down, and make the bughunt a more useful tool. This fixation is also done on all date/time methods. A run will start at the same time for all versions, even though the actual walltime progresses.

For example - this simple echo date(); script was submitted in 2012. Since it was created, I have executed it on new versions as well - which all output 2012 even though most of the PHP versions weren't even released at at that time!

The date/time fixation uses the last submit time as reference. This means a quick-preview can sometimes show "outdated" timestamps as you are actually looking at output from a run with the previous submit-time.

12.94 ms | 408 KiB | 6 Q