phar无法对可执行文件打包,打包后php调用exec()函数访问不到该可执行文件

xiaopi

问题描述

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打包底层的问题,还是没有执行权限?,应该怎么解决呢?

程序片断

  • 执行AServer
    $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老哥提出的解决方案,现在整理成以下:

  • phar打包后可以把无法打包的文件、目录拷贝到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);
            }
        }
    }
588 1 0
1个回答

北月

先把二进制文件从 phar 中复制出来,放到指定位置,比如 runtime_path,然后再执行,代码如下:

function start_my_server()
{
    $server_binary_file = base_path('my-server');
    if (is_phar()) {
        $_server_binary_file = runtime_path('my-server');
        if (!file_exists($_server_binary_file)) {
            copy($server_binary_file,$_server_binary_file);
            chmod($_server_binary_file,755);
        }
        $server_binary_file = $_server_binary_file;
    }
    $command = "$server_binary_file";
    exec($command, $output);
    var_dump($output);
}
  • xiaopi 2023-01-09

    感谢提供帮助,方法可以完美解决我的问题

年代过于久远,无法发表回答
🔝