php-phar打包避坑指南2025

有很多php脚本工具都是打包成phar形式,使用起来就很方便,那么如何自己做一个呢?也找了很多文档,也遇到很多坑,这里就来总结一下

phar安装

现在直接装yum php-cli包就有phar文件,很方便

可通过phar help查看帮助

重要修改:

php配置文件中

;phar.readonly = On

一定要改成

phar.readonly = Off

phar简单打包

先打包跟简单的单文件

先写一个简单的index.php文件

<?php
echo "HelloWorld\n";

打包

phar pack -f helloworld.phar -c gz -b '#!/usr/bin/php'  index.php 

参数说明

选中描述
-f指定生成的phar文件名
-c指定压缩算法
-b在首行添加内容(可直接执行类似于sh)(单文件时未生效)

执行

php helloworld.phar 

则会输出helloworld

如果文件名不是index.php呢?

[root@localhost test]# phar pack -f helloworld.phar -c gz -b '#!/usr/bin/php' helloworld.php
helloworld.php
[root@localhost test]# php helloworld.phar 
PHP Warning:  include(phar:///tmp/test/helloworld.phar/index.php): Failed to open stream: phar error: "index.php" is not a file in phar "/tmp/test/helloworld.phar" in /tmp/test/helloworld.phar on line 9
PHP Warning:  include(): Failed opening 'phar:///tmp/test/helloworld.phar/index.php' for inclusion (include_path='phar:///tmp/test/helloworld.phar:.:/opt/remi/php83/root/usr/share/pear:/opt/remi/php83/root/usr/share/php:/usr/share/pear:/usr/share/php') in /tmp/test/helloworld.phar on line 9
[root@localhost test]# 

打包虽然没报错,但运行找不到index.php文件

通过查看help,看到可以使用-s设置启动文件(使用-s时,后面...文件中可省略该文件,但单文件种情况还是要把单文件加上)

满怀期待的你是不是跃跃欲试了??

root@localhost test]# phar pack -f helloworld.phar -s helloworld.php
PHP Fatal error:  Uncaught PharException: illegal stub for phar "/tmp/test/helloworld.phar" (__HALT_COMPILER(); is missing) in phar:///opt/remi/php83/root/usr/bin/phar.phar/pharcommand.inc:534
Stack trace:
#0 phar:///opt/remi/php83/root/usr/bin/phar.phar/pharcommand.inc(534): Phar->setStub()
#1 phar:///opt/remi/php83/root/usr/bin/phar.phar/pharcommand.inc(592): PharCommand->phar_set_stub_begin()
#2 phar:///opt/remi/php83/root/usr/bin/phar.phar/clicommand.inc(87): PharCommand->cli_cmd_run_pack()
#3 /opt/remi/php83/root/usr/bin/phar.phar(52): CLICommand->__construct()
#4 {main}thrown in phar:///opt/remi/php83/root/usr/bin/phar.phar/pharcommand.inc on line 534
[root@localhost test]# 

哈哈报错了

注意-s指定的文件行尾必须要加上__HALT_COMPILER()

helloworld.php代码如下

<?php
echo "Hello Wolrd\n";
__HALT_COMPILER();
[root@localhost test]# phar pack -f helloworld.phar -s helloworld.php helloworld.php
helloworld.php
[root@localhost test]# php helloworld.phar 
Hello Wolrd
[root@localhost test]# 

打包通过运行成功

phar多文件打包

比较单文件打包,坑点比较多,最大的问题是路径问题

先写2个文件

├── helloworld.php
├── lib
│   └── app.php
└── start.php
<?php
//helloworld.php
include __DIR__ . '/lib/app.php';
echo "DIR:" . __DIR__ . "\n";
echo "FILE:" . __FILE__ . "\n";
$app = new app();
$app->show();
echo "HelloWorld\n";
<?php
//lib/app.php
class app {function show() {echo "AppName:" . __CLASS__ . "\n";echo "AppFunc:" . __FUNCTION__ . "\n";echo "AppDir:" . __DIR__ . "\n";echo "AppFile:" . __FILE__ . "\n";}
}

不建议直接改helloworld.php,要改的很多,不是简单的添加__HALT_COMPILER(); 

不死心的小伙伴可以试试

强烈建议重新写一个启动文件

这里经过不断尝试整理出来比较简单的写法,模板化,后面完全可以全部套用

