A synchronous, capability-empty QuickJS-NG runtime for PHP, built as a native extension in Rust. It is designed for running untrusted JavaScript orchestration code whose only authority comes from PHP callbacks explicitly registered by the host application.
- Mandatory positive CPU, memory, and native stack budgets
- No filesystem, network, process, environment, or standard QuickJS
std/os - No module loader, dynamic native modules, Promise job loop, or bytecode API
- Explicit, bounded PHP-to-JavaScript and JavaScript-to-PHP conversion
- Circular-reference, conversion-depth, and conversion-size rejection
- Fresh QuickJS runtime and global object for every
Sandbox - Typed PHP exceptions for syntax, runtime, timeout, memory, stack, conversion, and callback failures
This is an in-process language sandbox, not an operating-system isolation boundary. Read THREAT_MODEL.md before exposing it to users.
- PHP 8.4 on Linux x86_64 (NTS or ZTS), or PHP 8.5 NTS on macOS ARM64
- Rust 1.87+ when building from source
Release artifacts include the PHP minor version and thread-safety ABI in the
filename. Both must match php-config --version and the Thread Safety row in
php -i; an NTS extension cannot load into ZTS PHP or vice versa.
$sandbox = new \QuickJS\Sandbox(
memory_limit: 32 * 1024 * 1024,
cpu_limit: 5.0,
stack_limit: 512 * 1024,
);
$sandbox->setGlobal('ctx', ['run_number' => 4]);
$sandbox->register('__host', [
'greet' => fn (string $name): string => "Hello, {$name}!",
]);
$script = $sandbox->load(<<<'JS'
return {
run: ctx.run_number,
greeting: __host.greet('OpenCompany'),
};
JS, 'automation.js');
var_dump($script());load() compiles the source as a strict JavaScript function body. Top-level
return works, and invocation arguments are available through arguments.
Source is capped at 4 MiB before the extension creates its wrapped function.
| Method | Meaning |
|---|---|
__construct(int $memory_limit = 33554432, float $cpu_limit = 5.0, int $stack_limit = 524288) |
Create one isolated runtime. All limits must be positive. |
load(string $source, ?string $name = null): QuickJS\Script |
Compile a strict function body. |
setGlobal(string $name, mixed $value): void |
Inject structured data. |
register(string $namespace, array $callbacks): void |
Register explicit PHP capabilities. |
memoryUsage(): int |
Current allocator usage. |
peakMemoryUsage(): int |
Highest observed allocator usage at a host boundary. |
memoryStats(): array |
QuickJS allocator counters. |
cpuUsage(): float |
CPU seconds used by the last script/host operation. |
version(): array |
Extension and engine binding versions. |
null, booleans, floats, UTF-8 strings, lists, and associative arrays cross the boundary directly.- PHP integers outside JavaScript's safe
Numberrange becomeBigInt. - JavaScript
BigIntvalues must fit in a PHP 64-bit integer when returned. - Only JavaScript arrays and plain/null-prototype objects with enumerable string keys become PHP arrays; symbol and non-enumerable properties are rejected.
- Functions, symbols, promises, proxies, Dates, Maps, Sets, cycles, invalid UTF-8, and oversized/deep graphs are rejected explicitly.
cargo build --release
./scripts/run-php-tests.sh target/release/libquickjs_sandbox.dylibOn Linux the artifact ends in .so.
Download the release artifact matching both your platform and PHP minor ABI,
copy it into php-config --extension-dir, and enable it:
curl -fLO https://github.com/OpenCompanyApp/quickjs-sandbox/releases/download/v1.0.1/quickjs_sandbox-php85-nts-macos-aarch64.so
curl -fLO https://github.com/OpenCompanyApp/quickjs-sandbox/releases/download/v1.0.1/quickjs_sandbox-php85-nts-macos-aarch64.so.sha256
shasum -a 256 -c quickjs_sandbox-php85-nts-macos-aarch64.so.sha256
install -m 0755 quickjs_sandbox-php85-nts-macos-aarch64.so "$(php-config --extension-dir)/quickjs_sandbox.so"
printf '%s\n' 'extension=quickjs_sandbox.so' > "$(php-config --ini-dir)/quickjs-sandbox.ini"
php --ri quickjs_sandboxMIT