PHP 8.x · Rust loader · Web + CLI · Linux / Unix

Ship PHP code.
Without shipping source.

BinaryPHP encrypts your commercial PHP source with AES-256-GCM, derives a unique key per file, and enforces domain-locked or MAC-locked, time-limited licenses—all decoded transparently by a tiny Rust loader extension. Quarterly key rotation with permanent backward compatibility — cracking costs far exceed legitimate license fees.

1. Encode online 2. Customer installs 3. Code runs sealed
# Upload at binaryphp.com/encode/ and fill in the license:

  Domains: acmestore.com, *.acmestore.com
  Expires: 2027-12-31
  Plugin:  acme-pro

# Input  →  plugin.php          (your source, ~40 KB)
# Output →  plugin.php          (sealed, ~41 KB binary content)

# Same filename, same .php extension — drop-in replacement, no caller changes.
# The loader recognizes it by a 5-byte "BPHP2" magic header, not extension.
# Master key stays on our server; only the sealed output goes back to you.

PHP doesn't compile.
That's a business problem.

Your customer is your competitor

The moment a paying customer downloads your .zip, every line of PHP you wrote is theirs to copy, fork, and resell.

License keys aren't enforcement

Disabling a license check takes minutes when the source is right there. Without code-level protection, your license is a checkbox, not a wall.

Your code lives on disks you don't control

Once your customer downloads it, your source sits on shared hosts, VPSs, and CI runners you'll never see—exposed, indexed, and one tar -xzf away.

How it works

1

Upload

Drop a .php file or a plugin .zip into our web encoder. Pick the licensed domain(s), MAC address(es), and expiration. The master encryption key never leaves our server—you don't have to safeguard anything.

2

Distribute

Download the sealed .bphp (or rezipped plugin). Each file has its own per-file salt and HKDF-SHA256-derived key. Tampering invalidates the GCM tag and refuses to run.

3

Load

Your customer adds extension=binaryphp.so to php.ini. The loader hooks PHP's compile pipeline, decrypts in memory, validates the license against SERVER_NAME / HTTP_HOST (web) or the machine's MAC (CLI), and hands plaintext to the Zend Engine.

What's inside

🔐 AES-256-GCM

NIST-standard authenticated encryption. Tampering with a single byte invalidates the GCM tag and the file refuses to run.

🧂 Per-file key derivation

Every encoded file has its own 16-byte salt and a unique HKDF-SHA256-derived key. Each file is sealed independently.

🛡️ Bytecode VM for hot functions

Mark functions with #[binaryphp\Protected] and they get compiled to our own bytecode — not PHP, not Zend opcode. Runtime is interpreted by the loader; the algorithm never exists as PHP source on the customer's disk.

🌐 Multi-domain licenses

List multiple hostnames or wildcard suffixes (*.example.com) per license. License passes if any matches.

🔌 MAC-bound licenses

For CLI tools, cron jobs, or any non-HTTP context: bind the license to the customer's machine via MAC address (read from /sys/class/net).

⏳ Expiration dates

Issue time-limited builds for trials, subscriptions, or release windows. The loader checks the system clock against the embedded timestamp.

⚙️ Standard PHP extension

Loads via extension= in php.ini. Works under PHP-FPM, mod_php, CLI, FrankenPHP. No SAPI changes.

🪶 Compact loader

Single ~2.0 MB stripped .so (includes the bytecode VM + cranelift JIT). Sub-millisecond decrypt overhead per included file.

🔁 Transparent fallthrough

Plain .php files compile normally—the loader only intercepts files starting with the BinaryPHP magic header.

Performance: encryption is essentially free

The loader hooks zend_compile_file, so decrypt happens once per file per process. Once compiled, the runtime cost is identical to plain PHP. With OPcache enabled, decrypt happens once per cache invalidation cycle.