<?php
//start.php
//工作目录切换到文件所在目录,否则不在文件目录执行会报错
chdir(__DIR__);
//Phar::mapPhar();这样也能通过
Phar::mapPhar("helloworld.phar");
//只能用phar路径,否则不通过
require_once 'phar://helloworld.phar/helloworld.php';
//必须要加,否则stub-set会报错
__HALT_COMPILER(); 
[root@localhost test]# phar pack -f bin/helloworld.phar -c gz -b '#!/usr/bin/php' -s start.php helloworld.php lib/app.php
helloworld.php
lib/app.php
[root@localhost test]# chmod a+x bin/helloworld.phar 
[root@localhost test]# ./bin/helloworld.phar 
DIR:phar:///tmp/test/bin/helloworld.phar
FILE:phar:///tmp/test/bin/helloworld.phar/helloworld.php
AppName:app
AppFunc:show
AppDir:phar:///tmp/test/bin/helloworld.phar/lib
AppFile:phar:///tmp/test/bin/helloworld.phar/lib/app.php
HelloWorld
[root@localhost test]# 

多文件的-b参数就有效果

特别注意,如果有多级目录不能只写目录名,否则路径就会不对(-s文件可在文件列表中省略)

-s start.php helloworld.php lib/app.php

支持匹配写法

