PHPackages                             kminet/php-obfuscator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. kminet/php-obfuscator

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

kminet/php-obfuscator
=====================

PHP source code obfuscator — transforms namespaces, classes, methods and variables into hashed equivalents while preserving full runtime behaviour

0.0.1(2mo ago)02LGPL-3.0-onlyPHPPHP ^8.3CI passing

Since May 22Pushed 1mo agoCompare

[ Source](https://github.com/KminekMatej/PhpObfuscator)[ Packagist](https://packagist.org/packages/kminet/php-obfuscator)[ Docs](https://github.com/KminekMatej/PhpObfuscator)[ RSS](/packages/kminet-php-obfuscator/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (12)Versions (3)Used By (0)

PhpObfuscator
=============

[](#phpobfuscator)

> **⚠️ Draft / Work in Progress** — This library is not yet production-ready. APIs, behaviour, and output format may change without notice. Use at your own risk.

A PHP code obfuscator that transforms PHP source into functionally identical but hard-to-read code. It uses a "backplate" mapping system to track original-to-obfuscated name transformations and supports multiple obfuscation levels with increasing coverage.

Requirements
------------

[](#requirements)

- PHP 8.3+
- Composer

Installation
------------

[](#installation)

PhpObfuscator can be used in three ways depending on your workflow.

### Standalone / global tool

[](#standalone--global-tool)

Install it globally and use it from anywhere on your system:

```
composer global require kminet/php-obfuscator
phpobf --level 1 src/
```

### Per-project dev dependency

[](#per-project-dev-dependency)

Install it inside your project and run it as part of your build process:

```
composer require --dev kminet/php-obfuscator
vendor/bin/phpobf --level 1 src/
```

### Cloned locally

[](#cloned-locally)

Clone the repository and run directly:

```
git clone https://github.com/KminekMatej/PhpObfuscator.git
cd php-obfuscator
composer install
bin/phpobf --level 1 /path/to/your/project
```

Usage
-----

[](#usage)

### CLI

[](#cli)

```
Arguments:
                 Path to the PHP file or directory to obfuscate

Options:
  --config         Path to a Neon config file (see Configuration below)
  --level           Obfuscation level — overrides the value in the config file
                           0 - structural only (namespaces, classes, enums)
                           1 - + methods and functions
                           2 - + variables
  --output          Output directory (default: temp/)
  --test-mode            Keep original name prefix in obfuscated names (for debugging)
  --keep-paths           Do not relocate files to obfuscated PSR-4 directory structure
  --keep-backplate-file  Save backplate.json to the output directory (default: off)
  --log-level     Log verbosity: debug, info, notice, warning, error (default: info)
  --help                 Show help message

```

Examples:

```
# Use auto-detected config, override level via CLI flag
phpobf --level 1 --test-mode src/

# Point to a custom config file
phpobf --config phpobf.json src/
```

### Configuration

[](#configuration)

PhpObfuscator is configured via a [Neon](https://ne-on.org/) file — the same format used by PHPStan. JSON is also accepted when passing a `.json` file via `--config`, which can be easier to generate from shell scripts or CI pipelines. The tool resolves the config file in this order:

1. Path given by `--config ` (explicit, highest priority)
2. `phpobf.neon` in the **current working directory** (project-level config, committed to your repo)
3. `config/phpobf.default.neon` bundled with phpobf (the built-in fallback)

CLI flags always take precedence over the config file — they override any matching key.

#### Creating a project config

[](#creating-a-project-config)

Drop a `phpobf.neon` in your project root alongside `composer.json`. PhpObfuscator picks it up automatically without any `--config` flag:

```
# Obfuscation level preset (0–2)
level: 1

obfuscatePaths: true
testMode: false
keepBackplateFile: false

features:
    namespaces: null
    classes:    null
    interfaces: null
    enums:      null
    methods:    null
    functions:  null
    constants:  null
    variables:  null
    properties: null
    comments:   null

block:
    namespaces:
    classes:
```

#### Config reference

[](#config-reference)

KeyTypeDefaultDescription`level``int` (0–2)`1`Obfuscation level. Acts as a preset — defines which features are enabled by default.`obfuscatePaths``bool``true`Relocate output files to match the obfuscated PSR-4 namespace structure.`testMode``bool``false`Prefix obfuscated names with the original (e.g. `Teacher_abc123`) for easier debugging.`keepBackplateFile``bool``false`Save `backplate.json` alongside obfuscated output. ⚠️ Never distribute this file.`features``object`*(from level)*Fine-grained feature toggles. See below.`block.namespaces``string[]``[]`Regex patterns for namespaces to skip entirely (e.g. `"/^Psr\\\\/"` preserves PSR interfaces).`block.classes``string[]``[]`Regex patterns for class names to skip entirely.#### Feature flags

[](#feature-flags)

The `features` object lets you override individual obfuscation features on top of the level preset — the same way JavaScript Obfuscator handles presets. Each key accepts `true`, `false`, or `null`:

- **`null`** (default) — inherit from the level preset
- **`true`** — force this feature on, even if the level wouldn't enable it
- **`false`** — force this feature off, even if the level would enable it

FeatureLevel 0Level 1Level 2Description`comments`✓✓✓Strip all comments from source`namespaces`✓✓✓Rename namespace declarations`classes`✓✓✓Rename class, interface, and enum names`interfaces`✓✓✓Rename interface names (subset of `classes`)`enums`✓✓✓Rename enum names (subset of `classes`)`methods`✗✓✓Rename method and function definitions and call sites`functions`✗✓✓Rename standalone function definitions and call sites`constants`✗✓✓Rename class constants and enum cases`variables`✗✗✓Rename all variables (local, global, parameters)`properties`✗✗✓Rename class property declarations and `$this->prop` accesses**Example — level 1 but without method obfuscation, and with comments preserved:**

```
level: 1

features:
    methods:  false
    comments: false
```

**Example — block PSR and Symfony namespaces from obfuscation:**

```
level: 2

block:
    namespaces:
        - /^Psr\//
        - /^Symfony\//
```

### Ignoring specific declarations

[](#ignoring-specific-declarations)

You can exclude individual PHP declarations from obfuscation using two annotations. Both work for classes, interfaces, enums, methods, functions, properties, constants, enum cases, and variables.

#### `@phpobf-ignore-line`

[](#phpobf-ignore-line)

The annotation and the declaration must be on the **exact same line**:

```
private string $apiKey; // @phpobf-ignore-line
public function getToken(): string { ... } // @phpobf-ignore-line external API contract
```

#### `@phpobf-ignore-next-line`

[](#phpobf-ignore-next-line)

The annotation must be on the line **immediately before** the declaration:

```
// @phpobf-ignore-next-line
private string $apiKey;

// @phpobf-ignore-next-line required by external contract
public function getToken(): string { ... }

/* @phpobf-ignore-next-line */
const VERSION = '1.0.0';
```

An optional reason can follow either annotation — it is recorded in `backplate.json` alongside the `ignored: true` flag for traceability. Both `//` and `/* */` comment styles are supported.

> **Note:** Ignoring a class does not automatically ignore its methods or properties. Each declaration must be annotated individually if you want to exclude multiple members.

### In-code API

[](#in-code-api)

The obfuscator can also be used programmatically via the fluent builder API:

```
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use PhpObfuscator\Obfuscator\Obfuscator;

$logger = (new Logger('phpobf'))->pushHandler(new StreamHandler('php://stdout'));

$obf = new Obfuscator(outputDir: '/path/to/output');
$obf->setLogger($logger);
$obf->setSource('/path/to/your/project')
    ->setLevel(1)
    ->setTestMode(false)
    ->setObfuscatePaths(true)
    ->obfuscate();
```

The obfuscator uses a [PSR-3](https://www.php-fig.org/psr/psr-3/) `LoggerInterface` — any compliant logger works. When no logger is set, log output is silently discarded. The CLI entry point wires up a [Monolog](https://github.com/Seldaek/monolog) logger with colour-coded output automatically.

### API Reference

[](#api-reference)

MethodDefaultDescription`setSource(string $source)`*(required)*Path to the PHP file or directory to obfuscate. Directories are scanned recursively.`setLevel(int $level)``0`Obfuscation level (0–2). See below.`setTestMode(bool $testMode)``false`When `true`, obfuscated names are prefixed with the original (e.g. `Teacher_abc123`) for easier debugging.`setObfuscatePaths(bool $obfuscatePaths)``true`When `true`, files are relocated to match the obfuscated namespace directory structure.`setKeepBackplateFile(bool $keep)``false`When `true`, saves `backplate.json` to the output directory alongside obfuscated sources.`setLogger(LoggerInterface $logger)`*(none)*Attach a PSR-3 logger for progress and diagnostic output.`new Obfuscator(outputDir: $dir)``temp/{id}/`Custom output directory. Defaults to `temp/{obfuscationId}/` relative to the library root.### Obfuscation Levels

[](#obfuscation-levels)

Levels are stacked — each level applies everything from the previous levels plus its own transformations.

---

**Level 0** — Structural obfuscation (namespaces, classes, interfaces, enums)

- Renames all namespace declarations to hashed equivalents
- Renames all class, interface, and enum names to hashed equivalents
- Rewrites all fully-qualified references (type hints, `new` expressions, static calls) to match
- Removes `use` statements in production; rewrites them to obfuscated FQCNs in test mode
- Strips all comments
- Relocates files to match the obfuscated PSR-4 directory structure (when `setObfuscatePaths(true)`)
- Skips any class or namespace matched by the block list (e.g. `/^Psr/`)

```
// Input
namespace App\Service;
use App\Model\User;

// Creates a user
class UserService {
    public function create(User $user): void {}
}

// Output
namespace aB3kQz\xR9mLp;

class fT7wNq {
    public function create(\aB3kQz\qP2vYm $user): void {}
}
```

---

**Level 1** — Method &amp; function obfuscation (everything from Level 0, plus):

- Renames method definitions to hashed equivalents (magic methods like `__construct` are always skipped)
- Rewrites instance method calls (`$obj->method()`) by resolving the receiver's type via PHPStan inference, AST walking for chained `new` expressions, or `$this` class reflection
- Rewrites static method calls (`Foo::method()`) using the fully-qualified class name
- Renames standalone function definitions and their call sites
- Leaves a method call unobfuscated (with a warning) if the receiver type cannot be resolved (union types, mixed, or dynamic dispatch `$obj->$method()`)

```
// Input
namespace App\Service;

function helperFn(): void {}

class UserService {
    public function create(User $user): void {
        $this->validate($user);
    }
    private function validate(User $user): void {}
}

$service = new UserService();
$service->create(new User());
helperFn();
UserService::staticMethod();

// Output (methods and functions renamed on top of Level 0 structural obfuscation)
namespace aB3kQz\xR9mLp;

function kQ8mZp(): void {}

class fT7wNq {
    public function nX4vRt(\aB3kQz\qP2vYm $user): void {
        $this->pL6hWs($user);
    }
    private function pL6hWs(\aB3kQz\qP2vYm $user): void {}
}

$service = new fT7wNq();
$service->nX4vRt(new \aB3kQz\qP2vYm());
kQ8mZp();
fT7wNq::mR2jYk();
```

---

**Level 2** — Variable &amp; property obfuscation (everything from Level 1, plus):

- Renames all variables (local, global, function parameters) to hashed equivalents
- Renames class property declarations (`private string $name` → `private string $xR9mLp`)
- Renames `$this->property` access expressions to match
- Skips `$this` and all PHP superglobals (`$_SERVER`, `$_GET`, `$_POST`, `$_COOKIE`, `$_FILES`, `$_SESSION`, `$_REQUEST`, `$_ENV`, `$GLOBALS`)
- Throws a `ScopeResolutionException` and aborts the file if a dynamic variable-variable (`$$var`) is encountered, as its runtime name cannot be statically determined
- Property accesses on non-`$this` receivers (e.g. `$obj->name`) are intentionally skipped — resolving the owner class without full type inference risks renaming unrelated properties that share the same name across different classes

> **Note:** Because the hash is purely name-based, the same variable name always maps to the same obfuscated name everywhere it appears — across methods, closures, and arrow functions — so no per-scope tracking is required.

```
// Input
class School {
    private string $name;
    public function __construct(string $name) {
        $this->name = $name;
    }
}
$hogwarts = new School("Hogwarts");
$teacher = new Teacher("Albus", "Dumbledore");
$hogwarts->addTeacher($teacher);

// Output (variables and properties renamed on top of Level 1 obfuscation)
class fT7wNq {
    private string $xR9mLp;
    public function __construct(string $xR9mLp) {
        $this->xR9mLp = $xR9mLp;
    }
}
$nXvRtQp = new fT7wNq("Hogwarts");
$kQmZpYs = new aB3kQz("Albus", "Dumbledore");
$nXvRtQp->pL6hWs($kQmZpYs);
```

Output
------

[](#output)

Obfuscated sources are written to the output directory. A `backplate.json` file containing the full original-to-obfuscated name mapping can optionally be saved alongside the output using `--keep-backplate-file` (CLI) or `setKeepBackplateFile(true)` (API). This file is useful for correlating obfuscated symbols back to their originals (e.g. for stack trace interpretation).

> ⚠️⚠️ **Never distribute `backplate.json` with your obfuscated sources.** ⚠️⚠️
>
> The backplate is a complete reverse-mapping of every obfuscated name back to its original. Anyone with this file can trivially deobfuscate your entire codebase. Keep it private, treat it like a secret key, and delete it from the output directory before shipping.

If the source project contains a `composer.json` and `setObfuscatePaths(true)` is used, the autoloader in the output is automatically updated to use a classmap. Run `composer dump-autoload` in the output directory after obfuscation:

```
composer dump-autoload --working-dir=/path/to/output
```

License
-------

[](#license)

This project is licensed under the **GNU Lesser General Public License v3.0 (LGPL-3.0)**.

You are free to use this library in any software, including commercial and closed-source products. However, any modifications to the library itself must be published under the same LGPL-3.0 license.

See the [LICENSE](LICENSE) file for the full license text.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance89

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

65d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/16462921?v=4)[Matěj Kmínek](/maintainers/kminekmatej)[@KminekMatej](https://github.com/KminekMatej)

---

Top Contributors

[![KminekMatej](https://avatars.githubusercontent.com/u/16462921?v=4)](https://github.com/KminekMatej "KminekMatej (295 commits)")

---

Tags

phpastobfuscatortransformerobfuscationcode-protectionsource-protection

###  Code Quality

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/kminet-php-obfuscator/health.svg)

```
[![Health](https://phpackages.com/badges/kminet-php-obfuscator/health.svg)](https://phpackages.com/packages/kminet-php-obfuscator)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k16](/packages/tempest-framework)[jolicode/castor

A lightweight and modern task runner. Automate everything. In PHP.

54643.3k4](/packages/jolicode-castor)[rector/rector-src

Instant Upgrade and Automated Refactoring of any PHP code

136406.3k14](/packages/rector-rector-src)[ajthinking/archetype

Programmatically edit PHP and Laravel files.

2723.9M19](/packages/ajthinking-archetype)[atanamo/php-codeshift

A PHP code transformation toolkit based on 'PHP-Parser'

32160.3k1](/packages/atanamo-php-codeshift)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
