globus-studio / php-obfuscator
A token-based PHP source code obfuscator with full support for PHP 8.1 through 8.5.
Requires
- php: ^8.1
- ext-tokenizer: *
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0
README
A token-based PHP source code obfuscator. Renames identifiers, encodes string literals and minifies whitespace, all driven by PHP's own tokenizer rather than brittle regular expressions, so the transformed code keeps its original runtime semantics on every supported PHP version.
The obfuscator is fully tested on PHP 8.1, 8.2, 8.3, 8.4 and 8.5 in CI.
Why another obfuscator?
Most PHP obfuscators on the open web rely on regular expressions. They break
on namespaced code, on complex string interpolation, on constructor property
promotion and on anything that does not fit a simple textual pattern. This
library walks the official PhpToken stream and rewrites identifiers using
the same lexical context the engine itself uses, which makes the result
predictable and safe to ship.
Features
- Token-based identifier rewriting (variables, functions, classes, interfaces, traits, enums, methods, properties, class and global constants).
- Constructor property promotion,
readonly,enum,match, arrow functions, nullsafe operator, named arguments and attributes are all recognised. - Optional Base64 encoding of string literals (skipped automatically inside constant expressions where PHP requires literal values).
- Optional comment stripping and whitespace minification driven by a second tokenizer pass, so the output is guaranteed to remain parseable.
- Optional
eval(base64_decode(...))wrapping for an extra layer of protection. - Deterministic PRNG seed for reproducible builds.
- Inspection of the rename table via
getNameMap(). - Bundled
php-obfuscateCLI binary.
Installation
composer require globus-studio/php-obfuscator
Quick start
<?php require __DIR__ . '/vendor/autoload.php'; use GLOBUSstudio\PhpObfuscator\Obfuscator; use GLOBUSstudio\PhpObfuscator\Options; $obfuscator = new Obfuscator(); echo $obfuscator->obfuscate(<<<'PHP' <?php function greet(string $name): string { return "Hello, $name"; } echo greet('Ada'); PHP);
The output is a self-contained <?php eval(base64_decode("...")); payload that
prints Hello, Ada when executed.
Library API
Obfuscator
$obfuscator = new Obfuscator(new Options(seed: 42)); $code = $obfuscator->obfuscate('<?php echo 1 + 1;'); $code = $obfuscator->obfuscateFile(__DIR__ . '/src/in.php'); $obfuscator->obfuscateFileTo(__DIR__ . '/src/in.php', __DIR__ . '/build/out.php'); $map = $obfuscator->getNameMap(); // [ // 'variables' => ['userName' => 'vAbCdEfG', ...], // 'functions' => [...], // 'classes' => [...], // 'methods' => [...], // 'properties' => [...], // 'constants' => [...], // ]
Options
Options is an immutable value object. All flags default to true.
| Option | Default | Description |
|---|---|---|
obfuscateVariables |
true |
Rename local variables (superglobals and $this are always preserved). |
obfuscateFunctions |
true |
Rename user-defined function declarations and their call sites. |
obfuscateClasses |
true |
Rename classes, interfaces, traits and enums and every reference to them. |
obfuscateMethods |
true |
Rename methods (magic methods such as __construct are kept untouched). |
obfuscateProperties |
true |
Rename properties, including promoted constructor parameters and static props. |
obfuscateConstants |
true |
Rename const, class constants, enum cases and define() constants. |
encodeStrings |
true |
Replace string literals with base64_decode('...') calls. |
removeComments |
true |
Strip //, # and /* ... */ comments. |
removeWhitespace |
true |
Minify whitespace. |
wrapWithEval |
true |
Wrap the final payload in <?php eval(base64_decode('...'));. |
minNameLength |
6 |
Minimum length of generated identifiers. |
maxNameLength |
12 |
Maximum length of generated identifiers. |
seed |
null |
Optional PRNG seed for deterministic, reproducible output. |
use GLOBUSstudio\PhpObfuscator\Options; $options = new Options( encodeStrings: false, wrapWithEval: false, seed: 12345, ); $options = Options::fromArray(['wrapWithEval' => false]); $options = $options->with(['seed' => 7]);
Selective obfuscation
use GLOBUSstudio\PhpObfuscator\Obfuscator; use GLOBUSstudio\PhpObfuscator\Options; // Public API stays callable from the outside while the internals are scrambled. $opts = new Options( obfuscateClasses: false, obfuscateMethods: false, obfuscateFunctions: false, ); echo (new Obfuscator($opts))->obfuscate(file_get_contents('Library.php'));
CLI
Usage: php-obfuscate [options] <input.php> [output.php]
Reads PHP source from <input.php> (or `-` for STDIN), obfuscates it and writes
the result to <output.php> (or STDOUT when omitted).
Options:
--no-eval-wrap Do not wrap output in eval(base64_decode(...))
--no-strings Skip string literal Base64 encoding
--no-minify Preserve original whitespace
--no-comments Strip comments only (default removes them)
--keep-variables Do not rename variables
--keep-functions Do not rename functions
--keep-classes Do not rename classes
--keep-methods Do not rename methods
--keep-properties Do not rename properties
--keep-constants Do not rename constants
--seed=<int> Use a deterministic PRNG seed
-h, --help Show this help text
-V, --version Print library version
Examples:
vendor/bin/php-obfuscate src/Acme/Service.php build/Service.php cat src/Acme/Service.php | vendor/bin/php-obfuscate - > build/Service.php vendor/bin/php-obfuscate --keep-classes --seed=1 src/Service.php
What is preserved by design
$thisand every PHP superglobal ($_SERVER,$_GET, ...).- Magic methods (
__construct,__toString,__invoke, ...). - Built-in PHP functions, classes, traits and interfaces. The obfuscator only renames identifiers it has previously seen declared in the input, so references to anything from the standard library or third-party packages remain untouched.
- String literals appearing in constant-expression positions (class
constants, enum case values, default parameter values, top-level
constinitializers) are never wrapped inbase64_decode(...), because PHP requires those positions to be literal expressions.
Limitations
- Namespaced symbol names that appear as
T_NAME_QUALIFIEDorT_NAME_FULLY_QUALIFIEDtokens are not rewritten. If you need to obfuscate namespaced classes, the obfuscator must be applied to a single-namespace file at a time. - The obfuscator works at the source level. It is a deterrent that raises the cost of casual reverse engineering, not a cryptographic protection. Anyone able to run your code can trivially recover the runtime behaviour.
Development
composer install vendor/bin/phpunit
The bundled CI workflow runs the test suite on Ubuntu against PHP 8.1 - 8.5.
License
MIT.