How to run PHP code in a sandbox
Install php-cli in a Linux microVM, write the script there, and run it with php under a time limit and with the network off.
On Runtime, PHP is one apt command away and every script gets its own
kernel. Each sandbox is a Firecracker microVM running Ubuntu 24.04.5, where
sudo apt-get install -y php-cli installs PHP 8.3 from Ubuntu's archive. A new
sandbox took 351 ms from the create request to its first Python result at the median,
measured on 24 September 2026 (speed); bake PHP into an image and
that is all the wait there is.
PHP packages on Ubuntu 24.04
PHP is not in the default image. These are the Ubuntu 24.04 (noble) packages, read on packages.ubuntu.com on 25 September 2026:
| Package | Version | What it adds |
|---|---|---|
php-cli |
8.3 (php8.3-cli 8.3.6) |
The php command |
php8.3-sqlite3 |
8.3.6 | PDO and SQLite3 for SQLite |
php8.3-pgsql |
8.3.6 | PDO and pgsql for PostgreSQL |
composer |
2.7.1 | Composer, the dependency manager |
For another PHP version, start a custom image from the official
php image on Docker Hub, such as php:8.4-cli (a tag listed there on
25 September 2026).
Run a script
Install once, turn the internet off, then run what you were given. The script goes in as a file and runs with an array, so nothing passes through a shell.
TypeScriptimport { Sandbox } from "withruntime";const script = `<?php$words = str_word_count("the quick brown fox jumps over the lazy dog", 1);echo json_encode(array_count_values(array_map('strlen', $words))), PHP_EOL;`;await using sbx = await Sandbox.create({ timeoutSeconds: 600, onLeaseEnd: "stop" });await sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q php-cli", { check: true, timeoutMs: 300_000,});await sbx.network.set({ internet: false });await sbx.files.write("/workspace/job.php", script);const lint = await sbx.exec(["php", "-l", "job.php"]);if (lint.exitCode !== 0) throw new Error(lint.stdout);const run = await sbx.exec(["php", "-d", "memory_limit=256M", "job.php"], { timeoutMs: 20_000 });console.log(run.exitCode, run.timedOut, run.stdout);Pythonfrom withruntime import Sandboxscript = """<?php$words = str_word_count("the quick brown fox jumps over the lazy dog", 1);echo json_encode(array_count_values(array_map('strlen', $words))), PHP_EOL;"""with Sandbox.create(timeout_seconds=600, on_lease_end="stop") as sbx: sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q php-cli", check=True, timeout_ms=300_000) sbx.network.set(internet=False) sbx.files.write("/workspace/job.php", script) lint = sbx.exec(["php", "-l", "job.php"]) if lint.exit_code != 0: raise SystemExit(lint.stdout) run = sbx.exec(["php", "-d", "memory_limit=256M", "job.php"], timeout_ms=20_000) print(run.exit_code, run.timed_out, run.stdout)php -lchecks syntax without running the code and reports on stdout. It does not find errors that only show at run time, such as an undefined function (PHP command-line options).-dsets any php.ini directive for one run, so each job can get its own memory limit.timeoutMsstops the command from outside PHP. An endless loop returnstimedOut: truewith the output so far.
Why not disable_functions?
PHP's own settings can hide functions such as exec or system, but the code
still runs in your process, on your kernel, next to your files and network. A
sandbox moves the whole interpreter into a microVM with its own kernel. Leave
shell_exec on if the job needs it: it reaches only a throwaway machine whose
network, CPU, memory and cost are enforced on the host
(security).
Install Composer packages, then cut the network
Composer needs Packagist and the package hosts while it installs. Let it install with the web on, then switch the network off before the project's code runs:
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ timeoutSeconds: 900, onLeaseEnd: "stop" });await sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q php-cli composer unzip", { check: true, timeoutMs: 300_000,});await sbx.files.upload("./app", "/workspace/app");await sbx.exec(["composer", "install", "--no-interaction", "--no-progress"], { cwd: "/workspace/app", check: true, timeoutMs: 300_000,});await sbx.network.set({ internet: false });const tests = await sbx.exec(["php", "vendor/bin/phpunit"], { cwd: "/workspace/app", timeoutMs: 300_000,});console.log(tests.exitCode, tests.stdout.slice(-3000));See a PHP page in your browser
PHP's built-in web server (php -S) serves a folder. Start it with spawn so
it keeps running, then share the port as a private HTTPS
preview:
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ image: "php", timeoutSeconds: 1800 });await sbx.files.write("/workspace/site/index.php", "<?php echo 'Hello from PHP ', PHP_VERSION;");await sbx.spawn(["php", "-S", "0.0.0.0:8000", "-t", "/workspace/site"]);const preview = await sbx.previews.create(8000);console.log(preview.urlWithToken);This uses the php image built below. See
previews of agent-built apps for the
whole flow.
Start every sandbox with PHP
Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(name="php", recipe={"apt": ["php-cli", "php8.3-sqlite3", "composer", "unzip"]})with runtime.sandboxes.create(image="php", network={"internet": False}) as sbx: print(sbx.exec(["php", "-v"]).stdout)Terminalruntime image build --apt php-cli,php8.3-sqlite3,composer,unzip --name phpBuilding an image is free, and the free trial stores your first three images free (custom images).
What it costs
Runtime bills the CPU a script uses at $0.025 per vCPU-hour, with a floor of a twentieth of a vCPU, and memory at $0.0075 per GiB-hour. A 2 vCPU, 4 GiB sandbox waiting between requests costs $0.03125 an hour (pricing). New accounts get 50 free sandbox hours, no card:
Terminalnpx withruntime sandbox run --trial -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q php-cli && php -v'For code a model wrote, see running untrusted LLM code and turning off a sandbox's internet.
Sources
Checked 25 September 2026.
- Ubuntu 24.04 (noble) packages: php-cli, php8.3-cli, php8.3-sqlite3, php8.3-pgsql, composer
- php on Docker Hub
- PHP command-line options
Facts on this page were checked on 25 September 2026.