PHP原生支持PHAR但默认phar.readonly=On,需在php.ini中设为Off或通过-d参数临时关闭;打包须用startBuffering()、setStub()、stopBuffering()等步骤,并推荐签名;执行失败常因路径、扩展缺失或配置不匹配。

PHP 原生支持 PHAR,不需要额外扩展(只要不是极度古老的 PHP 5.2 以下版本),但默认 phar.readonly 是开启的,这意味着你无法在运行时动态创建或修改 PHAR 文件——这是绝大多数人打包失败的第一原因。
如何启用 PHAR 写入权限
PHAR 打包操作(比如 Phar::buildFromDirectory())本质是写文件,必须关闭只读限制。这不是代码能绕过的,得改配置:
- 在
php.ini中找到并修改:phar.readonly = Off - 如果用 CLI 运行,可临时覆盖:
php -d phar.readonly=Off script.php - Web 环境下(如 Apache + mod_php)通常不允许运行时修改该 ini 值,必须改主配置并重启服务
注意:线上环境不建议长期关闭 phar.readonly,打包应放在构建阶段(CI/CD 或本地),而非生产服务器上执行。
用 Phar::buildFromDirectory() 打包最简实践
这是最常用、最可控的打包方式,适合大多数 CLI 工具或单入口应用分发场景:
立即学习“PHP免费学习笔记(深入)”;
- 确保入口文件(如
index.php)能被正确加载:打包后需通过Phar::setStub()指定启动 stub,否则直接执行 PHAR 会报错 - 必须显式压缩前调用
Phar::startBuffering(),否则部分文件可能被跳过 - 签名是可选但强推荐的:不签名的 PHAR 在启用了
phar.require_hash=On的环境中无法执行
示例片段:
$phar = new Phar('app.phar');
$phar->startBuffering();
$phar->buildFromDirectory(__DIR__ . '/src', '/\.php$/');
$phar->setStub($phar->createDefaultStub('bin/app.php')); // 指定入口
$phar->stopBuffering();
$phar->compress(Phar::GZ); // 可选压缩
$phar->setSignatureAlgorithm(Phar::SHA256); // 必须签名才能在严格模式下运行
执行 PHAR 文件时常见的错误和对应检查点
打包成功不等于能跑起来。常见报错及定位方向:
-
PharException: unable to open file:路径中含中文、空格或符号未转义;或open_basedir限制了 PHAR 所在目录 -
require(): Failed opening required 'phar://...':PHAR 里引用的相对路径(尤其require)在打包后失效;应统一用__DIR__或Phar::running(true)动态计算根路径 -
Invalid signature:签名算法与phar.require_hash配置不匹配;检查 php.ini 中是否设为Off,或改用Phar::MD5(兼容性更好) - CLI 下能跑,Web 下 500:多数因 Web SAPI 禁用了
phar.stream_wrapper,确认extension=phar.so已加载且未被 disable_functions 拦截
PHAR 分发要注意的“隐形依赖”
PHAR 把代码打成一个文件,但不会自动打包 PHP 扩展、INI 设置或外部二进制依赖:
- 如果代码依赖
ext-curl或ext-mbstring,必须在文档里明确写出,PHAR 本身不校验这些 - INI 配置如
date.timezone、memory_limit仍由运行环境决定,PHAR 无法覆盖 - 想让 PHAR 自带 vendor?可以,但
buildFromDirectory()要包含vendor/,且 Composer autoloader 需用classmap或提前生成静态加载器,避免 runtime 解析失败
真正麻烦的从来不是打包动作本身,而是搞清你的应用在脱离原始目录结构后,哪些路径、哪些扩展、哪些配置还成立——PHAR 不是黑盒,它只是把问题从“部署多个文件”转移到了“验证单个文件的运行契约”。



















