php-doc-en/reference/phar/using.xml
Christoph Michael Becker e9f972da69 Remove obsolete Phar information
Phar 2.0.0 has been released 2009-07-29, so older versions are certainly
no longer relevant for the PHP manual.


git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@352054 c90b9560-bf6c-de11-be94-00142212c4b1
2020-12-13 16:38:57 +00:00

386 lines
15 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<chapter xml:id="phar.using" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Using Phar Archives</title>
<section xml:id="phar.using.intro" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Using Phar Archives: Introduction</title>
<para>
Phar archives are similar in concept to Java JAR archives, but are tailored
to the needs and to the flexibility of PHP applications. A Phar archive is
used to distribute a complete PHP application or library in a single file. A
Phar archive application is used exactly like any other PHP application:
</para>
<screen>
<![CDATA[
php coolapplication.phar
]]>
</screen>
<para>
Using a Phar archive library is identical to using any other PHP library:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
include 'coollibrary.phar';
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
The <literal>phar</literal> stream wrapper provides the core of the phar extension, and
is explained in detail <link linkend="phar.using.stream">here</link>.
The phar stream wrapper allows accessing the files within a phar archive using
PHP's standard file functions <function>fopen</function>, <function>opendir</function>, and
others that work on regular files. The <literal>phar</literal> stream wrapper supports all
read/write operations on both files and directories.
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
include 'phar://coollibrary.phar/internal/file.php';
header('Content-type: image/jpeg');
// phars can be accessed by full path or by alias
echo file_get_contents('phar:///fullpath/to/coollibrary.phar/images/wow.jpg');
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
The <classname>Phar</classname> class implements advanced functionality for accessing
files and for creating phar archives. The Phar class is explained in detail
<link linkend="phar.using.object">here</link>.
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
try {
// open an existing phar
$p = new Phar('coollibrary.phar', 0);
// Phar extends SPL's DirectoryIterator class
foreach (new RecursiveIteratorIterator($p) as $file) {
// $file is a PharFileInfo class, and inherits from SplFileInfo
echo $file->getFileName() . "\n";
echo file_get_contents($file->getPathName()) . "\n"; // display contents;
}
if (isset($p['internal/file.php'])) {
var_dump($p['internal/file.php']->getMetadata());
}
// create a new phar - phar.readonly must be 0 in php.ini
// phar.readonly is enabled by default for security reasons.
// On production servers, Phars need never be created,
// only executed.
if (Phar::canWrite()) {
$p = new Phar('newphar.tar.phar', 0, 'newphar.tar.phar');
// make this a tar-based phar archive, compressed with gzip compression (.tar.gz)
$p = $p->convertToExecutable(Phar::TAR, Phar::GZ);
// create transaction - nothing is written to newphar.phar
// until stopBuffering() is called, although temporary storage is needed
$p->startBuffering();
// add all files in /path/to/project, saving in the phar with the prefix "project"
$p->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator('/path/to/project')), '/path/to/');
// add a new file via the array access API
$p['file1.txt'] = 'Information';
$fp = fopen('hugefile.dat', 'rb');
// copy all data from the stream
$p['data/hugefile.dat'] = $fp;
if (Phar::canCompress(Phar::GZ)) {
$p['data/hugefile.dat']->compress(Phar::GZ);
}
$p['images/wow.jpg'] = file_get_contents('images/wow.jpg');
// any value can be saved as file-specific meta-data
$p['images/wow.jpg']->setMetadata(array('mime-type' => 'image/jpeg'));
$p['index.php'] = file_get_contents('index.php');
$p->setMetadata(array('bootstrap' => 'index.php'));
// save the phar archive to disk
$p->stopBuffering();
}
} catch (Exception $e) {
echo 'Could not open Phar: ', $e;
}
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
In addition, verification of phar file contents can be done using any of the
supported symmetric hash algorithms (MD5, SHA1, SHA256 and SHA512 if ext/hash is enabled)
and using asymmetric public/private key signing using OpenSSL. To
take advantage of OpenSSL signing, you need to generate a public/private key pair, and
use the private key to set the signature using
<function>Phar::setSignatureAlgorithm</function>. In addition, the public key
as extracted using this code:
<programlisting role="php">
<![CDATA[
<?php
$public = openssl_get_publickey(file_get_contents('private.pem'));
$pkey = '';
openssl_pkey_export($public, $pkey);
?>
]]>
</programlisting>
must be saved adjacent to the phar archive it verifies. If the phar archive
is saved as <literal>/path/to/my.phar</literal>, the public key must be saved
as <literal>/path/to/my.phar.pubkey</literal>, or phar will be unable to verify
the OpenSSL signature.
</para>
<para>
The <classname>Phar</classname> class also provides 3 static methods, <function>Phar::webPhar</function>,
<function>Phar::mungServer</function> and <function>Phar::interceptFileFuncs</function> that are crucial
to packaging up PHP applications designed for usage on regular filesystems and for web-based applications.
<function>Phar::webPhar</function> implements a front controller that routes HTTP calls to the correct
location within the phar archive. <function>Phar::mungServer</function> is used to modify the values of
the <varname>$_SERVER</varname> array to trick applications that process these values.
<function>Phar::interceptFileFuncs</function> instructs Phar to intercept calls to
<function>fopen</function>, <function>file_get_contents</function>, <function>opendir</function>, and
all of the stat-based functions (<function>file_exists</function>, <function>is_readable</function> and so on) and
route all relative paths to locations within the phar archive.
</para>
<para>
As an example, packaging up a release of the popular phpMyAdmin application for use as a phar archive requires
only this simple script and then <literal>phpMyAdmin.phar.tar.php</literal> can be accessed as a regular file
from your web server after modifying the user/password:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
@unlink('phpMyAdmin.phar.tar.php');
copy('phpMyAdmin-2.11.3-english.tar.gz', 'phpMyAdmin.phar.tar.php');
$a = new Phar('phpMyAdmin.phar.tar.php');
$a->startBuffering();
$a["phpMyAdmin-2.11.3-english/config.inc.php"] = '<?php
/* Servers configuration */
$i = 0;
/* Server localhost (config:root) [1] */
$i++;
$cfg[\'Servers\'][$i][\'host\'] = \'localhost\';
$cfg[\'Servers\'][$i][\'extension\'] = \'mysqli\';
$cfg[\'Servers\'][$i][\'connect_type\'] = \'tcp\';
$cfg[\'Servers\'][$i][\'compress\'] = false;
$cfg[\'Servers\'][$i][\'auth_type\'] = \'config\';
$cfg[\'Servers\'][$i][\'user\'] = \'root\';
$cfg[\'Servers\'][$i][\'password\'] = \'\';
/* End of servers configuration */
if (strpos(PHP_OS, \'WIN\') !== false) {
$cfg[\'UploadDir\'] = getcwd();
} else {
$cfg[\'UploadDir\'] = \'/tmp/pharphpmyadmin\';
@mkdir(\'/tmp/pharphpmyadmin\');
@chmod(\'/tmp/pharphpmyadmin\', 0777);
}';
$a->setStub('<?php
Phar::interceptFileFuncs();
Phar::webPhar("phpMyAdmin.phar", "phpMyAdmin-2.11.3-english/index.php");
echo "phpMyAdmin is intended to be executed from a web browser\n";
exit -1;
__HALT_COMPILER();
');
$a->stopBuffering();
?>
]]>
</programlisting>
</informalexample>
</para>
</section>
<section xml:id="phar.using.stream" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Using Phar Archives: the phar stream wrapper</title>
<para>
The Phar stream wrapper fully supports <function>fopen</function> for
read and write (not append), <function>unlink</function>, <function>stat</function>,
<function>fstat</function>, <function>fseek</function>, <function>rename</function>
and directory stream operations <function>opendir</function> and <function>rmdir</function>
and <function>mkdir</function>.
</para>
<para>
Individual file compression and per-file metadata can also be manipulated
in a Phar archive using stream contexts:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$context = stream_context_create(array('phar' =>
array('compress' => Phar::GZ)),
array('metadata' => array('user' => 'cellog')));
file_put_contents('phar://my.phar/somefile.php', 0, $context);
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
The <literal>phar</literal> stream wrapper does not operate on remote files,
and cannot operate on remote files, and so is allowed even when the
<link linkend="ini.allow-url-fopen">allow_url_fopen</link> and
<link linkend="ini.allow-url-include">allow_url_include</link> INI options
are disabled.
</para>
<para>
Although it is possible to create phar archives from scratch just using
stream operations, it is best to use the functionality built into
the Phar class. The stream wrapper is best used for read-only operations.
</para>
</section>
<section xml:id="phar.using.object" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Using Phar Archives: the Phar and PharData class</title>
<para>
The <classname>Phar</classname> class supports reading and manipulation
of Phar archives, as well as iteration through inherited functionality of
the <classname>RecursiveDirectoryIterator</classname>
class. With support for the <classname>ArrayAccess</classname>
interface, files inside a Phar archive can be accessed as if they were
part of an associative array.
</para>
<para>
The <classname>PharData</classname> class extends the <classname>Phar</classname>, and
allows creating and modifying non-executable (data) tar and zip archives even if
<literal>phar.readonly</literal>=1 in php.ini. As such,
<function>PharData::setAlias</function> and <function>PharData::setStub</function>
are both disabled as the concept of alias and stub are unique to executable phar
archives.
</para>
<para>
It is important to note that when creating a Phar archive, the full path
should be passed to the <classname>Phar</classname> object constructor.
Relative paths will fail to initialize.
</para>
<para>
Assuming that <literal>$p</literal> is a Phar object initialized as follows:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$p = new Phar('/path/to/myphar.phar', 0, 'myphar.phar');
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
An empty Phar archive will be created at <literal>/path/to/myphar.phar</literal>,
or if <literal>/path/to/myphar.phar</literal> already exists, it will be opened
again. The literal <literal>myphar.phar</literal> demonstrates the concept of an alias
that can be used to reference <literal>/path/to/myphar.phar</literal> in URLs as in:
</para>
<para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// these two calls to file_get_contents() are equivalent if
// /path/to/myphar.phar has an explicit alias of "myphar.phar"
// in its manifest, or if the phar was initialized with the
// previous example's Phar object setup
$f = file_get_contents('phar:///path/to/myphar.phar/whatever.txt');
$f = file_get_contents('phar://myphar.phar/whatever.txt');
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
With the newly created <literal>$p</literal> <classname>Phar</classname> object,
the following is possible:
<itemizedlist>
<listitem>
<simpara>
<literal>$a = $p['file.php']</literal> creates a <classname>PharFileInfo</classname>
class that refers to the contents of <literal>phar://myphar.phar/file.php</literal>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>$p['file.php'] = $v</literal> creates a new file
(<literal>phar://myphar.phar/file.php</literal>), or overwrites
an existing file within <literal>myphar.phar</literal>. <literal>$v</literal>
can be either a string or an open file pointer, in which case the entire
contents of the file will be used to create the new file. Note that
<literal>$p-&gt;addFromString('file.php', $v)</literal> is functionally
equivalent to the above. Also possible is to add the contents of a file
with <literal>$p-&gt;addFile('/path/to/file.php', 'file.php')</literal>.
Lastly, an empty directory can be created with
<literal>$p-&gt;addEmptyDir('empty')</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
<literal>isset($p['file.php'])</literal> can be used to determine
whether <literal>phar://myphar.phar/file.php</literal> exists within
<literal>myphar.phar</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
<literal>unset($p['file.php'])</literal> erases
<literal>phar://myphar.phar/file.php</literal> from
<literal>myphar.phar</literal>.
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
In addition, the <classname>Phar</classname> object is the only way to access
Phar-specific metadata, through
<function>Phar::getMetadata</function>,
and the only way to set or retrieve a Phar archive's PHP loader stub through
<function>Phar::getStub</function> and
<function>Phar::setStub</function>.
Additionally, compression for the entire Phar archive at once can only be manipulated
using the <classname>Phar</classname> class.
</para>
<para>
The full list of <classname>Phar</classname> object functionality is documented
below.
</para>
<para>
The <classname>PharFileInfo</classname> class extends the
<classname>SplFileInfo</classname>
class, and adds several methods for manipulating Phar-specific details of a file
contained within a Phar, such as manipulating compression and metadata.
</para>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->