PHP:Phar的打包和使用

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Phar包在概念上类似于Java的Jar包,但是根据PHP应用程序的需求和灵活性进行了定制,Phar包用于在单个文件中分发完整的PHP应用程序或者库(单一入口)。 使用Phar包和使用其他的PHP库是相同的: 加载文件 –> 调用

什么是Phar?


Phar是PHP里类似于Jar的一种打包文件,可以将整个应用打包,便于部署等。


安装需求


Phar需要 PHP >= 5.2 ,在 PHP5.3或以上,Phar已经包含在内置的扩展中,在这之前可以通过PECL扩展安装。


运行时配置


通过php.ini的配置项,可以设定一些Phar的函数行为方式。


配置项


默认值


解释


phar.readonly


1


只允许读,只能在php.ini中取消设置


phar.require_hash


1


强制所有打开的Phar包需要包含某种签名,否则拒绝处理,只能在php.ini中取消设置


phar.extract_list


从phar 2.0.0开始,此INI设置已被删除,加载路径映射


phar.cache_list


允许在Web服务器启动时预先解析映射phar存档,从而提供性能改进,使运行文件从phar存档中移出,非常接近从传统的基于磁盘的安装运行这些文件的速度。


使用Phar


Phar包在概念上类似于Java的Jar包,但是根据PHP应用程序的需求和灵活性进行了定制,Phar包用于在单个文件中分发完整的PHP应用程序或者库(单一入口)。 使用Phar包和使用其他的PHP库是相同的: 加载文件 –> 调用


<?php
require_once "phar://siam.phar/user.class.php";
$u = new user();
$u->set_name("siam");


制作Phar包


我们先建立以下层级的文件


siam
├── src 目标程序
   ├── test
      └── index.html
   └── A.php
   └── B.php
   └── index.php
└── build.php   打包程序


其中src目录下 就是你需要打包的整个程序文件,这里就不展示了、 build.php文件是执行打包的文件


<?php
//产生一个siam.phar文件
$phar = new Phar('siam.phar', 0, 'siam.phar');
// 添加src里面的所有文件到siam.phar归档文件
$phar->buildFromDirectory(dirname(__FILE__) . '/src');
//设置执行时的入口文件,第一个用于命令行,第二个用于浏览器访问,这里都设置为index.php
$phar->setDefaultStub('index.php', 'index.php');


设置好包名、打包目标、运行入口文件,我们在浏览器访问build.php即可看到在目录中生成了一个siam.phar的文件。


第一次访问build.php提示报错:disabled by the php.ini setting phar.readonly,记得看文章上面,在php.ini手动打开,不能通过函数设置的哈~


siam.phar的开头内容大概如下


<?php
$web = 'index.php';
if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
Phar::interceptFileFuncs();
set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
Phar::webPhar(null, $web);
include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
return;
}
if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET'  $_SERVER['REQUEST_METHOD'] == 'POST'))) {
Extract_Phar::go(true);
$mimes = array(
'phps' => 2,
'c' => 'text/plain',
'cc' => 'text/plain',
'cpp' => 'text/plain',
'c++' => 'text/plain',
......
)


效果预览


<?php
/**
 * 测试siam.phar
 */
# 测试入口文件
require 'phar://siam.phar';
echo "<br>";
# 测试类文件
require 'phar://siam.phar/A.php';
$class = new Siam\A();
echo $class->a();
echo "<br>";
# 测试静态文件
$html = require 'phar://siam.phar/test/index.html';
echo $html;


命令行模式


上面我们演示了的是其他php程序加载调用phar包的情况。 我们也可以用命令行来运行phar包。 首先我们先改造一下入口文件


<?php
foreach ($argv as $key => $value) {
    if ($key == 0){
        continue;
    }
    switch ($value) {
        case '-v':
            echo "当前版本 v1.0";
            break;
        case '-m':
            echo "siam";
            break;
        default:
            echo "未知命令";die;
            break;
    }
}


然后再次构建phar包,在命令行模式下分别输入以下命令试试吧


php ./siam.phar 
php ./siam.phar -v
php ./siam.phar -v -m 
php ./siam.phar -v -t


Phar中目录路径相关


我们都知道在PHP中是可以通过函数和常量来获取运行脚本所在目录路径的,那么在Phar打包的程序中,展示的目录路径又会是怎么样的? 我们将src/index.php中的文件再次改为以下内容来进行测试