-s start.php *.php lib/*.php

下面这种绝对不行,虽然help中说可以是目录名

[root@localhost test]# phar pack -f bin/helloworld.phar -c gz -b '#!/usr/bin/php' -s start.php helloworld.php lib
helloworld.php
app.php
[root@localhost test]# ./bin/helloworld.phar 
PHP Parse error:  Unclosed '{' on line 4 in phar:///tmp/test/bin/helloworld.phar/lib/app.php on line 6
[root@localhost test]# 

文件直接找不到了,看打包时的文件名就可以看出,文件路径就不对了

Phar其它注意点

从上面的dir输出就可以看到,里面文件或目录都是一种虚拟路径,

实际过程中涉及到的文件及目录操作都需要特殊注意

坑爹示范

//helloworld.php
include __DIR__ . '/lib/app.php';
echo "DIR:" . __DIR__ . "\n";
echo "FILE:" . __FILE__ . "\n";
echo "PharTrue:" . Phar::running(true) . "\n";
echo "PharFalse:" . Phar::running(false) . "\n";
echo "CWD:" . getcwd() . "\n";
$app = new app();
$app->show();
echo "HelloWorld\n";
$filename=__DIR__."/aaa.txt";
file_put_contents($filename, "HelloWorld");
<?php//lib/app.php
class app {function show() {echo "AppName:" . __CLASS__ . "\n";echo "AppFunc:" . __FUNCTION__ . "\n";echo "AppDir:" . __DIR__ . "\n";echo "AppFile:" . __FILE__ . "\n";echo "AppPharTrue:" . Phar::running(true) . "\n";echo "AppPharFalse:" . Phar::running(false) . "\n";echo "AppCWD:" . getcwd() . "\n";$filename = __DIR__ . "/bbb.txt";file_put_contents($filename, "HelloWorld");}}

使用了file_put_contents

不打包应该这样

[root@localhost test]# php helloworld.php
DIR:/tmp/test
FILE:/tmp/test/helloworld.php
PharTrue:
PharFalse:
CWD:/tmp/test
AppName:app
AppFunc:show
AppDir:/tmp/test/lib
AppFile:/tmp/test/lib/app.php
AppPharTrue:
AppPharFalse:
AppCWD:/tmp/test
HelloWorld

打包后第一次看着通过(有的会报错)

[root@localhost test]# phar pack -f helloworld.phar -c gz -b '#!/usr/bin/php' -a helloworld.phar -s start.php helloworld.php lib/app.php
helloworld.php
lib/app.php
[root@localhost test]# phar list helloworld.phar
Unexpected default arguments to command list, check /usr/bin/phar help
[root@localhost test]# phar list -f helloworld.phar
|-phar:///tmp/test/helloworld.phar/helloworld.php
\-phar:///tmp/test/helloworld.phar/lib\-phar:///tmp/test/helloworld.phar/lib/app.php
[root@localhost test]# php helloworld.phar
DIR:phar:///tmp/test/helloworld.phar
FILE:phar:///tmp/test/helloworld.phar/helloworld.php
PharTrue:phar:///tmp/test/helloworld.phar
PharFalse:/tmp/test/helloworld.phar
CWD:/tmp/test
AppName:app
AppFunc:show
AppDir:phar:///tmp/test/helloworld.phar/lib
AppFile:phar:///tmp/test/helloworld.phar/lib/app.php
AppPharTrue:phar:///tmp/test/helloworld.phar
AppPharFalse:/tmp/test/helloworld.phar
AppCWD:/tmp/test
HelloWorld

 第一次运行看着正常

[root@localhost test]# phar list -f helloworld.phar
|-phar:///tmp/test/helloworld.phar/aaa.txt
|-phar:///tmp/test/helloworld.phar/helloworld.php
\-phar:///tmp/test/helloworld.phar/lib|-phar:///tmp/test/helloworld.phar/lib/app.php\-phar:///tmp/test/helloworld.phar/lib/bbb.txt
[root@localhost test]# php helloworld.phar
PHP Notice:  require_once(): zlib: data error in /tmp/test/helloworld.phar on line 8
PHP Warning:  require_once(phar://helloworld.phar/helloworld.php): Failed to open stream: phar error: internal corruption of phar "/tmp/test/helloworld.phar" (actual filesize mismatch on file "helloworld.php") in /tmp/test/helloworld.phar on line 8
PHP Fatal error:  Uncaught Error: Failed opening required 'phar://helloworld.phar/helloworld.php' (include_path='.:/opt/remi/php83/root/usr/share/pear:/opt/remi/php83/root/usr/share/php:/usr/share/pear:/usr/share/php') in /tmp/test/helloworld.phar:8
Stack trace:
#0 {main}thrown in /tmp/test/helloworld.phar on line 8
[root@localhost test]# 

但在看文件列表,多了aaa.txt和bbb.txt

并且再运行直接报错了

注意Phar::running(true)的返回

解决方式

如果未使用则返回空,可以根据这个来处理文件名

        $filename = __DIR__ . "/bbb.txt";if (!empty(Phar::running(true))) {$filename = str_replace(Phar::running(true), getcwd(), $filename);if(!file_exists(dirname($filename))){mkdir(dirname($filename), 0777, true);}}file_put_contents($filename, "HelloWorld");

这样不管打不打包都能正常运行

执行php情况

[root@localhost test]# tree
.
├── aaa.txt
├── helloworld.php
├── lib
│   ├── app.php
│   └── bbb.txt
└── start.php

执行phar情况

[root@localhost bin]# tree
.
├── aaa.txt
├── helloworld.phar
└── lib└── bbb.txt

有更好的方式可以提出来

还有其它参数-i -x 我暂未试出效果,有兴趣的可以自己尝试一下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/67537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动化运维的未来:从脚本到AIOps的演进

点击进入IT管理资料库 一、自动化运维的起源&#xff1a;脚本时代 &#xff08;一&#xff09;脚本在运维中的应用场景 在自动化运维的发展历程中&#xff0c;脚本扮演着至关重要的角色&#xff0c;它作为最初的操作入口&#xff0c;广泛应用于诸多日常运维工作场景里。 在系统…

【2024年华为OD机试】(B卷,100分)- 热点网站统计(Java JS PythonC/C++)

一、问题描述 题目描述 企业路由器的统计页面需要动态统计公司访问最多的网页URL的Top N。设计一个算法&#xff0c;能够高效动态统计Top N的页面。 输入描述 每一行都是一个URL或一个数字&#xff1a; 如果是URL&#xff0c;代表一段时间内的网页访问。如果是数字N&#…

《DeepSeek 网页/API 性能异常(DeepSeek Web/API Degraded Performance):网络安全日志》

DeepSeek 网页/API 性能异常&#xff08;DeepSeek Web/API Degraded Performance&#xff09;订阅 已识别 - 已识别问题&#xff0c;并且正在实施修复。 1月 29&#xff0c; 2025 - 20&#xff1a;57 CST 更新 - 我们将继续监控任何其他问题。 1月 28&#xff0c; 2025 - 22&am…

智能汽车网络安全威胁报告

近年来随着智能汽车技术的快速发展&#xff0c;针对智能汽车的攻击也逐渐从传统的针对单一车辆控制器的攻击转变为针对整车智能化服务的攻击&#xff0c;包括但不限于对远程控制应用程序的操控、云服务的渗透、智能座舱系统的破解以及对第三方应用和智能服务的攻击。随着WP.29 …

docker中运行的MySQL怎么修改密码

1&#xff0c;进入MySQL容器 docker exec -it 容器名 bash 我运行了 docker ps命令查看。正在运行的容器名称。可以看到MySQL的我起名为db docker exec -it db bash 这样就成功的进入到容器中了。 2&#xff0c;登录MySQL中 mysql -u 用户名 -p 回车 密码 mysql -u root -p roo…

解锁微服务:五大进阶业务场景深度剖析

目录 医疗行业&#xff1a;智能诊疗的加速引擎 电商领域&#xff1a;数据依赖的破局之道 金融行业&#xff1a;运维可观测性的提升之路 物流行业&#xff1a;智慧物流的创新架构 综合业务&#xff1a;服务依赖的优化策略 医疗行业&#xff1a;智能诊疗的加速引擎 在医疗行业迈…

Cloudreve:Star22.3k,免费开源的网盘,支持多种存储方式,它允许用户快速搭建个人或团队的私有云存储服务。

嗨&#xff0c;大家好&#xff0c;我是小华同学&#xff0c;关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 Cloudreve是一个基于Web的文件管理和分享系统&#xff0c;它允许用户快速搭建个人或团队的私有云存储服务。该项目以其高度的可定制性和灵活性&#x…

AIGC(生成式AI)试用 20 -- deepseek 初识

>> 基本概念 Ollama -- 运行大模型&#xff0c;管理运行AI大模型的工具&#xff0c;用来安装布置DeepSeek https://ollama.com/ , Get up and running with large language models. AnythingLLM -- 大模型增强应用&#xff0c;GUI大模型交互程序 Download AnythingLLM …

Axure PR 9 旋转效果 设计交互

大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将学习Axure中的旋转效果设计与交互技巧。 旋转 创建旋转效果所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个按钮元件。 创建交互 创建按钮交互状态 1.选中按钮元件&#xf…

Attention--人工智能领域的核心技术

1. Attention 的全称与基本概念 在人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;领域&#xff0c;Attention 机制的全称是 Attention Mechanism&#xff08;注意力机制&#xff09;。它是一种能够动态分配计算资源&#xff0c;使模型在处理输入数据…

相同的树及延伸题型(C语言详解版)

从LeetCode 100和101看二叉树的比较与对称性判断 今天要讲的是leetcode100.相同的树&#xff0c;并且本文章还会讲到延伸题型leetcode101.对称二叉树。本文章编写用的是C语言&#xff0c;大家主要是学习思路&#xff0c;学习过后可以自己点击链接测试&#xff0c;并且做一些对…

【Rust自学】15.0. 智能指针(序):什么是智能指针及Rust智能指针的特性

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 15.0.1 指针的基本概念 指针是一个变量在内存中包含的是一个地址&#xff0c;指向另一个数据。 Rust 中最常见的指针是引用&#xff0c…

记录一次,PyQT的报错,多线程Udp失效,使用工具如netstat来检查端口使用情况。

1.问题 报错Exception in thread Thread-1: Traceback (most recent call last): File "threading.py", line 932, in _bootstrap_inner File "threading.py", line 870, in run File "main.py", line 456, in udp_recv IndexError: list…

电路研究9.2.5——合宙Air780EP中GPS 相关命令使用方法研究

注&#xff1a;本命令仅适用于合宙 4G CAT1 模块&#xff08;Air780EG 系列&#xff09;。 正好&#xff0c;我们使用的Air780EP好像也有4G CAT1模块&#xff0c;好像也属于Air780EG系列吧。 这个例子好像比较少就个。 18.9 使用方法举例 18.1GPS 开关&#xff1a;ATCGNSPWR 这…

【C语言】在Windows上为可执行文件.exe添加自定义图标

本文详细介绍了在 Windows 环境下,如何为使用 GCC 编译器编译的 C程序 添加自定义图标,从而生成带有图标的 .exe 可执行文件。通过本文的指导,读者可以了解到所需的条件以及具体的操作步骤,使生成的程序更具专业性和个性化。 目录 1. 准备条件2. 具体步骤步骤 1: 准备资源文…

python编程环境安装保姆级教程--python-3.7.2pycharm2021.2.3社区版

第1步安装解释器python-3.7.2&#xff0c;第2步安装pycharm编程软件 1、安装解释器 1.1 什么是解释器 就是将Python高级程序语言翻译成为计算机可以识别的0、1代码 1.2 安装解释器python-3.7.2&#xff08;根据自己的操作系统安装适配的解释器&#xff0c;以Windows为例&…

STM32 TIM输入捕获 测量频率

输入捕获简介&#xff1a; IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器…

21.3-启动流程、编码风格(了解) 第21章-FreeRTOS项目实战--基础知识之新建任务、启动流程、编码风格、系统配置 文件组成和编码风格(了解)

21.3-启动流程、编码风格(了解) 启动流程 第一种启动流程(我们就使用这个): 在main函数中将硬件初始化、RTOS系统初始化&#xff0c;同时创建所有任务&#xff0c;再启动RTOS调度器。 第二种启动流程&#xff1a; 在main函数中将硬件初始化、RTOS系统初始化&#xff0c;只…

【AI非常道】二零二五年一月(二),AI非常道

经常在社区看到一些非常有启发或者有收获的话语&#xff0c;但是&#xff0c;往往看过就成为过眼云烟&#xff0c;有时再想去找又找不到。索性&#xff0c;今年开始&#xff0c;看到好的言语&#xff0c;就记录下来&#xff0c;一月一发布&#xff0c;亦供大家参考。 有关AI非…

Mac Electron 应用签名(signature)和公证(notarization)

在MacOS 10.14.5之后&#xff0c;如果应用没有在苹果官方平台进行公证notarization(我们可以理解为安装包需要审核&#xff0c;来判断是否存在病毒)&#xff0c;那么就不能被安装。当然现在很多人的解决方案都是使用sudo spctl --master-disable&#xff0c;取消验证模式&#…