PHP Phar 打包与分发完整指南
Phar 基础概念
Phar (PHP Archive) 是 PHP 特有的归档格式,类似于 Java 的 JAR 文件,允许将整个 PHP 应用程序打包成单个文件。

创建 Phar 文件
基本配置要求
// 在 php.ini 中确保以下设置 phar.readonly = Off // 允许创建/修改 phar 文件
创建 Straw(存根)文件
<?php
// stub.php - Phar 入口文件
Phar::mapPhar('app.phar');
require 'phar://app.phar/index.php';
__HALT_COMPILER();
?>
生成 Phar 文件
<?php
// build.php - 打包脚本
$srcDir = __DIR__ . '/src';
$pharFile = 'app.phar';
// 创建 Phar 对象
$phar = new Phar($pharFile, 0, 'app.phar');
// 设置压缩格式
$phar->compressFiles(Phar::GZ);
// 或使用 BZ2 压缩
// $phar->compressFiles(Phar::BZ2);
// 开始写入文件
$phar->startBuffering();
// 设置默认的 stub,自动识别入口
$defaultStub = $phar->createDefaultStub('index.php', 'index.php');
// 添加文件
$phar->buildFromDirectory($srcDir, '/\.php$/');
// 设置存根
$phar->setStub($defaultStub);
// 添加自定义文件
$phar->addFromString('config.php', file_get_contents('config.prod.php'));
// 结束写入
$phar->stopBuffering();
echo "Phar 文件创建成功: $pharFile\n";
高级打包配置
完整打包脚本示例
<?php
// create-phar.php
class PharBuilder {
public function build() {
try {
// 检查 phar.readonly
if (ini_get('phar.readonly')) {
throw new Exception("请设置 phar.readonly = Off");
}
$pharFile = 'application.phar';
$srcDir = __DIR__ . '/app';
// 删除已存在的 phar 文件
if (file_exists($pharFile)) {
unlink($pharFile);
}
$phar = new Phar($pharFile, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_FILENAME, 'application.phar');
$phar->startBuffering();
// 添加所有 PHP 文件
$phar->buildFromDirectory($srcDir, '/\.php$/');
// 排除某些文件
$phar->delete('config.dev.php');
$phar->delete('test/');
// 添加非 PHP 文件
$phar->addFile('public/css/style.css', 'assets/style.css');
$phar->addFile('public/js/app.js', 'assets/app.js');
// 添加目录
$phar->buildFromDirectory('templates/', '/\.html$/');
// 设置文件权限
$phar['config.php']->setMetadata(['permission' => 0644]);
// 自定义 stub
$stub = $this->getCustomStub();
$phar->setStub($stub);
$phar->stopBuffering();
// 压缩所有文件
$phar->compressFiles(Phar::GZ);
echo "打包成功!文件大小: " . $this->formatSize(filesize($pharFile)) . "\n";
} catch (Exception $e) {
echo "打包失败: " . $e->getMessage() . "\n";
exit(1);
}
}
private function getCustomStub() {
return <<<STUB
<?php
// 自定义入口
Phar::mapPhar('application.phar');
// 设置常量
define('PHAR_MODE', true);
define('APP_ROOT', 'phar://application.phar/');
// 设置错误显示
error_reporting(E_ALL);
ini_set('display_errors', 0);
// 设置时区
date_default_timezone_set('Asia/Shanghai');
// 加载自动加载器
require 'phar://application.phar/vendor/autoload.php';
// 运行应用
$app = new Application();
$app->run();
__HALT_COMPILER();
STUB;
}
private function formatSize($bytes) {
$units = ['B', 'KB', 'MB', 'GB'];
$i = 0;
while ($bytes >= 1024 && $i < 3) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . $units[$i];
}
}
// 执行打包
$builder = new PharBuilder();
$builder->build();
使用 Composer 打包
<?php
// build-phar-with-composer.php
$pharFile = 'app.phar';
if (file_exists($pharFile)) {
unlink($pharFile);
}
$phar = new Phar($pharFile, 0, 'app.phar');
$phar->startBuffering();
// 添加 Composer 自动加载和项目文件
$phar->buildFromDirectory(__DIR__ . '/vendor', '/\.php$/');
$phar->buildFromDirectory(__DIR__ . '/src', '/\.php$/');
$phar->buildFromDirectory(__DIR__ . '/config', '/\.php$/');
// 添加其他资源文件
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('public')
);
foreach ($files as $file) {
if ($file->isFile()) {
$relativePath = 'public/' . $file->getBasename();
$phar->addFile($file->getPathname(), $relativePath);
}
}
// 设置存根
$stub = "#!/usr/bin/env php\n";
$stub .= $phar->createDefaultStub('bin/console');
$phar->setStub($stub);
$phar->stopBuffering();
// 压缩
$phar->compressFiles(Phar::GZ);
Phar 文件分发
命令行工具分发
# 给予执行权限 chmod +x app.phar # 直接运行 ./app.phar # 或通过 PHP 运行 php app.phar # 查看帮助 php app.phar --help
Web 应用分发
<?php
// deploy.php - 部署脚本
class PharDeployer {
public function deploy($source, $destination, $version = '1.0.0') {
// 验证 Phar 文件
if (!file_exists($source)) {
throw new Exception("源文件不存在");
}
// 验证 Phar 签名
$phar = new Phar($source);
if (!$phar->isFileFormat(Phar::PHAR)) {
throw new Exception("无效的 Phar 文件格式");
}
// 创建备份
if (file_exists($destination)) {
$backup = $destination . '.backup.' . date('YmdHis');
copy($destination, $backup);
echo "备份已创建: $backup\n";
}
// 复制文件
if (copy($source, $destination)) {
echo "部署成功! 版本: $version\n";
echo "文件大小: " . filesize($destination) . " bytes\n";
return true;
}
throw new Exception("部署失败");
}
public function verifySignature($pharFile) {
try {
$phar = new Phar($pharFile);
$signature = $phar->getSignature();
echo "签名算法: " . $signature['hash_type'] . "\n";
echo "签名哈希: " . $signature['hash'] . "\n";
return true;
} catch (Exception $e) {
echo "签名验证失败: " . $e->getMessage() . "\n";
return false;
}
}
}
// 使用示例
$deployer = new PharDeployer();
$deployer->deploy('app.phar', '/usr/local/bin/myapp', '2.0.0');
$deployer->verifySignature('app.phar');
版本管理和自动更新
<?php
// update.php - 自动更新系统
class AutoUpdater {
private $updateUrl;
private $currentVersion;
public function __construct($updateUrl, $currentVersion) {
$this->updateUrl = $updateUrl;
$this->currentVersion = $currentVersion;
}
public function checkForUpdates() {
$response = file_get_contents($this->updateUrl . '/version.json');
$versionInfo = json_decode($response, true);
if (version_compare($versionInfo['version'], $this->currentVersion, '>')) {
return [
'available' => true,
'version' => $versionInfo['version'],
'url' => $versionInfo['download_url'],
'checksum' => $versionInfo['checksum'],
'release_notes' => $versionInfo['release_notes']
];
}
return ['available' => false];
}
public function downloadUpdate($url, $expectedChecksum) {
$tempFile = tempnam(sys_get_temp_dir(), 'phar_update_');
// 下载文件
$downloaded = file_put_contents($tempFile, fopen($url, 'r'));
if ($downloaded === false) {
throw new Exception("下载失败");
}
// 验证校验和
$actualChecksum = md5_file($tempFile);
if ($actualChecksum !== $expectedChecksum) {
unlink($tempFile);
throw new Exception("校验和不匹配");
}
return $tempFile;
}
public function installUpdate($tempFile) {
$currentFile = $_SERVER['SCRIPT_FILENAME'];
// 创建备份
$backupFile = $currentFile . '.backup.' . date('YmdHis');
copy($currentFile, $backupFile);
// 替换文件
if (rename($tempFile, $currentFile)) {
echo "更新成功!旧版本备份至: $backupFile\n";
return true;
}
// 失败时恢复
copy($backupFile, $currentFile);
throw new Exception("更新失败,已恢复原文件");
}
}
// 使用示例
$updater = new AutoUpdater('https://updates.example.com', '1.0.0');
$update = $updater->checkForUpdates();
if ($update['available']) {
echo "发现新版本: {$update['version']}\n";
echo "发布说明: {$update['release_notes']}\n";
$tempFile = $updater->downloadUpdate($update['url'], $update['checksum']);
$updater->installUpdate($tempFile);
} else {
echo "当前已是最新版本\n";
}
性能优化和安全
性能优化
<?php
// 优化 Phar 文件使用
// 1. 使用 APC/OpCache
// 在 php.ini 中配置
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache=/tmp/opcache
// 2. 使用内存缓存
$pharPath = 'phar://app.phar/config.php';
if (function_exists('apc_fetch')) {
$config = apc_fetch('app_config');
if ($config === false) {
$config = require $pharPath;
apc_store('app_config', $config, 3600);
}
}
// 3. 延迟加载
class LazyLoader {
private $pharFile;
public function loadClass($className) {
$pharPath = "phar://{$this->pharFile}/{$className}.php";
if (file_exists($pharPath)) {
require $pharPath;
}
}
}
spl_autoload_register([new LazyLoader('app.phar'), 'loadClass']);
安全加固
<?php
// 添加安全检查
class PharSecurity {
public static function validatePhar($pharFile) {
// 1. 验证文件完整性
if (!self::verifyIntegrity($pharFile)) {
return "文件完整性验证失败";
}
// 2. 检查签名
$phar = new Phar($pharFile);
$signature = $phar->getSignature();
// 3. 检查是否篡改
$expectedHash = 'your_expected_hash_here';
if ($signature['hash'] !== $expectedHash) {
return "文件签名不匹配";
}
// 4. 限制执行环境
if (extension_loaded('suhosin')) {
ini_set('suhosin.executor.include.whitelist', 'phar');
}
return true;
}
public static function secureExecution() {
// 限制危险函数
$disabledFunctions = [
'exec', 'system', 'passthru',
'shell_exec', 'proc_open',
'popen', 'show_source'
];
foreach ($disabledFunctions as $function) {
if (function_exists($function)) {
// 记录或阻止
// 可以使用 disable_functions 在 php.ini 中配置
}
}
// 设置安全目录
define('PHAR_SAFE_MODE', true);
}
private static function verifyIntegrity($file) {
// 实现文件完整性检查
$checksumFile = $file . '.checksum';
if (file_exists($checksumFile)) {
$expected = file_get_contents($checksumFile);
$actual = md5_file($file);
return $expected === $actual;
}
return false;
}
}
// 使用
PharSecurity::validatePhar('app.phar');
PharSecurity::secureExecution();
自动化构建脚本
#!/bin/bash
# build.sh - 自动化打包脚本
echo "📦 开始打包 PHP Phar..."
# 检查 PHP 版本
PHP_VERSION=$(php -r "echo PHP_VERSION;")
echo "PHP 版本: $PHP_VERSION"
# 检查 phar.readonly
PHAR_READONLY=$(php -r "echo ini_get('phar.readonly');")
if [ "$PHAR_READONLY" = "1" ]; then
echo "❌ 需要设置 phar.readonly = Off"
exit 1
fi
# 清理旧文件
echo "清理旧文件..."
rm -f *.phar
rm -rf build/
# 创建构建目录
mkdir -p build
# 运行测试
echo "运行测试..."
php vendor/bin/phpunit tests/ || exit 1
# 生成文档
echo "生成文档..."
php vendor/bin/phpdoc -d src -t build/docs
# 打包 Phar
echo "打包 Phar..."
php create-phar.php
# 测试 Phar
echo "测试 Phar..."
php app.phar --version || exit 1
# 生成校验和
echo "生成校验和..."
md5sum app.phar > app.phar.md5
sha256sum app.phar > app.phar.sha256
# 复制到构建目录
cp app.phar build/
cp app.phar.md5 build/
cp app.phar.sha256 build/
echo "✅ 打包完成!"
echo "文件: app.phar"
echo "大小: $(du -h app.phar | cut -f1)"
最佳实践建议
- 版本控制:在 Phar 文件名中包含版本号
- 签名验证:使用数字签名确保文件完整性
- 自动更新:实现自动更新机制
- 兼容性测试:在不同 PHP 版本上测试
- 错误处理:完善的错误处理机制
- 日志记录:记录安装和更新日志
- 备份机制:更新时自动创建备份
这样,您就可以完整地实现 PHP 项目的 Phar 打包和分发流程了。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播