<?php
// getcwd()返回当前工作目录
echo "getcwd -->" . getcwd();
echo "\n";
// 获取当前文件的绝对路径
echo "__FILE__ -->" .__FILE__;
echo "\n";
// 获取当前脚本的目录
echo "__DIR__ -->" .__DIR__;
echo "\n";
// 当前执行脚本的绝对路径。记住,在CLI方式运行php是获取不到的
echo "SCRIPT_FILENAME -->" .$_SERVER["SCRIPT_FILENAME"];
echo "\n";
// 当前运行脚本所在的文档根目录。在服务器配置文件中定义
echo "DOCUMENT_ROOT -->" .$_SERVER["DOCUMENT_ROOT"];
echo "\n";

接着我们分别运行src/index.phpsiam.phar


error_icon.png


在结果中我们可以看到类似如图的结果


phar


正常PHP脚本


getcwd


得到phar包所在目录


得到php脚本所在目录


__FILE__


phar:// 数据流包装器,指向入口脚本所在绝对路径(注意:phar包名作为一个目录层级)


得到php脚本文件所在绝对路径


__DIR__


phar:// 数据流包装器,指向入口脚本所在目录绝对路径


得到php脚本所在目录绝对路径


$_SERVER[“SCRIPT_FILENAME”]


phar包名


php脚本文件名


$_SERVER[“DOCUMENT_ROOT”]


应该是本地测试原因为空,后面补充


Phar包中的临时文件存放


假设我们的程序打包成了phar包,那么在运行中产生的日志记录,我们应该怎么来存放。 根据上面的测试,我们知道了 __FILE____DIR__ 两个常量得到的是phar:// 数据流包装器,如果我们使用这两个常量来设置Log文件存放路径,是否能正常储存?


<?php
$logPath = __DIR__ .   "/test.log";
echo $logPath."\n";
file_put_contents($logPath, "test\n");
// 写完再读出来
echo file_get_contents($logPath);


打包,运行,会得到以下结果


phar://F:/WWW/learn/phar/siam.phar/test.log
test


但是我们的日志需要储存一般都是用FILE_APPEND追加内容储存。 然而phar包中的运行你将会得到以下结果


Warning: file_put_contents(phar://F:/WWW/learn/phar/siam.phar/test.log): failed to open stream: phar error: open mode append not supported in phar://F:/WWW/learn/phar/siam.phar/index.php on line 4


关键报错:open model append not supported in phar 可见phar内的文件写入不支持追加模式打开。 并且在后续的日志查看中 也极其不方便,因为phar包内的文件我们并不能直接查看,所以我们储存临时文件应该存放在外部。


<?php
$logPath = getcwd() .   "/test.log";
echo $logPath."\n";
file_put_contents($logPath, "test\n", FILE_APPEND);


getcwd()函数将会得到phar包所在目录,然后在同级将创建test.log文件存放日志内容。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
Java PHP
PHP:Phar的打包和使用
PHP:Phar的打包和使用
231 0
|
Java PHP JavaScript
php归档格式:phar文件详解(创建、使用、解包还原提取)
转载一篇,突然遇到一个冷知识,phar的东东,貌似和jar、war是一种鬼。 重点使用一下下面这个东东,就能解包出来东东了。 $phar = new Phar('lib/yunke.phar', 0);   $phar->setAlias ( "yun.
1322 0
|
Java 测试技术 PHP
|
存储 Java PHP
PHP V5.3 中的新特性,第 4 部分: 创建并使用 Phar 归档
Phar 归档的概念来自 Java™ 技术的 JAR 归档,它允许使用单个文件打包应用程序,这个文件中包含运行应用程序所需的所有东西。该文件不同于单个可执行文件,后者通常由编程语言生成,比如 C,因为该文件实际上是一个归档文件而非编译过的应用程序。
778 0
|
2月前
|
安全 关系型数据库 MySQL
PHP与MySQL交互:从入门到实践
【9月更文挑战第20天】在数字时代的浪潮中,掌握PHP与MySQL的互动成为了开发动态网站和应用程序的关键。本文将通过简明的语言和实例,引导你理解PHP如何与MySQL数据库进行对话,开启你的编程之旅。我们将从连接数据库开始,逐步深入到执行查询、处理结果,以及应对常见的挑战。无论你是初学者还是希望提升技能的开发者,这篇文章都将为你提供实用的知识和技巧。让我们一起探索PHP与MySQL交互的世界,解锁数据的力量!