最近尝试webman
的二进制打包,确实很方便,但是也出现了一些问题。
比如:使用phinx
数据库迁移,多语言,上传文件至public目录等,目前我遇到的都是资源读取问题。
这些问题解决非常简单,常常只需要将配置项的base_path()
变成base_path(false)
然后将目录拷贝至webman.bin
同目录就能解决,其他错误情况也类似,不过对部署上线就非常麻烦了。
通过编写一个自定义命令行可以轻松解决这个问题。
composer require webman/console ^1.2.24
php webman make:command custom:build:bin
目前只简单实现目录copy,将打包结果压缩成zip,方便分发和部署,其他需求可自行修改扩展。
<?php
namespace app\command;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use Webman\Console\Commands\BuildBinCommand;
use ZipArchive;
class CustomBuildBinCommand extends Command
{
protected static $defaultName = 'custom:build:bin';
protected static $defaultDescription = 'Custom build bin';
/**
* @return void
*/
protected function configure(): void
{
$this->addArgument('version', InputArgument::OPTIONAL, '打包的PHP版本', '8.1');
$this->addArgument('zip', InputArgument::OPTIONAL, '是否将打包输出目录压缩', 0);
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
// 是否将打包输出目录压缩
$zip = $input->getArgument('zip');
// 打包输出目录
$buildDir = config('plugin.webman.console.app.build_dir', base_path() . '/build');
$output->writeln('<comment>正在打包...</comment>');
// 调用打包bin命令
$command = new BuildBinCommand();
$command->execute($input, $output);
$output->writeln('<comment>复制目录...</comment>');
// 复制db目录 phinx数据库迁移
$this->copyDirectory(base_path() . '/db', $buildDir . '/db');
// 复制public目录(如果需要读取里面的资源)
$this->copyDirectory(base_path() . '/public', $buildDir . '/public');
// 复制resource目录(使用多语言)
$this->copyDirectory(base_path() . '/resource', $buildDir . '/resource');
$output->writeln('<info>复制完毕</info>');
if ($zip) {
$output->writeln('<comment>压缩中...</comment>');
$zipFilename = $buildDir . '/build.zip';
// 删除之前的压缩包
if (file_exists($zipFilename)) {
unlink($zipFilename);
}
// 压缩目录并跳过非必要的文件
$this->zipDirectory($buildDir, $zipFilename, [
'*.zip',
'*.sfx',
'*.phar',
'.env'
]);
$output->writeln('<info>压缩完成! ' . $zipFilename . '</info>');
}
$output->writeln('<info>打包完成!</info>');
return self::SUCCESS;
}
/**
* 拷贝目录 包含子目录及文件
* @param $src
* @param $dst
* @return false|void
*/
protected function copyDirectory($src, $dst)
{
$dir = opendir($src);
if (!$dir) {
return false;
}
if (!is_dir($dst)) {
mkdir($dst, 0755, true);
}
while (false !== ($file = readdir($dir))) {
if (($file != '.') && ($file != '..')) {
$srcFile = $src . '/' . $file;
$dstFile = $dst . '/' . $file;
if (is_dir($srcFile)) {
// 递归调用自身,拷贝子目录
$this->copyDirectory($srcFile, $dstFile);
} else {
// 拷贝文件
copy($srcFile, $dstFile);
}
}
}
closedir($dir);
}
/**
* zip压缩目录
* @param $source
* @param $destination
* @param array $exclude
* @return bool
*/
protected function zipDirectory($source, $destination, array $exclude = []): bool
{
$zip = new ZipArchive();
if (!$zip->open($destination, ZipArchive::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = str_replace('\\', '/', $file);
$fileName = basename($file);
if ($fileName == '.' || $fileName == '..') {
continue;
}
echo "Source: $source, File: $file\n";
// Skip excluded files and dirs
$skip = false;
foreach ($exclude as $pattern) {
if (fnmatch($pattern, $file)) {
$skip = true;
break;
}
}
if ($skip) {
echo "Skipping: $file\n";
continue;
}
$file = realpath($file);
if (is_dir($file) === true) {
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
} else if (is_file($file) === true) {
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
} else if (is_file($source) === true) {
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
}
打包php8.1版本,并将打包结果压缩zip:
php -d phar.readonly=0 webman custom:build:bin 8.1 true
打包完成后在输出目录会看到一个build.zip
压缩包。