3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features

Introduction

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:

- we've served 850k sessions to 500k users.

Statistics

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:

Pro-tricks

There are a few tricks you might appreciate; did you know you can submit a script using the keyboard shortcut ctrl + enter? Did you ever want to copy a script to run it yourself? You can simply download it, use:

$ curl -H Accept:text/plain https://3v4l.org/uNUDC

Did you ever complain there is no API? Well, REST is an API too, and I offer json output for most pages:

$ curl -H Accept:application/json https://3v4l.org/uNUDC

Links

Technology

Backend

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.

All binaries are compiled using the same settings; they are stripped and then compiled with upx to keep their filesize down.

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

[PHP]
; 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]
date.timezone = Europe/Amsterdam

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

#!/bin/bash
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-*
do
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=$?

sf=/out/$1/${bin##*-}-exit
[[ $ex -eq 0 && -f $sf ]] && rm $sf
[[ $ex -ne 0 ]] && echo -n $ex > $sf
done

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.

Frontend

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.