kminet/php-obfuscator 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

kminet/php-obfuscator

最新稳定版本:0.0.1

Composer 安装命令:

composer require kminet/php-obfuscator

包简介

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

README 文档

README

⚠️ 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

  • PHP 8.3+
  • Composer

Installation

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

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

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

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

CLI

Arguments:
  <source>               Path to the PHP file or directory to obfuscate

Options:
  --config <file>        Path to a Neon config file (see Configuration below)
  --level <0-2>          Obfuscation level — overrides the value in the config file
                           0 - structural only (namespaces, classes, enums)
                           1 - + methods and functions
                           2 - + variables
  --output <dir>         Output directory (default: temp/<id>)
  --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 <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

PhpObfuscator is configured via a Neon 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 <file> (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

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

Key Type Default Description
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

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
Feature Level 0 Level 1 Level 2 Description
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

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

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

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

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 LoggerInterface — any compliant logger works. When no logger is set, log output is silently discarded. The CLI entry point wires up a Monolog logger with colour-coded output automatically.

API Reference

Method Default Description
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

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 & 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 & property obfuscation (everything from Level 1, plus):

  • Renames all variables (local, global, function parameters) to hashed equivalents
  • Renames class property declarations (private string $nameprivate 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

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

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 file for the full license text.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: LGPL-3.0-only
  • 更新时间: 2026-06-11

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固