I am using xampp to develop my php application. Few days back I installed pear ti use DB abstraction. After that, I couldn't use include files from parent directory, however I can include from sub-driectories.
Here is what I see when I check my include path
.;E:\xampp\php\PEAR
I tried changed include path using set_include_path to the location where my files are stored, then the application failed to load Pear files.
Any help appreciated.
Easiest way to prepend to the include path stack is...
set_include_path(implode(PATH_SEPARATOR, array(
'path/to/app/includes',
'path/to/any/other/includes',
get_include_path()
)));
If you really want to use set_include_path, you can do it like this:
set_include_path(get_include_path().PATH_SEPARATOR.'path_to_parent');
Use the predefined constant DIRECTORY_SEPARATOR in case your code moves to a server that uses a different directory separator.
Personally if I needed to set the path specially for a particular site, I would try to set the path in the .htaccess file in the site's web root. It provides a more obvious place to look for site-wide configurations like the include_path. Here is the line you would put in the .htaccess file:
php_value include_path ".;E:\xampp\php\PEAR;path_to_parent"
or on a Linux server:
php_value include_path ".:some_path/PEAR:path_to_parent"
Related
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');
I am using XAMPP for PHP development, new to this, was previously familiar with WampServer. I have a require_once statement like this
require_once('config.php');
I assumed it would include the file in the current directory, but it is fetching a file from PEAR directory because the path to PEAR is also set in the include_path directive in php.ini.
However if I change the include_path to just '.' which is the current directory, it seems to work fine.
This had worked fine for me before in WampServer, no clue as to what causes this (it has always looked in the current directory before fetching form include paths). Is this a problem with PHP or something to do with XAMPP? And any solutions for this?
Well, you already found the problem: the include path directive is different.
Every include is looked up relative to the include path, the first matching file is used. If you want to explicitly use a file in a specific directory, use an absolute path:
require_once __DIR__ . '/config.php';
Is this, for example, a good idea?
require_once($_SERVER['DOCUMENT_ROOT'].'/include.php');
If you have two virtual hosts on the same server, one for live and one for development, with different Apache DocumentRoots, this would avoid having to include absolute paths when the source of the include is unknown, and may be in any directory.
(Note: file paths in the following section are relative to the web root. They would in fact be like /var/www/app/core/init.php, where /var/www/app is the web root)
For instance: I have an /core/init.php which is called using relative paths from places all over the website (/file.php, /dir/file.php or /dir/dir/file.php).
This init.php then includes several function pages, in the fund directory, a subdir of /core (as in /core/func/userfunctions.php).
So, in init.php, I can use the $_SERVER method, because it breaks if I use a relative path and try to call functions from a page like /dir/file.php.
I can't see any problem with it, but in general what could go wrong?
I've seen cases where $_SERVER['DOCUMENT_ROOT'] is not set or is not what you would expect (i.e. not set in CLI or old IIS, or invalid in certain CGI setups).
For that reason you can use dirname(__FILE__) to obtain the path of the script that line is called in. You can then reference relative paths from there e.g.
include dirname(__FILE__) . '/../../other/file.php';
I go with the above method when the directory structure of the files is known and is not subject to change.
If DOCUMENT_ROOT is not available, the following is a suitable replacement:
substr($_SERVER['SCRIPT_FILENAME'], 0, -strlen($_SERVER['SCRIPT_NAME']));
You don't need to do this. PHP looks for the included file in the document root by default.
You can use set_include_path($new_include_path) to change this behaviour, or edit include_path in the php config file.
Also, from http://php.net/manual/en/reserved.variables.server.php:
'DOCUMENT_ROOT'
The document root directory under which the current script is executing, as defined in the server's configuration file.
For example, if you use URL rewriting, you will be very happy when you find out that the includes in your /there/are/so/many/paths/in/the/url/of/this/ page are still working!
I have to deal with complex directories hierarchy, and I am facing the common trouble of include path with PHP.
I have searched the web but I haven't found anything that fit my needs.
For instance, I was using a simple directory hierarchy that never fail: no php script in the site root, only one level of subdirectory, all php script in this sublevel. To include a php file, I was simply using relative path, always starting with '../' just like in this example:
include( '../my_subdirectory/my_script.php' ) ;
This way, I can be sure to locate the file I want...
But there is some drawback:
I can't have more than one level of subdirectory (reason: when a file include a file that include another file, the path used to include the third file is not relative to the path of second file file, but relative to the path of the very first file).
Coming from a C++ background (using handmade makefile), I have always thought it was a dirty way to do it
So I want a way to include file directly from the site root (not the $_SERVER['DOCUMENT_ROOT'] because I may have independant website into subdirectory of this document_root).
I want it to be:
centralized in only one file
portable from a server to another without any change (if possible)
keep php's include simple and elegant, no complex string concat, this should work this way: "include('directory_a/directory_b/my_php_script.php')"
Using a .htaccess that contains:
php_value include_path "/var/www/my_website/"
... do it well except that the path is hardcoded into the .htaccess, annoying for some reason: in my case, I have prod, dev and testing version of the website, and the .htaccess is versionned (it contains many others things). If possible, I want an .htaccess that work everywhere. Something that set the include_path to the path of this current .htaccess would be fine.
So... What is the best practice, dealing with include() and complex directory hierarchy in PHP ?
A good way is to use an absolute path like this :
Php < 5.3 :
include(dirname(__FILE__) . '/yourfile.php');
Php 5.3 :
include(__DIR__. '/yourfile.php');
The __FILE__ constant will always point to the absolute path to the current file.
If you do this in a script in your site root:
define("ROOT_DIRECTORY", dirname(__FILE__));
and include it in every script, you can easily do relative includes:
include ROOT_DIRECTORY."/dir1/dir2/dir3/index.php";
if what you are including are PHP class structures, you may also want to look into Autoloading which is a great feature.
I think the best way to handle this, is to set an "SetEnv directive" in your vhost or httpd.conf for each environment.
httpd.conf:
SetEnv INCLUDES_DIR /var/www/my_website/
In every PHP file, you can use the following $_SERVER variable
include_once($_SERVER['INCLUDES_DIR'].'/my_subdirectory/my_script.php');
I can set the PHP include path in the php.ini:
include_path = /path/to/site/includes/
But then other websites are affected so that is no good.
I can set the PHP include in the start of every file:
$path = '/path/to/site/includes/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
But that seems like bad practice and clutters things up.
So I can make an include of that and then include it into every file:
include 'includes/config.php';
or
include '../includes/config.php';
This is what I'm doing right now, but the include path of config.php will change depending on what is including it.
Is there a better way? Does it matter?
If you're using apache as a webserver you can override (if you allow it) settings using .htaccess files. See the PHP manual for details.
Basically you put a file called .htaccess in your website root, which contains some PHP ini values. Provided you configured Apache to allow overrides, this site will use all values in your PHP config, + the values you specify in the .htaccess file.
Can be used only with PHP_INI_ALL and PHP_INI_PERDIR type directives
as stated in the page I linked. If you click through to the full listing, you see that the include path is a PHP_INI_ALL directive.
Erik Van Brakel gave, IMHO, one of the best answers.
More, if you're using Apache & Virtual hosts, you can set up includes directly in them. Using this method, you won't have to remember to leave php_admin commands in your .htaccess.
Use a php.ini file in website root, if your setup uses PHP as CGI (the most frequent case on shared hosts) with the same syntax as the server-wide php.ini; put it into .htaccess if you have PHP as an Apache module (do a phpinfo() if unsure):
php_value include_path "wherever"
Note that per-folder php.ini does not affects subfolders.
Why do you think append to include path is bad practice?
This code near top of root script shouldn't be that bad...
$path = '/path/to/site/includes/';
set_include_path($path . PATH_SEPARATOR . get_include_path());
IMHO the main advantage is that it's portable and compatible not only with Apache
EDIT: I saw a drawback of this method: small performance impact. see http://www.geeksengine.com/article/php-include-path.html
Depending on how your host is set up, you may be permitted to place a php.ini file in the root of your home directory with extra configuration directives.
Your application should have a config file written in PHP. Then include that with a relative page into every page in the program. That config file will have a variable for the path to the includes dir, templates dir, images dir, etc.
You can set include_path in your php.ini file too. I'm a perl guy, so I expect to be able to load includes and have include do the right thing. I have all my includes in a specific directory, which is added to include_path. I can do things like
require_once "ClassName.php";
I don't need to worry about relative paths or locations of files.
I've also written my own CustomRequire to do things like
function CustomRequire ($file) {
if(defined('MYINCLUDEPATH')) {
require_once MYINCLUDEPATH . "/$file";
} else {
require_once $file;
}
}
That way I can change how I do includes at a later date. Of course, you still need to find a way to include your include code :)