diff --git a/src/Commands/BuildBinCommand.php b/src/Commands/BuildBinCommand.php index a00ebef..d073051 100644 --- a/src/Commands/BuildBinCommand.php +++ b/src/Commands/BuildBinCommand.php @@ -11,6 +11,14 @@ #[AsCommand('build:bin', 'build bin')] class BuildBinCommand extends BuildPharCommand { + protected string $binFileName; + + public function __construct() + { + parent::__construct(); + $this->binFileName = config('plugin.webman.console.app.bin_filename', 'webman.bin'); + } + /** * @return void */ @@ -37,16 +45,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $version = max($version, 8.1); $supportZip = class_exists(ZipArchive::class); $microZipFileName = $supportZip ? "php$version.micro.sfx.zip" : "php$version.micro.sfx"; - $pharFileName = config('plugin.webman.console.app.phar_filename', 'webman.phar'); - $binFileName = config('plugin.webman.console.app.bin_filename', 'webman.bin'); - $this->buildDir = config('plugin.webman.console.app.build_dir', base_path() . '/build'); $customIni = config('plugin.webman.console.app.custom_ini', ''); - $binFile = "$this->buildDir/$binFileName"; - $pharFile = "$this->buildDir/$pharFileName"; - $zipFile = "$this->buildDir/$microZipFileName"; - $sfxFile = "$this->buildDir/php$version.micro.sfx"; - $customIniHeaderFile = "$this->buildDir/custominiheader.bin"; + $binFile = $this->buildDir. DIRECTORY_SEPARATOR . $this->binFileName; + $pharFile = $this->buildDir . DIRECTORY_SEPARATOR . $this->getPharFileName(); + $zipFile = $this->buildDir. DIRECTORY_SEPARATOR . $microZipFileName; + $sfxFile = $this->buildDir. DIRECTORY_SEPARATOR . "php$version.micro.sfx"; + $customIniHeaderFile = $this->buildDir. DIRECTORY_SEPARATOR . "custominiheader.bin"; // 打包 $command = new BuildPharCommand(); @@ -137,7 +142,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // 添加执行权限 chmod($binFile, 0755); - $output->writeln("\r\nSaved $binFileName to $binFile\r\nBuild Success!\r\n"); + $output->writeln("\r\nSaved $this->binFileName to $binFile\r\nBuild Success!\r\n"); return self::SUCCESS; } diff --git a/src/Commands/BuildPharCommand.php b/src/Commands/BuildPharCommand.php index 7866d5c..be38415 100644 --- a/src/Commands/BuildPharCommand.php +++ b/src/Commands/BuildPharCommand.php @@ -12,12 +12,21 @@ #[AsCommand('build:phar', 'Can be easily packaged a project into phar files. Easy to distribute and use.')] class BuildPharCommand extends Command { - protected $buildDir = ''; + protected string $pharFileName; - public function __construct(?string $name = null) + protected string $buildDir; + + protected int $pharFormat; + + protected int $pharCompression; + + public function __construct() { - parent::__construct($name); - $this->buildDir = config('plugin.webman.console.app.build_dir', base_path() . '/build'); + parent::__construct(); + $this->pharFileName = config('plugin.webman.console.app.phar_filename', 'webman.phar'); + $this->buildDir = rtrim(config('plugin.webman.console.app.build_dir', base_path() . '/build'), DIRECTORY_SEPARATOR); + $this->pharFormat = config('plugin.webman.console.app.phar_format', Phar::PHAR); + $this->pharCompression = config('plugin.webman.console.app.phar_compression', Phar::NONE); } /** @@ -34,19 +43,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $phar_filename = config('plugin.webman.console.app.phar_filename', 'webman.phar'); - if (empty($phar_filename)) { - throw new RuntimeException('Please set the phar filename.'); - } - - $phar_file = rtrim($this->buildDir,DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $phar_filename; + $phar_file = $this->buildDir . DIRECTORY_SEPARATOR . $this->getPharFileName(); if (file_exists($phar_file)) { unlink($phar_file); } $exclude_pattern = config('plugin.webman.console.app.exclude_pattern',''); - $phar = new Phar($phar_file,0,'webman'); + $phar = new Phar($this->buildDir . DIRECTORY_SEPARATOR . $this->pharFileName,0 , 'webman'); + if(!str_ends_with($this->getPharFileName(), '.phar')) { + $phar = $phar->convertToExecutable($this->pharFormat, $this->pharCompression); + } $phar->startBuffering(); @@ -62,9 +69,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $private = openssl_get_privatekey(file_get_contents($private_key_file)); $pkey = ''; openssl_pkey_export($private, $pkey); - $phar->setSignatureAlgorithm($signature_algorithm, $pkey); + !$phar->getSignature() && $phar->setSignatureAlgorithm($signature_algorithm, $pkey); } else { - $phar->setSignatureAlgorithm($signature_algorithm); + !$phar->getSignature() && $phar->setSignatureAlgorithm($signature_algorithm); } $phar->buildFromDirectory(BASE_PATH,$exclude_pattern); @@ -98,6 +105,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + if ($this->pharCompression != Phar::NONE) { + $phar->addFromString('vendor/composer/ClassLoader.php', $this->getClassLoaderContents()); + $phar->addFromString('/vendor/workerman/workerman/src/Worker.php', $this->getWorkerContents()); + } $output->writeln('Files collect complete, begin add file to Phar.'); $phar->setStub("#!/usr/bin/env php @@ -111,6 +122,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Write requests to the Phar archive, save changes to disk.'); $phar->stopBuffering(); + unset($phar); return self::SUCCESS; } @@ -131,5 +143,48 @@ public function checkEnv(): void ); } } - + + public function getPharFileName(): string + { + $phar_filename = $this->pharFileName; + if (empty($phar_filename)) { + throw new RuntimeException('Please set the phar filename.'); + } + $phar_filename .= match ($this->pharFormat) { + Phar::TAR => '.tar', + Phar::ZIP => 'zip', + default => '' + }; + $phar_filename .= match ($this->pharCompression) { + Phar::GZ => '.gz', + Phar::BZ2 => '.bz2', + default => '' + }; + return $phar_filename; + } + + public function getClassLoaderContents(): string + { + $fileContents = file_get_contents(BASE_PATH . '/vendor/composer/ClassLoader.php'); + $replaceContents = <<<'PHP' + if (str_starts_with($file, 'phar://')) { + $lockFile = sys_get_temp_dir() . '/phar_' . md5($file) . '.lock'; + $fp = fopen($lockFile, 'c'); + flock($fp, LOCK_EX) && include $file; + fclose($fp); + file_exists($lockFile) && @unlink($lockFile); + } else { + include $file; + } +PHP; + return str_replace(' include $file;', $replaceContents, $fileContents); + } + public function getWorkerContents(): string + { + $fileContents = file_get_contents(BASE_PATH . '/vendor/workerman/workerman/src/Worker.php'); + $replaceContents = <<<'PHP' + static::forkOneWorkerForLinux($worker); php_sapi_name() == 'micro' && usleep(50000); + PHP; + return str_replace('static::forkOneWorkerForLinux($worker);', $replaceContents, $fileContents); + } } diff --git a/src/config/plugin/webman/console/app.php b/src/config/plugin/webman/console/app.php index 074e986..d7bf968 100644 --- a/src/config/plugin/webman/console/app.php +++ b/src/config/plugin/webman/console/app.php @@ -6,6 +6,10 @@ 'phar_filename' => 'webman.phar', + 'phar_format' => Phar::PHAR, // Phar archive format: Phar::PHAR, Phar::TAR, Phar::ZIP + + 'phar_compression' => Phar::NONE, // Compression method for Phar archive: Phar::NONE, Phar::GZ, Phar::BZ2 + 'bin_filename' => 'webman.bin', 'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.