How to create a Phar archive without index? - php

I'm trying to make a Phar archive with one of my lib. The lib is just a bunch of classes organized into folders and subfolders. No index.php at all here, just a static Config class to call to initiate the autoloader.
Anyway, I built a archive like this :
$phar = new Phar(__DIR__ . '/lis.phar',0,'lib.phar');
$phar->buildFromDirectory(__DIR__ . '/class','/\.php$');
$phar->stopBuffering();
After that I'm trying to use the phar like this :
require('lib.phar');
Config::register(); // Config is in the phar
But I get the following error :
Warning: include(phar://D:\wamp\www_test\phar\lib.phar/index.php)
[function.include]: failed to open stream: phar error: "index.php" is
not a file in phar "D:/wamp/www/_test/phar/lib.phar" in
D:\wamp\www_test\phar\lib.phar on line 9
How can I make a phar archive without any index.php file inside it ? In fact I just need the archive to be a container for my files, no need to auto execute anything.

First of all, i think you have to startBuffering() before stopBuffering(). And I might think that buildFromDirectory does this internally for you.
You don't need to do stopBuffering() for "sealing" the archive. Its ready "on the fly".
So second: You can watch the defaultStub (which is used in your code implicity) like this:
$phar->setDefaultStub();
var_dump($phar->getStub());
Its a littly bit cryptic, but you will figure it out. It does check for phar stream wrapper support (in 5.3) and if not it extracts the contents to temp file and then executes the Phar::START constant File - which is by default "index.php". And of course it does Phar::interceptFileFuncs() and sets the include path, which makes the phar working "magic". But your question sounds like you only need an archive for your libs. So you're better off with using the "PharData" class. Haven't tried it yet, but the documentation says so.

Related

Include PHP PHAR without .phar extension

I'm having trouble including a PHAR into my application bootstrapping code. I'm attempting to include the phpunit/phpunit PHAR to have the PHPUnit classes available in my application.
Given I have the following directory structure:
/path/to/code/
app.php
phpunit
Where phpunit is the PHPUnit as a PHAR, and app.php contains:
<?php
$phar = 'phar://' . __DIR__ . '/phpunit';
include $phar;
assert(class_exists('\\PHPUnit\\Framework\\TestCase'));
I get the following error:
PHP Warning: include(phar:///path/to/code/phpunit): failed to open stream:
phar error: no directory in "phar:///path/to/code/phpunit",
must have at least phar:///path/to/code/phpunit/ for root directory
(always use full path to a new phar) in /path/to/code/app.php on line 4
But when I rename the PHAR to phpunit.phar, and include that instead using
<?php
$phar = 'phar://' . __DIR__ . '/phpunit.phar';
include $phar;
assert(class_exists('\\PHPUnit\\Framework\\TestCase'));
The code works fine, and the TestCase class exists.
Why doesn't the first version work, and what does the error about "full path to a new phar" mean?
My PHP version is 7.2, and the PHPUnit PHAR is on version 7.* which has been installed with Phive.
"Why don't you just include using the .phar extension?"
I want to be able to use the PHPUnit PHAR as a binary without the .phar extension to keep things cleaner.
Why doesn't the first version work
Based on the source code, you should be able to use a mark the phar as executable and use it without an extension, but if you do that, I am not sure you can run it.
* if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
* if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
* the first extension as the filename extension
*
* if an extension is found, it sets ext_str to the location of the file extension in filename,
* and ext_len to the length of the extension.
* for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
* the calling function to use "alias" as the phar alias
*
* the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
* extension rules, not to iterate.
what does the error about "full path to a new phar" mean?
I think they are trying to convey that you cannot pass a partial path to a phar.
I want to be able to use the PHPUnit PHAR as a binary without the .phar extension to keep things cleaner.
You could always just symlink or alias the phar file to an extensionless name.
Omit using the phar:// stream since you're accessing the (outer) Phar file. Using phar:// actually tries to access resources inside a Phar archive.
<?php
$phar = __DIR__ . '/phpunit';
include $phar;
assert(class_exists('\\PHPUnit\\Framework\\TestCase'));

Extract extensionless files using Phar

Using PHPs Phar, how can I specify which type of file I have, when it does not have and extension?
I have a directory of files with randomly generated names, all files are tar.gz and have the same structure, I want to extract only a single file, config.xml:
Using:
$phar = new PharData($source_file);
$phar->extractTo($tmp, 'config.xml');
I get the following error:
PHP Fatal error: Uncaught UnexpectedValueException: Cannot create phar '/path/to/fkd20c3nd', file extension (or combination) not recognised or the directory does not exist in /path/to/my_script.php:123
However, this is only because the file is randomly named on disk, i.e.
fkd20c3nd
If I just rename this to
fkd20c3nd.tar.gz
Phar works just fine.
Question being
How can I use Phar to extract a file that is missing the extension, besides making a copy of it first, with a new name? Can I simply tell Phar the file type?
.phar file names need to contain at least a dot in the middle of its name so that the file name.
The technical reason for this is that you can access files inside a phar by passing its combined path like "/path/to/my.phar/README.rst", and without a dot it would not work.
I know in your case you don't need this, but the same internal functions are used to detect the correctness of a phar name.

Calling files inside PHAR

I know that you can call files using require 'phar://pharname.phar/path/to/file.php'; but what about when both files are in the same PHAR? I tried using require 'path/to/file.php'; but that throws an error which makes sense since the file is in the packaged phar and not in the directory it's in.
A phar file has an alias that can be used to address files inside the archive:
Inside a phar file with the alias foo.phar you can do
include 'phar://foo.phar/path/to/file.php';
to include a file from the same archive. See the Phar::__construct() manual page for another example.

how to get a .phar file real directory within the phar file code?

I am trying to create a php executable (a phar file) for generating some files, and I would like to know how to get the real path of the phar file (within the phar file code).
What I want to do is to create a folder in the same level of the phar file and create the new files there, but realpath(__DIR__.'/../') does not seem to work.
Thanks
As shown in https://stackoverflow.com/a/28775172/282601 the __FILE__ constant has the full path with the scheme:
phar:///home/cweiske/Dev/test/phar/test.phar/path/to/foo.php
__DIR__ is similar:
phar:///home/cweiske/Dev/test/phar/test.phar/path/to
So when calling realpath(__DIR__) you still have the phar:// prefix that prevents you from loading the file.
You have to remove the phar:// scheme as well as the path of the file inside the .phar to get the phar location with __DIR__.
Much easier is Phar::running(false), which simply returns the path:
/home/cweiske/Dev/test/phar/test.phar
the answer is
$string = 'phar://E:/php/www/my.phar';
$string = pathinfo($string);
$_dir_ = parse_url($string['dirname']);
echo $_dir_['host'].':/'.$_dir_['path'];
result
E:/php/www

PHP working with files inside an archive

Is there a PHP supported way to work with an archive of files (.zip, .tar or any other archive) same way we work with a folders?
For example if in our root "/www/" directory there is an archive "/www/catalog.zip" that contains .php files, would it be possible to include this archive with PHP so that PHP would know what is inside the archive and if required to include a file (for example test.php that is inside the catalog.zip) we can do so without extracting the "catalog.zip" archive?
Not sure if something like this exists (of course it would be possible to build a application to do something like this, but it would be resource if done with PHP using extract read/remove)
or maybe there is something similar that can be used?
Perhaps something like ZipArchive::getStream together with stream_get_contents would get you the file content but I'm not sure how you'd include it - don't think php can include from stdin

Categories