PHPによるpharの詳細な分析

WBOY
WBOY転載
2022-04-22 12:14:036475ブラウズ

この記事では、PHP に関する関連知識をお届けします。主に phar に関する関連コンテンツを紹介します。phar の正式名は PHP Archive です。phar 拡張機能は、PHP アプリケーション全体を統合する方法を提供します。移動やインストールを容易にするために、pha ファイルに入れる方法を見てみましょう。

PHPによるpharの詳細な分析

推奨学習: 「PHP ビデオ チュートリアル

1 phar ファイルとは

Jar (Java アーカイブ) ファイルは、すべての実行可能ファイルとアクセス可能なファイルを含むアプリケーションを JAR ファイルにパッケージ化するため、展開プロセスが非常に簡単になります。

JAR に似ています。 phar の完全な名前は PHP Archive です。phar 拡張子は、PHP アプリケーション全体を .phar ファイルに入れて、移動とインストールを容易にする方法を提供します。 phar ファイルの最大の特徴は、複数のファイルを 1 つのファイルに結合する便利な方法であることです。 .phar ファイルは、完全な PHP プログラムを 1 つのファイルに配布し、そのファイルから実行する方法を提供します。

Phar は、JAR とは異なり、PHP 自体で処理できるため、作成または使用するために追加のツールを使用する必要はなく、PHP スクリプトを使用して作成または抽出できます。

2 phar の作成

1 php.ini 設定ファイルを変更します

PHAR ファイルのデフォルトの状態は次のとおりです。読み取り専用 。Phar ファイルの使用には構成は必要ありません。導入は非常に簡単です。独自の Phar ファイルを作成する必要があるため、Phar ファイルへの書き込みを許可する必要があります。これを変更する必要があります。php.ini

私の php.ini ファイルでは、phar.読み取り専用 = オン。

[Phar]
; http://php.net/phar.readonly
;phar.readonly = On

まず、php.ini の phar.readonly オプションを変更し、先行するセミコロンを削除し、値を off に変更します。セキュリティ上の理由により、このオプションのデフォルトは on です。php で無効になっている場合は、 ini (値は 0 または off) にすると、ユーザー スクリプトでオンまたはオフにできます。php.ini でオンになっている場合、ユーザー スクリプトはオフにできないため、ここでは表示するためにオフに設定されています。例。

これで、PHP アプリケーションを Phar ファイルにパッケージ化できます。

2 独自の PHP ファイル プロジェクトを作成します

ここでは、他の人のブログ プロジェクトから直接コピーしましたが、このブログを構成する当初の目的は phar:/ を理解することであったため、実演はしませんでした。 / 脆弱性がある場合は、ctf を使用してください。したがって、ファイル名は元の作成者に従って変更されません。参考記事は最後に追記します。

まず、アプリケーションのディレクトリ構造をルールに従って作成する必要があります。ルート ディレクトリはプロジェクトで、プロジェクト配下のディレクトリは次のとおりです。空のコンテンツを持つ JS ファイルと CSS ファイルの 2 つのファイル フォルダーがあります。複数のファイル形式を含めることができるのはデモンストレーション phar のみです。

lib_a.php のコンテンツは次のとおりです。

file
    -yunek.js
    -yunke.css
lib
    -lib_a.php
template
    -msg.html
index.php
Lib.php

msg.html のコンテンツは次のとおりです。 :

<?php
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/10
 * Time: 9:23
 */
function show(){
    echo "l am show()";
}

index.php の内容は次のとおりです:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>phar</title>
</head>
<body>
<?=$str; ?>
</body>
</html>

Lib.php の内容は次のとおりです:

<?php
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/10
 * Time: 9:17
 */
require "lib/lib_a.php";
show();
 
$str = isset($_GET["str"]) ? $_GET["str"] : "hello world";
include "template/msg.html";

3 phar ファイルの作成

プロジェクト ファイルの準備ができました。プロジェクト フォルダーと同じディレクトリにあります。yunkeBuild.php を作成して、次の内容の phar 形式ファイルを生成します。

<?php
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/10
 * Time: 9:20
 */
function yunke()
{
    echo "l am yunke()";
}

次に、ブラウザで yunkeBuild.php ファイルにアクセスします。このとき、サーバーのルートディレクトリ構造は次のようになります:

project

