tl;dr: How do I make PHP interpret relative paths in include/require statement from the perspective of the current file?
This is yet another question about that old issue in PHP about relative paths. Please bear with me, as I couldn't find any solution for what I am specifically trying to do.
Consider the following directory tree and files:
[www]:
index.php
config.php
[webroot]:
home.php
index.php
requires home.php
, found inside webroot
:
require('webroot/home.php');
home.php
requires config.php
, found in the parent directory:
require('../config.php');
My problem is that this won't work in my local development environment (Ubuntu 14.04 LTS / 15.10), whereas it runs flawlessly in production. Every mentioned environment is running Apache 2 and PHP 5.
Strangely, this does run locally when I run it inside my Vagrant VM (Ubuntu 12.04 LTS), accessing it from the host machine. But, right now, I cannot run a VM here.
So, why do these environments behave so differently?
This makes me believe that there must be a way to change how PHP interprets relative paths. I am currently working with a 6GB+ PHP project that is written like the example above, and I really need to avoid the amount of effort that it'll take from me to rewrite every include/require statement (using dirname(__FILE__)
or so), as well as the git merge conflicts this might cause.
EDIT: I've just remembered I actually had already asked this question here: PHP: include inside included file
The path used to resolve relative URLs like this is configured by the include_path
configuration option which has a dedicated function for setting it at runtime: set_include_path
.
Note that the set of paths to search may include .
, representing the "current working directory", which can be set with chdir
and read with getcwd
. You may also need to change this to make explicitly relative paths like ./foo.php
and ../foo.php
to work.
(I was going to recommend you used __DIR__
or $_SERVER['DOCUMENT_ROOT']
instead, but you mention that you don't want to rewrite existing code. I would still recommend to anyone else reading this to make explicit in each include where paths are relative to, to avoid odd bugs and potential security holes with the dynamic base.)
If you want to override existing functionality in place you need to either install an external library or use namespaces. Both are extra work. I'm guessing that installing an extra library probably isn't even an option.
You could try adding the paths to those folders using set_include_path.
Or you could add a global variable and several global functions like below, for all the require and include overloads, but you would still have to do a find/replace through the whole project for instances of include, require, include_once, require_once... and replace them with "include_rel"...
$include_rel_path = '.';
function include_rel($path){
global $include_rel_path;
$my_path = $include_rel_path;
//TODO maybe need to check for drive letters?
if(strpos($path, '/') === 0) { //absolutepath
$include_rel_path = preg_replace('/\/[^\/]*$/','',$path);
include($path);
} else { //relative path
$include_rel_path .= preg_replace('/\/[^\/]*$/','',$path);
include($my_path.'/'.$path);
}
$include_rel_path = $my_path;
}
You have to use auto_prepend_file. if PHP is run as an Apache module then .htaccess file to the path to your config.php
file and any PHP file accessed will automatically have the contents of the config file prepended to it.
For .htaccess
:
php_value auto_prepend_file /full/path/to/file/config.php
If your server is using CGI then set this directive in your php.ini or Keep in mind this ONLY will work on a server where If PHP is run as a CGI you need to add edit it in your php.ini
file or put it inside a .user.ini
file just without the php_value
part.
auto_prepend_file /full/path/to/file/config.php
In Nginx
you could add this line to server configuration inside location ~ \.php$
fastcgi_param PHP_VALUE "auto_prepend_file=/full/path/to/file/config.php";
Let me know if doesn't resolve your problem.
<?php
$path = $_SERVER['DOCUMENT_ROOT'];
$path .= "/Folder/File.php";
include_once($path);
?>
That should do the trick :)
index.php:
chdir('webroot');
require_once('home.php');