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.rhkb.cn/news/6837.html

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

相关文章

博睿数据获中国信通院泰尔终端实验室致谢!

近日&#xff0c;博睿数据收到中国信息通信研究院&#xff08;以下简称“中国信通院”&#xff09;的感谢信&#xff0c;信中对博睿数据积极参与信通院牵头的“铸基计划——高质量数字化转型推进行动”&#xff0c;并在新技术研究、标准建设、课题共创、专家智库等多项工作中提…

分布式理解

分布式 如何理解分布式 狭义的分布是指&#xff0c;指多台PC在地理位置上分布在不同的地方。 分布式系统 分布式系**统&#xff1a;**多个能独立运行的计算机&#xff08;称为结点&#xff09;组成。各个结点利用计算机网络进行信息传递&#xff0c;从而实现共同的“目标或者任…

centos哪个版本建站好?centos最稳定好用的版本

在信息化飞速发展的今天&#xff0c;服务器操作系统作为构建网络架构的基石&#xff0c;其稳定性和易用性成为企业和个人用户关注的重点。CentOS作为一款广受欢迎的开源服务器操作系统&#xff0c;凭借其强大的性能、出色的稳定性和丰富的软件包资源&#xff0c;成为众多用户建…

计算机网络 (58)无线局域网WLAN

前言 无线局域网WLAN&#xff08;Wireless Local Area Network&#xff09;是一种利用无线通信技术将计算机设备互联起来&#xff0c;构成可以互相通信和实现资源共享的网络体系。 一、定义与特点 定义&#xff1a; WLAN通过无线信道代替有线传输介质连接两个或多个设备形成一个…

vim 中粘贴内容时提示: -- (insert) VISUAL --

目录 问题现象&#xff1a;解决方法&#xff1a;问题原因&#xff1a; 问题现象&#xff1a; 使用 vim 打开一个文本文件&#xff0c;切换到编辑模式后&#xff0c;复制内容进行粘贴时有以下提示&#xff1a; 解决方法&#xff1a; 在命令行模式下禁用鼠标支持 :set mouse …

总结与展望,龙蜥社区第 30 次运营委员会会议线上召开

2025 年 1 月 20 日&#xff0c;龙蜥社区召开了第 30 次运营委员会线上会议&#xff0c;来自 24 家理事单位的 22 位委员及委员代表出席&#xff0c;本次会议由运营委员凝思软件李晨斌主持。会上总结和回顾了龙蜥社区 1 月运营发展情况&#xff0c;同步了龙蜥社区 3 大运营目标…

新型人工智能“黑帽”工具:GhostGPT带来的威胁与挑战

生成式人工智能的发展既带来了有益的生产力转型机会&#xff0c;也提供了被恶意利用的机会。 最近&#xff0c;Abnormal Security的研究人员发现了一个专门为网络犯罪创建的无审查AI聊天机器人——GhostGPT&#xff0c;是人工智能用于非法活动的新前沿&#xff0c;可以被用于网…

智能体0门槛开发

分享一个智能体开发流程。 2025 年啊&#xff0c;好多专家还有行业报告都觉得这是智能体&#xff08;AI Agent&#xff09;应用的头一年。相关的应用在商业、工业、消费等好些领域都到了关键的时候&#xff0c;这意味着从实验室走向大规模实际应用的重要转变。而且呢&#xff0…

计算机网络 (53)互联网使用的安全协议

一、SSL/TLS协议 概述&#xff1a; SSL&#xff08;Secure Sockets Layer&#xff09;安全套接层和TLS&#xff08;Transport Layer Security&#xff09;传输层安全协议是工作在OSI模型应用层的安全协议。SSL由Netscape于1994年开发&#xff0c;广泛应用于基于万维网的各种网络…

grafana新增email告警

选择一个面板 比如cpu 新增一个临界点表达式 input选A 就是A的值达到某个临界点 触发告警 我这边IS ABOVE0.15就是cpu大于0.15%就触发报警&#xff0c;这个值怎么填看指标的值显示 这里要设置一下报警条件 这边随便配置下 配置标签和通知&#xff0c;选择你的邮件 看下告警…