yunkeBuild.php

yunke.phar

これは、phar アーカイブ ファイルを生成する最も簡単なプロセスです。

ここでは、理解を深めるためにその他の追加をいくつか行います:

1)

phar ファイルは、yunkeBuild.php にアクセスすることで生成されます。実行。したがって、ターミナルで次のコードを実行して

<?php
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/10
 * Time: 9:36
 */
 
//产生一个yunke.phar文件
$phar = new Phar(&#39;yunke.phar&#39;, 0, &#39;yunke.phar&#39;);
// 添加project里面的所有文件到yunke.phar归档文件
$phar->buildFromDirectory(dirname(__FILE__) . '/project');
//设置执行时的入口文件,第一个用于命令行,第二个用于浏览器访问,这里都设置为index.php
$phar->setDefaultStub('index.php', 'index.php');
を生成すると、yunke.phar ファイルが生成されます。

2)

new phar() は phar オブジェクトを生成します。パラメータを解釈してみましょう。

aabouzekry@platinum:~/myapp$ php yunkeBuild.php
説明:

新しい

Phar

オブジェクトの作成には、通常 3 つのパラメーターが必要です。 最初のパラメータは Phar ファイルへのパスです。それを通じて Phar ファイルを作成できるだけでなく、既存の Phar ファイルを操作することもできます。

2 番目のパラメータは、

Phar

オブジェクトがファイルを処理する方法を設定することです。 Phar オブジェクトは PHP RecursiveDirectoryIterator オブジェクトを継承し、このパラメータは親クラスに直接渡されます。ここで指定される値は RecursiveDirectoryIterator のデフォルト値であり、現在の要件を満たすことができます。 3 番目のパラメータは Phar ファイルのエイリアスです。この Phar ファイルを内部で参照する場合、このエイリアスを使用する必要があります。

通常はファイル名を渡すだけです。それが 3 番目のパラメータです。

3)

ファイルを phar に追加します。ファイルを追加するにはいくつかの方法があります:

  • 手动添加已有文件

调用类方法Phar::addFile($filepath,$localpath=?)添加文件,参数是文件绝对路径和(可选)存储到phar的相对路径

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar->addFile('test.php');
	include('phar://yunke.phar/test.php') // in test.php
?>

这里出现的phar://就是访问phar文件的一种方法,所以不需要太在意。

  • 以字符串添加文件内容

调用类方法Phar::addFromString($localpath,$contents)以字符串形式添加文件

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar->addFromString('test.php','<?php echo \&#39;in test.php\&#39;?>');
	include('phar://yunke.phar/test.php'); // in test.php
?>
  • 添加空目录

调用类方法Phar::addEmptyDir($dirname)添加空目录,使用方法Phar::getContent()获取文件结构

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar->addEmptyDir('test'); // yunke.phar/test/
?>
  • 手动选择添加已有目录

调用类方法Phar::buildFromDirectory($dir,$pattern = "")添加整个目录

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar->buildFromDirectory('test'); // test.php in test/
	include('phar://yunke.phar/test/test.php'); // in test/test.php
?>

4) 存根文件Stub,理解这个很重要。

归档文件中有一个存根文件stub,其实就是一段php执行代码,在制作归档时可以设置,直接执行归档文件时,其实就是执行它,所以它是启动文件;在脚本中包含归档文件时就像包含普通php文件一样包含它并运行,但直接以phar://的方式包含归档中某一个文件时不会执行存根代码, 往往在存根文件里面require包含要运行的其他文件,对存根文件的限制仅为以__HALT_COMPILER(); 结束,默认的存根设计是为在没有phar扩展时能够运行,它提取phar文件内容到一个临时目录再执行,不过从php5.3开始该扩展默认内置启用了。

stub是phar文件的文件头,格式为...<?php ...;__HALT_COMPILER();?>,…可以是任意字符,包括留空,且php闭合符与最后一个分号之间不能有多于一个的空格符。另外php闭合符也可省略。最短省略闭合符的stub是__HALT_COMPILER();?></p> <p>运行Phar文件时,stub文件被当做一个meta文件来初始化Phar, 并告诉Phar文件在被调用时该做什么。</p> <p>在我们的例子中,使用的是 <code>createDefaultStub() 方法。

其他的方式如下:

