Tuesday, June 14, 2011

PHP - Relative paths and Phar Archives

Working with file paths and Phar archives in PHP can be tricky. The PHP code inside of a Phar file will treat relative paths as being relative to the Phar archive, *not* relative to the current working directory. Here's a short example:

Say you have the following files:
phar/index.php
test.php
my.phar
The index.php file is located inside of the phar directory. It is the bootstrap file for the phar archive:
function does_it_exist($file){
  return file_exists($file) ? "true" : "false";
}
The bootstrap file is executed when the phar file is included from a PHP script. Our bootstrap file will simply cause the function "does_it_exist" to be declared.

The file my.phar is the packaged phar archive (see the phar-util project for an excellent phar-building tool). It contains the index.php file at its root.

Let's try running different code inside of test.php and see what the results are for each run:
//Run 1:
require_once 'phar/index.php';  //PHP file
$file = __DIR__ . "/index.php"; //absolute path
echo does_it_exist($file);      //prints "false"

//Run 2:
require_once 'phar/index.php';  //PHP file
$file = "index.php";            //relative path
echo does_it_exist($file);      //prints "false"

//Run 3:
require_once 'my.phar';         //phar file
$file = __DIR__ . "/index.php"; //absolute path
echo does_it_exist($file);      //prints "false"

//Run 4:
require_once 'my.phar';         //phar file
$file = "index.php";            //relative path
echo does_it_exist($file);      //prints "true"
Look at Run 4. This code includes the phar file and passes the function a relative path. Relative to the current working directory, index.php does not exist. But relative to the contents of the phar archive, it does exist, which is why it prints "true"!

Any file paths that you manipulate inside of a phar archive must be absolute. If they are relative, the phar will treat the path as being relative to the phar archive, not relative to the current working directory, which may not be what you intended!