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…

基于微信小程序的辅助教学系统的设计与实现

标题:基于微信小程序的辅助教学系统的设计与实现 内容:1.摘要 摘要&#xff1a;随着移动互联网的普及和微信小程序的兴起&#xff0c;基于微信小程序的辅助教学系统成为了教育领域的一个新的研究热点。本文旨在设计和实现一个基于微信小程序的辅助教学系统&#xff0c;以提高教…

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

近年来随着智能汽车技术的快速发展&#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…

创建 priority_queue - 进阶(内置类型)c++

内置类型就是 C 提供的数据类型&#xff0c;⽐如 int 、 double 、 long long 等。以 int 类型为例&#xff0c;分 别创建⼤根堆和⼩根堆。 这种写法意思是&#xff0c;我要告诉这个优先级队列要建一个什么样的堆&#xff0c;第一个int是要存什么数据类型&#xff0c;vecto…

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

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

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

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

Day28(补)-【AI思考】-AI会不会考虑自己的需求?

文章目录 AI会不会考虑自己的需求&#xff1f;一、**技术本质&#xff1a;深度≠理解**二、**传播机制&#xff1a;热搜如何制造幻觉**三、**伦理考量&#xff1a;为何必须"撇清"**关键结论 AI会不会考虑自己的需求&#xff1f; 让思想碎片重焕生机的灵魂&#xff1a…

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 …

解决Oracle SQL语句性能问题(10.5)——常用Hint及语法(7)(其他Hint)

10.5.3. 常用hint 10.5.3.7. 其他Hint 1)cardinality:显式的指示优化器为SQL语句的某个行源指定势。该Hint具体语法如下所示。 SQL> select /*+ cardinality([@qb] [table] card ) */ ...; --注: 1)这里,第一个参数(@qb)为可选参数,指定查询语句块名;第二个参数…

Axure PR 9 旋转效果 设计交互

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

SSM开发(三) spring与mybatis整合(含完整运行demo源码)

目录 本文主要内容 一、Spring整合MyBatis的三个关键点 二、整合步骤 1、创建一个Maven项目 2、在pom.xml文件中添加jar包的依赖 3、配置MyBatis 注解实现方式 XML配置文件实现 4、配置Spring 5、测试运行 本文主要内容 1. Spring + Mybatis整合; 2. MyBatis两种SQL…

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;并且做一些对…

Carla-ModuleNotFoundError: No module named ‘agents.navigation‘

解决办法&#xff1a; You need to make sure that _agents _ is in your (PYTHON)PATH variable or your working dictionary. Setting your working dictionary to <CARLA_ROOT>/PythonAPI/carla would fix it as agents is a sub dictionary. Similarly adding the c…

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

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

数据结构:线性表查找的三种方式

只要是静态查找表即可 #define ElemType int typedef struct { ElemType *d; int length; }SSTable; 顺序查找 S(n)O(1) 哨兵空间 int Search_Seq(SSTable t,ElemType key) {t.d[0]key;for (int i t.length; i >0 ; i--) {if(t.d[i]t.d[0]){return i;}}return 0; } 折半查找…

记录一次,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…