方法一:调用类方法Phar::setStub($string)为实例创建自定义stub

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar->setStub('<?php echo \&#39;in stub!\&#39;;__HALT_COMPILER();?>');
	include('phar://yunke.phar');	// in stub!
?>

也可以

$phar->setStub($phar->createDefaultStub("index.php"));

生成的缺省stub文件包含如下的代码:

<?php
Phar::mapPhar();
include "phar://yunke.phar/index.php";
__HALT_COMPILER();

createDefaultStub() 方法缺省创建的stub文件的内容很简单。 Phar::mapPhar() 用来分析Phar文件的元数据,并初始化它。stub文件的结尾处需要调用 __HALT_COMPILER() 方法,这个方法后不能留空格。__HALT_COMPILER() 会立即终止PHP的运行,防止include的文件在此方法后仍然执行。这是Phar必须的,没有它Phar将不能正常运行。

除此之外,我们还可以创建自己的stub文件来执行自定义的初始化过程,像这样加载自定义文件

<?php
$phar->setStub(file_get_contents("stub.php"));

方法二:使用默认stub,调用类方法Phar::setDefaultStub()为实例设置默认stub,使用方法Phar::getStub()获取实例的stub

<?php
    $phar = new Phar(&#39;yunke.phar&#39;);
    $phar->setDefaultStub();
    print_r($phar->getStub()); // 2, 'c' => 'text/plain', 'cc' => 'text/plain', ...
?>

如果缺省创建stub,PHP会使用默认stub

<?php
	$phar = new Phar(&#39;yunke.phar&#39;);
	$phar[&#39;demo.txt&#39;] = &#39;demo&#39;;
	print_r($phar->getStub()); // 2, 'c' => 'text/plain', 'cc' => 'text/plain', ...
?>

4 phar文件的运行

我们在服务器根目录建立一个index.php文件来演示如何使用上面创建的phar文件,内容如下:

<?php
 
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/8
 * Time: 9:33
 */
 
require "yunke.phar";
require "phar://yunke.phar/Lib.php";
yunke();

如果index.php文件中只有第一行,那么和不使用归档文件时,添加如下代码完全相同:

require "project/index.php";

如果没有第二行,那么第三行的yunke()将提示未定义,所以可见require一个phar文件时并不是导入了里面所有的文件,而只是导入了入口执行文件而已,但在实际项目中往往在这个入口文件里导入其他需要使用的文件,在本例中入口执行文件为project/index.php。

补充:

可以为归档设置别名,别名保存在归档文件中永久保存,它可以用一个简短的名字引用归档,而不管归档文件在文件系统中存储在那里,设置别名:

$phar = new Phar(&#39;lib/yunke.phar&#39;, 0);
$phar->setAlias ( "yun.phar");

设置别名后可以如下使用:

<?php
require "lib/yunke.phar";
require "phar://yun.phar/Lib.php";  //使用别名访问归档文件
require "phar://lib/yunke.phar/Lib.php"; //当然仍然可以使用这样的方式去引用

如果在制作phar文件时没有指定别名,也可以在存根文件里面使用Phar::mapPhar('yunke.phar');指定。

5 phar文件的提取还原

我们有时候会好奇phar里面包含的文件源码,这个时候就需要将phar文件还原,如果只是看一看的话可以使用一些ide工具,比如phpstorm 10就能直接打开它,如果需要修改那么就需要提取操作了,为了演示,我们下载一个composer.phar放在服务器目录,在根目录建立一个get.php文件,内容如下

<?php
/**
 * Created by yunke.
 * User: yunke
 * Date: 2017/2/9
 * Time: 19:02
 */
 
$phar = new Phar(&#39;composer.phar&#39;);
$phar->extractTo('composer'); //提取一份原项目文件
$phar->convertToData(Phar::ZIP); //另外再提取一份,和上行二选一即可

用浏览器访问这个文件,即可提取出来,以上列子展示了两种提取方式:

2 行目は、composer ディレクトリを作成し、抽出したコンテンツをそこに置きます;

3 行目は、composer.zip ファイルを生成します。このファイルは、解凍することで抽出および復元できます。

phar:// 疑似プロトコルによって引き起こされるサーバー検証バイパスについて:

推奨される学習: 「PHP ビデオ チュートリアル

以上がPHPによるpharの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。