命令行速查,配合 README.md 一起看。
swcenc doctor
swcenc 环境自检
==================================================================
引擎根目录 : /opt/swcenc/engine
Python : 3.12.3 (/usr/bin/python3)
PHP 搜索路径: /www/server/php:/usr/local/php:/opt/php:/opt
── 本机 PHP 工具链 ──
✅ PHP 8.3 /www/server/php/83/bin/php
opcache no-debug-non-zts-20230831
...
── 各 (loader, PHP) 组合可用性 ──
PHP 3.1 3.2
----- -------------------------- --------------------------
8.3 — 官方无此 loader ✅ strong
✅ strong 表示这个组合能做字节码加密;⚠️ 仅 weak 表示本机缺 opcache。
swcenc pack <输入.php> -o <输出.php> [选项]
# 最常见:PHP 8.3 + loader 3.2 + 加固 + 验证
swcenc pack app/common.php -o out/common.php \
--php 8.3 --loader-version 3.2 --swc-strict --verify
# 老站:PHP 7.2 + loader 3.1
swcenc pack app/common.php -o out/common.php --php 7.2 --loader-version 3.1 --verify
# Pro 产物
swcenc pack app/common.php -o out/common.php --php 8.3 --pro --verify
输出文件建议不要覆盖原文件。产物已经不可读,覆盖后想改也改不回来。
swcenc batch ./app -o ./app_enc --php 8.3 --loader-version 3.2 --verify -j 8
./app/a/b.php → ./app_enc/a/b.php-j 是并发数,按 CPU 核数调。--verify 会让每个文件都跑一次 PHP,比较慢。vendor/、runtime/ 会被跳过(第三方库没必要加密,且体量大)。一个站要上多套环境时,按 (loader, PHP) 组合各跑一次:
for v in 7.4 8.0 8.1 8.2 8.3; do
swcenc batch ./app -o ./dist/php$v --php $v --loader-version 3.2 --swc-strict
done
每个组合的产物只认那一个 PHP 版本,不能混用。
swcenc info out/common.php
文件 : out/common.php
大小 : 12552 B
PHP : 7.3
loader : 3.2
模式 : strong
弱加密标记: 否
载荷 A : 11420 B
载荷 B : 0 B
Pro 层 : 是 / 否
swcenc unpack out/common.php -o payload.bin # 解出载荷(strong 模式下是字节码)
unpack 只是把容器拆开,不做反编译。strong 载荷是 op_array 字节码,需要
额外的解析工具才能读。
swcenc versions # loader 3.1 / 3.2 × PHP 支持矩阵(看本机文件)
swcenc caps # 各版本能力分层(JSON,含实测探测结果)
swcenc caps --refresh # 重新实测一遍并更新缓存
实测语料:真实 66 文件 PHP 工程(1.1 MB),PHP 8.3 / loader 3.2,40 核机器。
表里是 batch 跑完整目录的墙钟时间(取最快一次)。
| 配置 | 总耗时 | 每文件 | 相对默认 |
|---|---|---|---|
--mode weak | 0.9 s | 0.014 s | 5.9× 快 |
strong(默认,不加固) | 2.4 s | 0.036 s | 1.0×(基准) |
strong --swc-strict --verify | 32.5 s | 0.49 s | 13.8× 慢 |
strong --swc-strict | 33.0 s | 0.50 s | 14.0× 慢 |
strong --swc-strict --swc-calibrate | 33.9 s | 0.51 s | 14.4× 慢 |
strong --swc-strict --pro | 36.8 s | 0.56 s | 15.6× 慢 |
strong --swc-strict --pro --verify | 35.8 s | 0.54 s | 15.2× 慢 |
strong --swc-strict --swc-encode-ops | 67.2 s | 1.02 s | 28.6× 慢 |
结论:
weak 最快,比 strong 快约 6 倍 —— 它不做字节码编译,纯 Python 拼容器。代价是载荷就是源码,只有形式上的保护。
--swc-strict)是真正的开销大头,约 14 倍。它要做 opdump 转储 + CV 名洗白 + 逐文件探针验证,值不值看你自己的威胁模型。
--pro 在加固之上只多约 10%(置换 + 掩码是纯查表,很便宜)。--verify 几乎是免费的 —— 加固通路本来就每文件跑一次探针,多执行一次产物几乎不增加时间。强烈建议开。
--swc-encode-ops 再翻一倍,是因为它要重写整个 opcode 表。-j 1 | -j 2 | -j 4 | -j 8 | |
|---|---|---|---|---|
strong(不加固) | 5.15 s | 3.22 s | 2.34 s | 1.81 s |
strong --swc-strict | 26.3 s | 31.0 s | 31.8 s | 33.7 s |
原因:strong 的耗时几乎全在等 PHP 子进程(opcache 编译),线程能重叠这段等待;
而加固通路的耗时是纯 Python 字节操作,被 GIL 串行化,多开线程只剩上下文切换开销。
所以 batch 的 -j 默认是自动的:
min(8, CPU 核数)--swc-strict / --pro / --swc-encode-ops / --swc-calibrate)→ 1显式给 -j N 时一律听你的。如果你在跑加固,别手动加 -j,默认的 1 就是最快的。
每个文件都有一次 Python + PHP 启动成本,小文件尤其明显:
| 每次耗时(913 B 小文件) | |
|---|---|
--mode weak | 0.159 s |
strong | 0.240 s |
所以批量走 batch,不要循环调用 pack:66 个文件循环调用要 34.9 s,
batch 只要 2.4 s(strong)。
| 场景 | 建议 |
|---|---|
| 一般交付 | --swc-strict --verify |
| 要跟官方 swc 产物观感一致 | 再加 --swc-calibrate(慢) |
| 只想先跑通 | 什么都不加,先确认产物能起来 |
| 要更强的逆向门槛 | 加 --pro,同时把目标机的 loader 换成 Pro 版 |
--swc-encode-ops | ⚠ 目前无效,别指望它(见下) |
--swc-repoint | ⚠ 实验性,默认关闭 |
--swc-encode-ops 当前是空操作这一层(编码态 op + 函数名字面量加密)目前一个 op 都编不上,实测 66 文件
真实项目:编码 0 个。原因有两层:
pack/newgen_<php><loader>.json 里的 encoded 条目只有 5–13 条,而真实调用序列还需要 SEND_VAR / DO_FCALL 等形状 —— 序列永远配不平,
于是调用序列门禁(newgen72.sequence_gate)放行 0 个;
尚未定位。所以门禁是故意不编的:宁可不生效,也不产出会崩的产物。
开着不会出错,但不要把它算作一层保护。 工具在收尾时会明确告诉你
"本次 --swc-encode-ops 没有生效",不会让你误以为多了一层。
要真实强度请用 --swc-strict + --pro。
--swc-repoint 是实验特性字面量槽重定位加密函数名:机制单独验证过,但与「去掉名字门禁」组合时大文件
未通过自检,因此默认关闭。不确定就不要开。
set -e
SRC=./app
OUT=./dist
PHP=8.3
LV=3.2
# 1) 自检
swcenc doctor
# 2) 加密(加固 + 验证)
swcenc batch "$SRC" -o "$OUT/php$PHP" \
--php "$PHP" --loader-version "$LV" \
--swc-strict --verify -j 8
# 3) 抽查一个产物信息
swcenc info "$OUT/php$PHP/index.php"
# 4) 在目标机上装对应 loader(不要装错代次 / 版本)
# php.ini: extension=swoole_loader${PHP/./}_nts.so
# 然后重启 PHP-FPM
# 5) Pro 产物额外确认 php.ini 里有:
# swoole_loader_pro.enable_vm_hybrid=1
Q:加密后能不能改源码?
不能。改源码必须改明文再重新加密。
Q:能不能一个产物跑多个 PHP 版本?
不能,Swoole 是单版本加密。要支持 5 个 PHP 版本就出 5 份。
Q:目标机需要装什么?
只要对应版本的 loader 扩展。
Q:产物会不会回连某个服务器?
不会。本工具完全离线,不做域名/IP 绑定、不联网校验。
Q:--verify 安全吗?
它会真的执行被加密的文件(用 loader 加载并运行)。只对你自己的、可信的
源码使用;不要拿它验证来路不明的文件。
Q:产物比源码大还是小?
通常更大 —— 字节码载荷里有常量表、字面量和元信息,加固层还要再叠数据。
这是正常的。
Q:报"源码语法检查失败"?
源码在目标 PHP 版本下语法不合法。常见:7.x 用了类型化属性(要 7.4+)、
match(要 8.0+)、new ('...')(要 8.0+)。换 --php 或改源码。
swcenc machine # 本机机器码 → 发给签发者
swcenc license # 查看授权(客户名 / 版本 / 有效期 / 功能位)
swcenc pack a.php -o a.enc.php --license /path/to/license.json
没有有效授权时 pack / batch 会直接退出(退出码 3),并在 stderr 说明原因
(未找到 / 签名不匹配 / 已过期 / 机器码不匹配)。
| 能力 | Linux | Windows |
|---|---|---|
pack / batch / info / machine / license / doctor | ✅ | ✅ |
--verify(用真实 loader 跑一遍产物) | ✅ | ❌ loader 是 Linux 扩展,Windows 的 PHP 加载不了 |
| 产物绑定(域名 / IP / 到期) | ✅ | ✅ 一样 |
--pro / --swc-strict(加固层) | ✅ 全部 PHP 版本 | ⚠ 只支持 PHP 7.0 / 7.1(7.2+ 需要 Linux 专有的转储扩展) |
所以:在 Windows 上出普通 strong 产物完全没问题(绑定、授权、多版本都正常);
要出加固/Pro 产物、或者要逐文件 --verify,请到 Linux 上打包 —— 那边的组合是完整的。
# 只允许 customer.com 及其子域运行,2027-01-01 到期
swcenc batch ./app -o ./app_enc --php 8.3 \
--domains "customer.com,*.customer.com" --expire 2027-01-01
# 再加来访 IP 白名单
swcenc pack app.php -o app.enc.php --php 8.3 --ips "1.2.3.4,10.0.0.0/8"
# 连 CLI 一起绑域名(默认只绑 Web,避免客户 cron 挂掉)
swcenc pack app.php -o app.enc.php --php 8.3 --domains "a.com" --bind-cli
命中不允许的环境时:
$ php app.enc.php
This script is not licensed to run here (host evil.com). # Web 上是 403
swcenc doctor | head -12 # 看「内置运行时」那一行
发行包自带 PHP 7.0–8.4 与 Python;SWCENC_PHP_ROOT / SWC_PHP_ROOT 可以指向
系统里别的 PHP(例如客户机上已经装了他自己那套):
SWC_PHP_ROOT=/www/server/php swcenc doctordocs/USAGE.md)。
下载发行包后可离线查看同样的内容。