1M-iter hot loop (for + % + accumulate) · shorter is faster · baseline = plain PHP
Plain PHP
88.6 ms
1.0×
binaryphp-rs
89.5 ms
1.0×
binaryphp-vm + JIT
~115 ms
1.3×
binaryphp-vm interp
197.6 ms
2.2×
Plain / .bphp full-file #[Protected] · cranelift JIT #[Protected] · interpreter
Workload Plain PHP binaryphp-rs
(.bphp · full file encrypt)
binaryphp-vm
(#[Protected] · bytecode VM)
1 M-iter hot loop in a function (for + % + accumulate) 88.61 ms ± 0.95 89.48 ms ± 3.08 ~115 ms (JIT) · interpreter 197.56 ms
Cold include — small file (~220 B) 56.05 ms ± 1.62 56.46 ms ± 1.34 ~bphp (stub only — VM idle until called)
Cold include — 10 KB file (200 functions) 57.14 ms ± 1.33 57.09 ms ± 1.57 ~bphp (same: VM cost is per-call, not per-load)
Steady-state with OPcache identical identical per-call cost only
Plain ≈ binaryphp-rs (within noise). binaryphp-vm: ~1.3× hot-loop overhead with cranelift JIT (tier-up after 8 calls; int-only fast-path) — the trade-off for bytecode-level protection that survives even a leaked master key.

Measured 2026-05-05 with hyperfine, 30 runs per row, on Debian 12 (kernel 6.5) + PHP 8.2.30 + Rust 1.95.0, Intel Xeon E5-2680 v4 @ 2.40 GHz (binaryphp.so 548 KB, release+LTO). Per-include decrypt cost scales as file_size / ~1 GB/s on AES-NI hardware, plus ~50 µs fixed overhead for HKDF + license check. VM cost scales linearly with the number of bytecode ops executed. Compiler peepholes ($x++, $x += k, $x = $x + e, slot-vs-slot int compare, $x * imm, x % imm) cut the hot-loop overhead from ~5× to ~2.5× by collapsing common LoadVar / StoreVar stack churn into single ops.

VM language coverage: OOP (classes, extends, abstract, interface, trait + use, static, class constants, $this, parent::, self::, magic __construct / __get / __set / __call); closures (function () use (…)) + arrow fns (fn () => expr); try / catch / finally / throw; match, === / !==, ??, ?:, <=>, instanceof; lazy / coroutine generators (yield with frame snapshot & resume — infinite generators work, only consumed values are computed); full for / while / foreach / switch / break / continue; spread ...$args; references &$x on params and builtins like array_push / sort; global; heredoc + nowdoc; ~50 built-in functions (strlen, count, trim, explode, implode, sprintf, md5, sha1, base64_encode/decode, array_*, …); encoder support for #[Protected] on individual class methods (with full $this->prop read/write that round-trips back to PHP); cranelift AOT JIT for hot int-only loops.

How to choose: ship everything as .bphp (binaryphp-rs) — the runtime delta is unmeasurable. Reach for #[Protected] (binaryphp-vm) only on your most sensitive functions — license checks, key derivation, anti-tamper routines — where you accept ~2.5× cost on those specific functions in exchange for "even with the master key, the body is opaque bytecode." With OPcache enabled, repeat-request overhead for plain code paths remains indistinguishable from plain PHP.

Pricing

Monthly or annual via Stripe. Annual = 20% off.

Free

$0forever
  • Sign in with Google
  • Up to 1 MB per encoding — .php or .zip
  • 1 exact domain (no wildcards) + 1 MAC
  • Same encryption as paid tiers
  • Rate-limited per account
Sign in to start
For ISVs

Ultra

$10/ month · $96 / year (save 20%)
  • Everything in Pro
  • Single file up to 300 MB (multipart upload)
  • REST API + Webhook: integrate into your sales flow
  • Customer pays you → call our API → we deliver encoded ZIP via webhook → you notify your customer with download URL
  • Per-encoding domain / MAC / expiry
  • Priority support
Subscribe via Stripe

The Free tier uses the exact same encoding engine as paid tiers. Same AES-256-GCM, same bytecode VM, same protection strength. The only difference is usage limits (file size, API access, batch rate).

Install the loader

Free, redistributable. Anyone running a BinaryPHP-encoded plugin needs this on their server.

Customer / end-user

Standard install (Debian/Ubuntu, PHP 8.2)

# 1. Drop the .so into PHP's extension directory
$ sudo cp binaryphp.so /usr/lib/php/20220829/

# 2. Enable the extension
$ echo 'extension=binaryphp.so' | sudo tee /etc/php/8.2/mods-available/binaryphp.ini
$ sudo phpenmod binaryphp

# 3. Restart PHP-FPM (or your SAPI)
$ sudo systemctl restart php8.2-fpm

Verify the loader is active:

$ php -r 'echo binaryphp_version();'
0.9.2

$ php -r 'echo binaryphp_hostname();'
your-domain-or-hostname

$ php -r 'print_r(binaryphp_macs());'
Array ( [0] => aa:bb:cc:dd:ee:ff )

Or hit any phpinfo() page in a browser — you'll see a dedicated BinaryPHP block listing the loader version, master generation, supported file formats, and bytecode VM status. Same info, easier for non-CLI environments (cPanel, Plesk, shared hosts):

BinaryPHP support  →  enabled
Loader version     →  0.9.2
Master gen         →  2 (rotated 2026-05-06)
File formats       →  BPHP2/3/4 · HBPH1/2/3 · BVMC1/2/3
Bytecode VM        →  v3 obfuscation + cranelift JIT

Pick the loader for your PHP minor version (each .so is built against that exact ABI — they're not interchangeable):

Run php -v on your server to find your exact PHP version. macOS / aarch64 / FreeBSD not yet supported.

Plugin author

Use the SaaS encoder

No CLI install, no master key to safeguard. Open the encoder, upload, set the license, download the sealed file.

  • Per-file random salt + AES-256-GCM
  • License envelope (domain · MAC · expire) bound inside ciphertext — untamperable
  • Original filename preserved (.php.php)
  • Loader detects by magic header, not extension
Open encoder

Free tier accepts .php or .zip up to 1 MB. Pro up to 100 MB; Ultra up to 300 MB with multipart.

FAQ

Is BinaryPHP truly unbreakable?

Honestly: no offline-runnable DRM can guarantee "permanently unbreakable". ionCube, Zend Guard, and SourceGuardian have all been studied and broken at various points.

So BinaryPHP's goal isn't a mythical "absolute security" — it's:

Make cracking cost far exceed the price of a legitimate license.

Cracking BinaryPHP isn't simply "decrypting a file." An attacker typically also has to:

  • Reverse-engineer the loader
  • Analyse runtime behaviour
  • Recover VM bytecode
  • Reconstruct the obfuscated control flow

Even when they succeed, what they get is rarely the original source — it's:

  • Variable names lost
  • No comments
  • Mangled control flow
  • An intermediate representation that's painful to maintain

And BinaryPHP keeps moving:

  • Loader
  • VM instruction set
  • Obfuscation layer
  • Anti-debug / anti-tamper

so older cracking tools quickly stop working.

That's the core philosophy:

Not making cracking "impossible" — making it "not worth it."

Web vs CLI — which license type should I use?

If your code runs inside a web server, use domain binding. The loader checks $_SERVER['SERVER_NAME'] first (set by nginx/Apache config—cannot be spoofed by the client) and falls back to HTTP_HOST. If your code runs as a CLI tool (cron jobs, internal scripts), use MAC address binding—the loader reads from /sys/class/net/*/address. You can also include both in a single license; the loader passes if either matches.

Does this affect performance?

No. The decrypt happens at compile_file time—once per file per PHP process. Once compiled into Zend opcodes, your code runs at identical speed to plain PHP. Our 50M-iteration loop benchmark shows runtimes within statistical noise (~30% normal jitter). With OPcache (standard on production servers), even the cold-start decrypt is amortized across all subsequent requests. See the Performance section above for measured numbers.

Does the master key live on my server?

With the SaaS encoder: no. The master key never leaves our infrastructure. You upload plaintext, we encode, you download ciphertext. With the upcoming source-available CLI: yes, the key would be embedded in your encoder build. SaaS is the safer default for most plugin developers.

What's the technical approach?

BinaryPHP is a 2026 ground-up implementation built on modern crypto (AES-256-GCM, HKDF-SHA256) plus our own bytecode VM that protects the core logic of #[Protected] functions. The toolchain is delivered as SaaS — your master encryption key never leaves our infrastructure, you don't have to safeguard or rotate anything, and the file format is documented and stable within major versions.

Can my customers' shared host run BinaryPHP files?

Only if their host has the BinaryPHP loader installed. The loader is free and redistributable — you can ask your customers to install it (one-line php.ini entry) or bundle it with your installer. We're working on cPanel / Plesk integrations to make this even more frictionless.

What protection layers does BinaryPHP apply?

Three independent layers, all enforced by the loader:

  • AES-256-GCM authenticated encryption with HKDF-SHA256 per-file key derivation. Each file has its own salt and key — one cracked file leaks nothing about the others.
  • Custom bytecode VM for functions you mark with #[binaryphp\Protected]. Those function bodies are compiled to our own bytecode (not PHP, not Zend opcode) and interpreted by the loader at runtime. They never exist as PHP source on the customer's machine.
  • License envelope bound inside the ciphertext: domain / MAC / expiration. Tampering invalidates the GCM tag and the file refuses to run.

For your most sensitive algorithms, keep them on a server-side API; for everything else, BinaryPHP gives you defense in depth without re-architecting your codebase.

Does it work with my framework / autoloader?

Yes. BinaryPHP intercepts PHP's compile pipeline, so anything that does include / require works transparently—Composer autoload, framework routers, plugin systems, custom dispatchers. Tested against PHP 8.1–8.4.

What about OPcache?

Compatible. OPcache caches the compiled opcodes after our loader has decrypted and compiled. Your encoded file gets decrypted once per OPcache invalidation cycle, then runs at native speed.

What's the file format?

Documented and stable: a 52-byte header ("BPHP2" magic + version + 16-byte salt + 12-byte IV + 16-byte GCM tag) followed by ciphertext. The decrypted plaintext is a 4-byte length-prefixed license JSON followed by your PHP source. We commit to format compatibility within major versions.

What payment methods do you accept?

All billing is handled by Stripe. You can choose:

  • Monthly subscription — $5 / month (Pro) or $10 / month (Ultra). Cancel anytime.
  • Annual subscription — same plans, paid yearly, with a built-in 20% discount ($48 / year for Pro, $96 / year for Ultra).

30-day refund on subscriptions. Stripe accepts all major cards plus most regional payment methods.

Could a malicious upload crash your server?

Architecturally, no. We never execute uploaded PHP — we only tokenize and encrypt it. The encoder runs token_get_all() (PHP's lexer, not the executor) on your file, splits HTML from PHP code, AES-encrypts each PHP block, and writes the output. There is no eval, no include, no shell call against your code's contents.

For zip uploads we additionally enforce four hardenings before extracting:

  • Reject path traversal (../, absolute paths, drive letters)
  • Reject zip bombs (cumulative uncompressed > 200 MB or compression ratio > 100×)
  • Reject excessive entries (> 2,000 files or > 1,000 .php files per zip)
  • Reject deep nesting (> 16 directory levels)

Each job runs in an isolated temporary directory that is wiped after the response is sent. You can upload literal malware — we'll just encrypt it and hand it back.

How does the API tier work?

Designed for ISVs reselling encoded PHP plugins. After your customer purchases your software:

  1. Your server POSTs our REST API with the customer's domain / MAC + your encoding parameters + a webhook URL.
  2. We pull the source from a URL you provide (or accept it inline), encode it, and upload the result to R2.
  3. We POST the result download URL to your webhook.
  4. Your server forwards the URL to the customer (email, dashboard, however you do it).

Encoded files live on R2 for 72 hours, then auto-delete. Source uploads we receive are deleted within 24 hours.

Customers shipping with BinaryPHP

Stop shipping your source code.

Sign in with Google — free tier active immediately, no credit card.