npm常见报错整理

npm install时报UNMET PEER DEPENDENCY 现象 npm install时报UNMET PEER DEPENDENCY,且执行npm install好几遍仍报这个。 原因 不是真的缺少某个包,而是安装的依赖版本不对,警告你应该安装某一个版本。 真的缺少某个包。 解决 看了下package.json文件,我的react是有的…

24_游戏启动逻辑梳理总结

首先这个项目从游戏根入口GameRoot.cs的初始化开始 分为 服务层初始化Svc.cs 与 业务系统层初始化Sys.cs 而服务层 分为 资源加载服务层ResSvc.cs 与 音乐播放服务层AudioSvc.cs 而在 资源加载服务层ResSvc.cs中 初始化了 名字的 配置文件 而音乐播放服务层AudioSvc.cs 暂时没…

UE求职Demo开发日志#8 强化前置条件完善,给物品加图标

1 强化前置条件完善 StrengthManager里实现一个Check前置的函数 bool CheckPreAllIsActive(int index)&#xff0c;所有的前置都已经激活就返回true&#xff0c;否则返回false 之后在强化的时候加入条件检查&#xff1a; 1.所有前置技能全部激活 2.本身没有强化过 最后测…

QT:tftp client 和 Server

1.TFTP简介 TFTP&#xff08;Trivial File Transfer Protocol,简单文件传输协议&#xff09;是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。端口号为69。 FTP是一个传输文件的简单协议&#xff0c;…

dm8在Linux环境安装精简步骤说明(2024年12月更新版dm8)

dm8在Linux环境安装详细步骤 - - 2025年1月之后dm8 环境介绍1 修改操作系统资源限制2 操作系统创建用户3 操作系统配置4 数据库安装5 初始化数据库6 实例参数优化7 登录数据库配置归档与备份8 配置审计9 创建用户10 屏蔽关键字与数据库兼容模式11 jdbc连接串配置12 更多达梦数据…

24年总结 -- 共赴心中所向往的未来

一、前言 我又回来了&#xff0c;前阵子忙着期末考试的东西&#xff0c;也是快半个月没更新了&#xff0c;刚好前几天报名了博客之星的评选&#xff0c;也很幸运的入围了&#xff0c;也借此机会来回顾一下关于2024年的个人成长、创作经历等。 二、个人 本人是一个双非学校的软…

动态规划一> 让字符串成为回文串的最少插入次数

题目&#xff1a; 解析&#xff1a; 状态表示状态转移方程&#xff1a; 初始化填表顺序返回值&#xff1a; 代码&#xff1a; public int minInsertions(String ss) {char[] s ss.toCharArray();int n s.length; int[][] dp new int[n][n]; for(int i n-1; i > 0;…

2025.1.21——八、[HarekazeCTF2019]Avatar Uploader 2(未完成) 代码审计|文件上传

题目来源&#xff1a;buuctf [HarekazeCTF2019]Avatar Uploader 2 一、打开靶机&#xff0c;整理信息 跟Avatar Uploader 1 题目长得一样&#xff0c;先上传相同文件看看情况&#xff0c;另外这道题还有源码&#xff0c;可以看看 二、解题思路 step 1&#xff1a;上传同类…

Elementor Pro 3.27 汉化版 2100套模板 安装教程 wordpress主题中文编辑器插件免费下载

插件下载地址 https://a5.org.cn/a5ziyuan/732506.html 转载请注明出处! Elementor Pro 是流行的 Elementor 的付费扩展 WordPress 页面构建器插件. 它为免费的 Elementor 插件添加了许多附加功能和增强功能&#xff0c;使其成为创建美丽的更强大的工具 WordPress 网站。 如果…

深入理解动态规划(dp)--(提前要对dfs有了解)

前言&#xff1a;对于动态规划&#xff1a;该算法思维是在dfs基础上演化发展来的&#xff0c;所以我不想讲的是看到一个题怎样直接用动态规划来解决&#xff0c;而是说先用dfs搜索&#xff0c;一步步优化&#xff0c;这个过程叫做动态规划。&#xff08;该文章教你怎样一步步的…