Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP relative path: can I configure it?

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

like image 592
Gui Imamura Avatar asked Dec 14 '15 17:12

Gui Imamura


People also ask

How do you specify relative paths?

A relative path refers to a location that is relative to a current directory. Relative paths make use of two special symbols, a dot (.) and a double-dot (..), which translate into the current directory and the parent directory. Double dots are used for moving up in the hierarchy.

Should I use absolute or relative path?

Relative links show the path to the file or refer to the file itself. A relative URL is useful within a site to transfer a user from point to point within the same domain. Absolute links are good when you want to send the user to a page that is outside of your server.

What is relative path in PHP?

Relative pathsIf you don't supply the root, it means that your path is relative. The simplest example of relative path is just a file name, like index. html . So one should be careful with relative paths. If your current directory is /about/ then index.

Why do we use relative path?

A relative path is a way to specify the location of a directory relative to another directory. For example, suppose your documents are in C:\Sample\Documents and your index is in C:\Sample\Index. The absolute path for the documents would be C:\Sample\Documents.


2 Answers

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.)

like image 57
IMSoP Avatar answered Oct 13 '22 19:10

IMSoP


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;
}
like image 31
Nick Kuznia Avatar answered Oct 13 '22 18:10

Nick Kuznia