Related
I'm having trouble understanding the ruleset regarding PHP relative include paths. If I run file A.PHP- and file A.PHP includes file B.PHP which includes file C.PHP, should the relative path to C.PHP be in relation to the location of B.PHP, or to the location of A.PHP? That is, does it matter which file the include is called from, or only what the current working directory is- and what determines the current working directory?
It's relative to the main script, in this case A.php. Remember that include() just inserts code into the currently running script.
That is, does it matter which file the include is called from
No.
If you want to make it matter, and do an include relative to B.php, use the __FILE__ constant (or __DIR__ since PHP 5.2 IIRC) which will always point to the literal current file that the line of code is located in.
include(dirname(__FILE__)."/C.PHP");
#Pekka got me there, but just want to share what I learned:
getcwd() returns the directory where the file you started executing resides.
dirname(__FILE__) returns the directory of the file containing the currently executing code.
Using these two functions, you can always build an include path relative to what you need.
e.g., if b.php and c.php share a directory, b.php can include c.php like:
include(dirname(__FILE__).'/c.php');
no matter where b.php was called from.
In fact, this is the preferred way of establishing relative paths, as the extra code frees PHP from having to iterate through the include_path in the attempt to locate the target file.
Sources:
Difference Between getcwd() and dirname(__FILE__) ? Which should I use?
Why you should use dirname(__FILE__)
The accepted answer of Pekka is incomplete and, in a general context, misleading. If the file is provided as a relative path, the called language construct include will search for it in the following way.
First, it will go through the paths of the environment variable include_path, which can be set with ini_set. If this fails, it will search in the calling script's own directory dirname(__FILE__) (__DIR__ with php >= 5.3.) If this also fails, only then it will search in the working directory ! It just turns out that, by default, the environment variable include_path begins with ., which is the current working directory. That is the only reason why it searches first in the current working directory. See http://php.net/manual/en/function.include.php.
Files are included based on the file path given or, if none is given,
the include_path specified. If the file isn't found in the
include_path, include will finally check in the calling script's own
directory and the current working directory before failing.
So, the correct answer to the first part of the question is that it does matter where is located the included calling script. The answer to the last part of the question is that the initial working directory, in a web server context, is the directory of the called script, the script that includes all the others while being handled by PHP. In a command line context, the initial working directory is whatever it is when php is invoked at the prompt, not necessarily the directory where the called script is located. The current working directory, however, can be changed at run time with the PHP function chdir. See http://php.net/manual/en/function.chdir.php.
This paragraph is added to comment on other answers. Some have mentioned that relying on include_path is less robust and thus it is preferable to use full paths such as ./path or __DIR__ . /path. Some went as far as saying that relying on the working directory . itself is not safe, because it can be changed. However, some times, you need to rely on environment values. For example, you might want set include_path empty, so that the directory of the calling script is the first place that it will search, even before the current working directory. The code might be already written and updated regularly from external sources and you do not want to reinsert the prefix __DIR__ each time the code is updated.
If include path doesn't start with ./ or ../, e.g.:
include 'C.php'; // precedence: include_path (which include '.' at first),
// then path of current `.php` file (i.e. `B.php`), then `.`.
If include path starts with ./ or ../, e.g.:
include './C.php'; // relative to '.'
include '../C.php'; // also relative to '.'
The . or .. above is relative to getcwd(), which defaults to the path of the entry .php file (i.e. A.php).
Tested on PHP 5.4.3 (Build Date : May 8 2012 00:47:34).
(Also note that chdir() can change the output of getcwd().)
Short answer: it's relative to the including script.
TFM explains it correctly:
If the file isn't found in the include_path, include will check in the calling script's directory and the current working directory
So, if /app/main.php says include("./inc.php") that will find /app/inc.php.
The ./ is not strictly necessary but removes any dependency on include_path.
I would not rely on finding include files in the current working directory in case someone changes it with chdir().
dir
-> a.php
-> c.php
- dir2
-> b.php
To include a in b you need to include("../a.php");
To include b in c you need to include("dir2/b.php");
I have a directory root:
index.php
includes/
template.php
testfile.php
phpFiles/
processInput.php
testfile.php
index.php:
require_once("includes/template.php");
template.php:
require_once("includes/phpFiles/processInput.php")
processInput.php:
require_once("testfile.php")
require_once("../testfile.php")
This code will work when you run index.php, of course it will not work when you run template.php.
As you can see, index.php includes template.php like normal. But in template.php, you have to include like if you are in the directory that index.php is in. But then, in processInput.php, you include as if you are in the directory that processInput.php is in.
Why is this happening, and how can I fix it so that the include path is always the directory of the file that the require is done in? The second included file have the same include path as the requested file, but the next one does not.
Thanks for your help!
EDIT: The strange thing is that I've included classes in a class folder. And it included other files as it is supposed to, even though the paths are relative. WHY does this happen, and how can I fix it?
VERY IMPORTANT EDIT: I just realized that all this is because in my example, the inclusion in includes/phpFiles/processInput.php includes a file in the same directory: require_once("file in same dir.php"); This is the reason. If you are including a file with out specifying anything more than the filename, the include_path is actually the dir where the file the require is written in is in. Can anyone confirm this?
Use an absolute path.
require_once($_SERVER['DOCUMENT_ROOT']."/includes/phpFiles/processInput.php");
Use a similar form for all your required files and they will work no matter where you are.
You can do this in a few ways, amongst others:
Use set_include_path to control the directories from where to perform require() calls.
Define a common absolute base path in a constant that you define in index.php and use that in every require() statement (e.g. require(BASEPATH . '/includes/template.php')).
Use relative paths everywhere and leverage dirname(__FILE__) or __DIR__ to turn them into absolute paths. For instance: require(__DIR__ . '/phpFiles/processInput.php');
By default, the current working directory is used in the include path; you can verify this by inspecting the output of get_include_path(). However, this is not relative to where the include() is made from; it's relative to the main executing script.
You're using relative paths. You need to use absolute paths: $_SERVER['DOCUMENT_ROOT'].
When you include/require, you are basically temporarily moving all code from one file, to another.
so if file1.php (which is located in root) contains:
require("folder/file.php");
and you include file1.php in file2.php (which is in a different location (say folder directory for example):
file2.php:
require("../file1.php");
Now all of file1.php code is in file2.php. So file2.php will look like this:
require("../file1.php");
require("folder/file.php");//but because file2.php is already in the `folder` directory, this path does not exist...
index.php:
require_once("includes/template.php");
template.php:
require_once("includes/phpFiles/processInput.php")
Your directory structure is off. The file inclusion is being seen from the file you're using it from. So, "template.php" is looking for an "includes/" folder in its current folder (/includes/).
As others are saying, use absolute paths, which will make sure you're always going at it from the file system root, or use:
require_once("phpFiles/processInput.php")
In your template.php file (which is far more likely to break if you ever move things around, which is why others all recommend using absolute paths from the file system root).
BTW, if you're using "index.php" as some kind of framework system, you can consider defining a variable that stores the address of common files such as:
define('APPLICATION_PATH', realpath(dirname(__FILE__));
define('PHPFILES_PATH', APPLICAITON_PATH . '/includes/phpFiles/');
I'm having trouble understanding the ruleset regarding PHP relative include paths. If I run file A.PHP- and file A.PHP includes file B.PHP which includes file C.PHP, should the relative path to C.PHP be in relation to the location of B.PHP, or to the location of A.PHP? That is, does it matter which file the include is called from, or only what the current working directory is- and what determines the current working directory?
It's relative to the main script, in this case A.php. Remember that include() just inserts code into the currently running script.
That is, does it matter which file the include is called from
No.
If you want to make it matter, and do an include relative to B.php, use the __FILE__ constant (or __DIR__ since PHP 5.2 IIRC) which will always point to the literal current file that the line of code is located in.
include(dirname(__FILE__)."/C.PHP");
#Pekka got me there, but just want to share what I learned:
getcwd() returns the directory where the file you started executing resides.
dirname(__FILE__) returns the directory of the file containing the currently executing code.
Using these two functions, you can always build an include path relative to what you need.
e.g., if b.php and c.php share a directory, b.php can include c.php like:
include(dirname(__FILE__).'/c.php');
no matter where b.php was called from.
In fact, this is the preferred way of establishing relative paths, as the extra code frees PHP from having to iterate through the include_path in the attempt to locate the target file.
Sources:
Difference Between getcwd() and dirname(__FILE__) ? Which should I use?
Why you should use dirname(__FILE__)
The accepted answer of Pekka is incomplete and, in a general context, misleading. If the file is provided as a relative path, the called language construct include will search for it in the following way.
First, it will go through the paths of the environment variable include_path, which can be set with ini_set. If this fails, it will search in the calling script's own directory dirname(__FILE__) (__DIR__ with php >= 5.3.) If this also fails, only then it will search in the working directory ! It just turns out that, by default, the environment variable include_path begins with ., which is the current working directory. That is the only reason why it searches first in the current working directory. See http://php.net/manual/en/function.include.php.
Files are included based on the file path given or, if none is given,
the include_path specified. If the file isn't found in the
include_path, include will finally check in the calling script's own
directory and the current working directory before failing.
So, the correct answer to the first part of the question is that it does matter where is located the included calling script. The answer to the last part of the question is that the initial working directory, in a web server context, is the directory of the called script, the script that includes all the others while being handled by PHP. In a command line context, the initial working directory is whatever it is when php is invoked at the prompt, not necessarily the directory where the called script is located. The current working directory, however, can be changed at run time with the PHP function chdir. See http://php.net/manual/en/function.chdir.php.
This paragraph is added to comment on other answers. Some have mentioned that relying on include_path is less robust and thus it is preferable to use full paths such as ./path or __DIR__ . /path. Some went as far as saying that relying on the working directory . itself is not safe, because it can be changed. However, some times, you need to rely on environment values. For example, you might want set include_path empty, so that the directory of the calling script is the first place that it will search, even before the current working directory. The code might be already written and updated regularly from external sources and you do not want to reinsert the prefix __DIR__ each time the code is updated.
If include path doesn't start with ./ or ../, e.g.:
include 'C.php'; // precedence: include_path (which include '.' at first),
// then path of current `.php` file (i.e. `B.php`), then `.`.
If include path starts with ./ or ../, e.g.:
include './C.php'; // relative to '.'
include '../C.php'; // also relative to '.'
The . or .. above is relative to getcwd(), which defaults to the path of the entry .php file (i.e. A.php).
Tested on PHP 5.4.3 (Build Date : May 8 2012 00:47:34).
(Also note that chdir() can change the output of getcwd().)
Short answer: it's relative to the including script.
TFM explains it correctly:
If the file isn't found in the include_path, include will check in the calling script's directory and the current working directory
So, if /app/main.php says include("./inc.php") that will find /app/inc.php.
The ./ is not strictly necessary but removes any dependency on include_path.
I would not rely on finding include files in the current working directory in case someone changes it with chdir().
dir
-> a.php
-> c.php
- dir2
-> b.php
To include a in b you need to include("../a.php");
To include b in c you need to include("dir2/b.php");
I have a site where the PHP include path is /usr/share/php
Within this path I have a sub-folder containing some utility files, e.g. /usr/share/php/utils. my_session.php is one of these utility files.
My application calls
require ("my_session.php");
and this works even though the file is actually within the utils folder.
I am trying to replicate this site in another installation and I am getting the error:
Failed opening required 'my_session.php' (include_path='.:/usr/share/php)
My question is:
Should the php include path also include files in sub-folders in the include path?
This appears to be the case on my original site and I don't know why the behaviour seems to be different on the second site.
According to PHP documentation when you try to include a file, only paths listed in the include_path directive are checked. PHP is not supposed to check their subfolders.
My guess would be that this fails because you are using a relative path for the require.
Your include_path is defined as .:/usr/share/php. That means only two folders will be checked when require('my_session.php') gets executed:
the current path
the folder /usr/share/php
I don't know your folder structure, so let's just imagine one:
my_project
- app
-- index.php
- lib
-- my_session.php
Now, if my_project/app/index.php tries to require('my_session.php') this will fail, because the current folder at the time executing the require is my_project/app/ and there is no file entry of my_session.php relative to my_project/app/ (it's relative to my_project/lib/ instead).
Long story short: Try to to use an absolute path instead of your relative one, e.g.
require('/var/www/html/my_project/lib/my_session.php');
Edit: removed and its subfolders, which was wrong. Too much __autoload in my brain^^
Two solutions:
Add /usr/share/php/utils to your include_path.
or
Include your file with require ("utils/my_session.php");
As many do I have a config.php file in the root of a web app that I want to include in almost every other php file. So most of them have a line like:
require_once("config.php");
or sometimes
require_once("../config.php");
or even
require_once("../../config.php");
But I never get it right the first time. I can't figure out what php is going to consider to be the current working directory when reading one of these files. It is apparently not the directory where the file containing the require_once() call is made because I can have two files in the same directory that have different paths for the config.php.
How I have a situation where one path is correct for refreshing the page but an ajax can that updates part of the page requires a different path to the config.php in the require_once() statement;
What's the secret? From where is that path evaluated?
Shoot, I was afraid this wouldn't be a common problem - This is occurring under apache 2.2.8 and PHP 5.2.6 running on windows.
The current working directory for PHP is the directory in which the called script file is located. If your files looked like this:
/A
foo.php
tar.php
B/
bar.php
If you call foo.php (ex: http://example.com/foo.php), the working directory will be /A/. If you call bar.php (ex: http://example.com/B/bar.php), the working directory will be /A/B/.
There is where it gets tricky. Let us say that foo.php is such:
<?php
require_once( 'B/bar.php' );
?>
And bar.php is:
<?php
require_once( 'tar.php');
?>
If we call foo.php, then bar.php will successfully call tar.php because tar.php and foo.php are in the same directory which happens to be the working directory. If you instead call bar.php, it will fail.
Generally you will see either in all files:
require_once( realpath( dirname( __FILE__ ) ).'/../../path/to/file.php' );
or with the config file:
// config file
define( "APP_ROOT", realpath( dirname( __FILE__ ) ).'/' );
with the rest of the files using:
require_once( APP_ROOT.'../../path/to/file.php' );
I like to do this:
require_once(dirname(__FILE__)."/../_include/header.inc");
That way your paths can always be relative to the current file location.
I use the dirname(__FILE__) thing like bobwienholt most the time, but what it could pay to do is have a base entry point that loads all your other code that defines a constant refereing to the root of the project, ie
define("ROOT",dirname(__FILE__).'/' );
and then later all you need to know is where the path is relative to root, ie:
require(ROOT . "/lib/tool/error.php");
note,
you should REALLY avoid paths with "../" at the start of them, they are not relative to the file, but relative to where you ARE and this creates broken-ass code.
cd foo
php bar/baz.php
-> some error saying it cant find the file
cd bar
php baz.php
-> suddenly working.
Important
If you use "../" notation, it takes complete ignorance of the PHP Include Path, And ONLY considers where the person whom is running it is.
I include this code at the top of every page:
//get basic page variables
$self=$_SERVER['PHP_SELF'];
$thispath=dirname($_SERVER['PHP_SELF']);
$sitebasepath=$_SERVER['DOCUMENT_ROOT'];
//include the global settings, variables and includes
include_once("$sitebasepath/globals/global.include.php");
Include and require both take either a relative path or the full rooted path. I prefer working with the full path and make all my references like the inlcude statement above. This allows me to enter a general variable $sitebasepath that handles account specific information that may change from machine to machine and then simply type the path from the webroot, ie. /globals/whatever_file.php
I also use the $self variable in forms that may call themselves to handle data input.
Hope that helps.
If you have sufficient access rights, try to modify PHP's include_path setting for the whole site. If you cannot do that, you'll either have to route every request through the same PHP script (eg. using Apache mod_rewrite) or you'll have to use an "initialization" script that sets up the include_path:
$includeDir = realpath(dirname(__FILE__) . '/include');
ini_set('include_path', $includeDir . PATH_SEPARATOR . ini_get('include_path'));
After that file is included, use paths relative to the include directory:
require_once '../init.php'; // The init-script
require_once 'MyFile.php'; // Includes /include/MyFile.php
Since require and require_once are very similar to include and include_once, all the documentation is posted under the "include" functions doc area on php.net From that page
Files for including are first looked
for in each include_path entry
relative to the current working
directory, and then in the directory
of current script. E.g. if your
include_path is libraries, current
working directory is /www/, you
included include/a.php and there is
include "b.php" in that file, b.php
is first looked in /www/libraries/
and then in /www/include/. If filename
begins with ./ or ../, it is looked
only in the current working directory.
Further, you can find all the current include paths by doing a "php -i" from the command line. You can edit the include path in your php.ini file, and also via ini_set(). You can also run the php_info() function in your page to get a printout of your env vars if the CLI is inconvenient.
The only place I've seen the path evaluated from is the file that you are currently editing. I've never had any problems with it, but if you are, you might want to provide more information (PHP version, OS, etc).
The path of the PHP file requested in the original GET or POST is essentially the 'working directory' of that script. Any "included" or "required" scripts will inherit that as their working directory as well.
I will either use absolute paths in require statements or modify PHP's include_path to include any path in my app I may want to use to save me the extra typing. You'll find that in php.ini.
include_path = ".:/list/of/paths/:/another/path/:/and/another/one"
I don't know if it'll help you out in this particular instance but the magical constants like FILE and DIR can come in handy if you ever need to know the path a particular file is running in.
http://us2.php.net/manual/en/language.constants.predefined.php
Take a look at the function getcwd. http://us2.php.net/getcwd