phar无法对可执行文件打包,打包后php调用exec()函数访问不到该可执行文件。
第三方提供了一个编译后的C++可执行文件AServer
,我需要使用php执行这个文件,未打包前是可以正常执行的,但是打包后,exec()函数就不能访问这个可执行文件了,webman控制台提示
sh: 1: phar:///code/webman-project-v1.0.phar/app/bin/AServer: not found
刚开始怀疑AServer
未被打包进app/bin/
目录下,但是查看webman-project-v1.0.phar
包内容,发现是有这个文件的,是由于phar打包底层的问题,还是没有执行权限?,应该怎么解决呢?
$command = app_path() . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'AServer';
exec($command, $output);
打包配置config/plugin/webman/console/app.php
return [
'enable' => true,
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman-project-' . env('VERSION', '0.0') . '.phar',
'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.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
'exclude_files' => [
'.env.example', 'LICENSE', 'composer.json', 'composer.lock', 'start.php'
]
];
感谢@fuzqing老哥提出的解决方案,现在整理成以下:
xxx.phar
文件相对目录中Phar::running()
方法可以判断出当前环境是是否在phar
中phar
与非phar
中的逻辑support/helpers.php
中增加bin_path()函数,用来区分phar环境与非phar环境
/**
* 获得脚本运行路径
* 如果是在phar中,则将phar同级路径下runtime/bin/目录作为脚本执行路径
* 若果在非phar中,则将app/bin/目录作为脚本执行路径
* @return false|string
*/
function bin_path()
{
return is_phar() ? runtime_path() . DIRECTORY_SEPARATOR . 'bin' : realpath(app_path() . DIRECTORY_SEPARATOR .'bin');
}
增加方法,在需要的地方执行,若phar环境下,需要拷贝执行文件到runtime/bin/目录下
/**
* 生成phar环境下所需二进制文件
*/
protected function genderBinaryForPhar(): void
{
// phar环境下
if (is_phar()) {
// 原路径
$sourceBinaryPath = app_path() . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'AServer';
// 目标路径
$targetBinaryPath = bin_path() . DIRECTORY_SEPARATOR . 'AServer';
// 生成所需二进制文件
if (!file_exists($targetBinaryPath) && file_exists($sourceBinaryPath)) {
$targetDirectory = dirname($targetBinaryPath);
if (!is_dir($targetDirectory)) {
mkdir($targetDirectory);
}
copy($sourceBinaryPath, $targetBinaryPath);
chmod($this->genderCommand, 644);
}
}
}