22

Normally we use the following code to include php files inside each other:

<?php 

include_once 'include/config.php';
// OR
include 'include/config.php'; 
// OR 
include_once $_SERVER['DOCUMENT_ROOT'].'include/config.php';
// ect...
?>

But the above codes only apply if the php files are in the root file. I mean, if we move our files into a subfolder. We need to make a change to the code we included in the php files. For example like this:

<?php 
    include_once 'subfolder/include/config.php';
    // OR
    include 'subfolder/include/config.php'; 
    // OR 
    include_once $_SERVER['DOCUMENT_ROOT'].'/subfolder/include/config.php';
    // ect...
?>

What I'm saying is that when we move our php files into the subfolder, then include_once want to see subfolder name like (include_once 'subfolder/include/config.php';). This is a challenging situation because we need to do this for the included page in many files.

For example i include the include_once $_SERVER['DOCUMENT_ROOT'].'/functions/includes.php'; from the index.php and also included this includes.php file from all php files like header.php, posts.php, and ajax_post.php . It is working fine from the root folder but if we move the files in the subfolder then include.php file not including without subfolder name.

Maybe it is also possible to do this with .htaccess.

I have made this htaccess code maybe you have a solution with htaccess. I must be say i have tryed to use RewriteBase /subfoldername/ but include files didn't worked.

Options +FollowSymLinks -MultiViews
RewriteEngine On 
RewriteBase /

RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=302,NE,L]

RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteRule ^(.*)index\.php$ /$1 [L,R=302,NC,NE]

RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

RewriteRule ^group/([\w-]+)/?$ sources/group.php?group_username=$1 [L,QSA]  
RewriteRule ^profile/([\w-]+)/?$ sources/user_profile.php?username=$1 [L,QSA]
RewriteRule ^profile/(followers|friends|photos|videos|locations|musics)/([\w-]+)/?$ sources/$1.php?username=$2 [L,QSA]     

RewriteRule ^admin/(.*)$ admin/index.php?page=$1 [L,QSA]

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]  

RewriteRule ^(.+?)/?$ index.php?pages=$1 [L,QSA]

. My responsibility is, how can we include php files without subfolder name?

AlwaysStudent
  • 1,354
  • 18
  • 49
  • 1
    One way is to configure those paths using [set_include_path](http://php.net/manual/en/function.set-include-path.php). – cteski Dec 13 '17 at 20:55
  • 2
    why dont you use relative paths – sumit Dec 13 '17 at 20:55
  • @cteski hmm it looks like a nice solution. I am going to test it. – AlwaysStudent Dec 13 '17 at 20:58
  • I usually include relative to document root using the DIRECTORY_SEPARATOR constant. Makes it all clean and portable between operating environments. `include_once($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."include_folder".DIRECTORY_SEPARATOR."included_file.php");` – Typel Dec 13 '17 at 20:59
  • @Typel What is `include_folder` , I am asking **My responsibility is, how can we include php files without subfolder name** but your answer have subfolder name?? – AlwaysStudent Dec 13 '17 at 21:02
  • @DevStud sorry I misunderstood what you were asking then. cteski has the right idea. – Typel Dec 13 '17 at 21:05
  • On smaller apps, I prefer to keep stuff like includes, templates, etc in their own folders for organization purposes. Inside my config file, I'll create variables for stuff like $incPath, $imgPath, $tplPath and then all through my code, I'll use the path variables for accessing any of my resources. If the time comes that I need to change a location, a quick modification to my config file updates my whole application. – R. Smith Dec 13 '17 at 21:22
  • @R.Smith nice solution i also using your method sometimes but i don't want to change anything after moving the php files to subfolders. Maybe there is a sharp solution. – AlwaysStudent Dec 13 '17 at 21:25
  • Added a code solution, even though I'm not a fan of it. – R. Smith Dec 13 '17 at 21:42
  • You should put them in a config .... – ArtisticPhoenix Dec 23 '17 at 09:21
  • What happens when someone creates a new include file with the same name as another file? How does this get resolved? – Nigel Ren May 31 '18 at 16:08
  • @NigelRen This is a nice question, that is why i give my htaccess rules for the solution. – AlwaysStudent May 31 '18 at 16:13

8 Answers8

15

You can use auto_prepend_file directive in your .htaccess to make a .php file included before all of your php files.

If you're using mod_php then have this line in your .htaccess:

php_value auto_prepend_file "/Applications/MAMP/htdocs/script/env.php"

Note that for PHP-FPM you need to have these equivalent line in your .user.ini file:

auto_prepend_file = "/Applications/MAMP/htdocs/script/env.php"

Then create a new file env.php in your project base directory with just one line:

<?php
   $baseDir = __dir__ . '/';
?>

This line sets a variable $baseDir that has value of your project base directory i.e. /Applications/MAMP/htdocs/script/ OR /Applications/MAMP/htdocs/subdir/script/

Then use this variable $baseDir anywhere you have to include other files such as:

include_once $baseDir.'functions/includes.php';

include_once $baseDir.'functions/get.php';
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 3
    I think this your answer will help many people. And thank you very much. You are the best for me – AlwaysStudent Jun 01 '18 at 11:23
  • Auto prepend can be very dangerous, be sure not to have any output from an auto prepend script, as this can cause header issues, and issues in some cases with downloads. – ArtisticPhoenix Jun 08 '18 at 17:33
  • Agree with that though this case is fairly simple as OP just wants access to a single global. – anubhava Jun 08 '18 at 18:13
  • @anubhava Dear your answer is working on the localhost but when i upload the files from the online server i get an 500 Internal Server Error. Can you help me about it please ? – AlwaysStudent Jul 01 '18 at 07:54
  • @anubhava Dear your answer is not working from online server because of the tobias-k user answer `https://stackoverflow.com/questions/51121579/htaccess-php-value-auto-prepend-file-gives-me-internal-500-error/51121649#51121649` :(( – AlwaysStudent Jul 01 '18 at 09:29
  • 1
    @Azzo: This answer would work for php-gpm also with a minor change. See this post: https://medium.com/@jacksonpauls/moving-from-mod-php-to-php-fpm-914125a7f336 – anubhava Jul 01 '18 at 09:53
  • @anubhava Dear, thanks for your edit. But you know not everyone can undetstand how to change user.ini file. The answer mybe correct but not easy for sell business. – AlwaysStudent Jul 01 '18 at 09:59
  • If one understands how to create .htaccess file then creating a simple 1 line `.user.ini` won't be a problem in your site root. – anubhava Jul 01 '18 at 10:01
  • Also check this official documentation on user.ini: http://php.net/manual/en/configuration.file.per-user.php – anubhava Jul 01 '18 at 10:03
  • @anubhava Sor for this question, where is the user.ini file ? – AlwaysStudent Jul 01 '18 at 10:06
  • It should be in site root directory (same place where .htaccess is kept) – anubhava Jul 01 '18 at 10:09
  • @anubhava No, there is not have any user.ini file – AlwaysStudent Jul 01 '18 at 10:12
  • @anubhava Ok, i have created user.ini file from the subfolder and removed this `php_value auto_prepend_file "/Applications/MAMP/htdocs/script/env.php"` from htaccess and added `auto_prepend_file = "/Applications/MAMP/htdocs/script/env.php"` in the user.ini file but i $baseDir is not including ? – AlwaysStudent Jul 01 '18 at 10:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174112/discussion-between-azzo-and-anubhava). – AlwaysStudent Jul 01 '18 at 10:20
  • hi @anubhava : can you join the chat plz at https://chat.stackoverflow.com/rooms/174112/discussion-between-azzo-and-anubhava – noobie-php Jul 24 '18 at 15:28
  • @anubhava Dear i need your little help. Can you help me please ? – AlwaysStudent Nov 27 '18 at 12:59
  • @anubhava The answer not give me a multiple amoji result just showing one result. I think there is a regex problem. https://stackoverflow.com/questions/53497765/replace-if-key-is-in-a-text/53498439#53498439 – AlwaysStudent Nov 27 '18 at 13:03
6

You have to use function set_include_path() and somewhere in your bootstrap.php or index.php add next code:

<?php
$path = '/usr/pathToYourDir';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);

now everywhere below you can write this:

include_once 'include/config.php';
// or
include_once 'include/db/index.php';
// etc

And in case you need to move your code into another directory - you have only to change value of path varibalbe $path = '/usr/pathToYourDir'; to new path to your directory.

cn007b
  • 16,596
  • 7
  • 59
  • 74
5

Ok, I'm not a fan of doing this, but it will get the job done, as requested:

$newpath="";

$dirs = array_filter(glob('*'), 'is_dir');
foreach ($dirs as $location) {
    $newpath .= PATH_SEPARATOR . $location; 
}
set_include_path(get_include_path() . $newpath);

The above code will find all subfolders from where this file is running, and add them all to the current include path. by changing the glob from:

glob('*') 

to

glob('includes/*')  or glob('includes' . DIRECTORY_SEPARATOR . '*')

You can restrict it to only subfolders under includes.

The above is not tested, I just threw the code together, but it illustrates a way to do what you're asking for.

I would still recommend putting files in determined locations rather than trying to include them from anywhere.

R. Smith
  • 551
  • 4
  • 10
5

This is how I would do it.

//----- some global location like index.php

if(!defined("CONFIG_PATH")) define("PATH_CONFIG", __DIR__."/include/");

//------------ then later in some other file

if(!defined("CONFIG_PATH"))die("Config path is not defined.");

include_once CONFIG_PATH.'config.php';

Then when you change it you just update

if(!defined("CONFIG_PATH")) define("PATH_CONFIG", __DIR__."/include/subfolder/");

I would say this is the "Traditional" way to do it, and it's perfectly fine to use a global constant for this. It's not something you want changing at run time. You need access to it in many places, potentially. You can check if your files are accessed properly .. etc.

Many many many, MVC frameworks do it this exact way.

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
  • Globals are globals and they can make integrating other frameworks/libraries/scripts difficult without adequate name spacing. – Progrock Dec 23 '17 at 10:28
2

Here's an example of an approach that requires your files upfront via the auto_prepend_file directive.

bootstrap.php:

<?php

$require_upfront = function($dir) {
    require_once $dir . '/one.php';
    require_once $dir . '/two.php';
};

$require_upfront(__DIR__ . '/inc');

Add to php config, here .htaccess example:

php_value auto_prepend_file "/abs/path/to/bootstrap.php"
Progrock
  • 7,373
  • 1
  • 19
  • 25
  • This works fine tell you do a download and realize something in bootstrap.php is outputting stuff. Then it blows up your headers or includes content in your download file. It's also hard to trackdown where that content came from. – ArtisticPhoenix Dec 23 '17 at 09:34
  • Yes it's good to be aware of the limitations of any approach. Good documentation/commenting would help here. – Progrock Dec 23 '17 at 10:30
  • I had a network guy "fix" some stuff with our reverse proxy with that took us about 2 weeks to figure it out. – ArtisticPhoenix Dec 23 '17 at 10:42
  • You would be surprised how hard it is to fine `\n\n` at the end. I never close my PHP tags now... lol – ArtisticPhoenix Dec 23 '17 at 10:47
  • Trailing and preceding whitespace output/issues is not particular to the solution I present here. – Progrock Dec 23 '17 at 12:45
2

If you have the file's name unique in all server, you can make a research of this using a research like this.

I think that this solution isn't better when this script run a lot of, but you can include if the include function fails, using try and catch (if you use this method watch the php version) or if you know that this path change once a day you can make a file which is launched with routine.

If you make this, you need to store this path, but I don't know if there is a method for make global variable. My solution is to store or in a DB or in a file.

I hope I have helped you.

L. Ros.
  • 114
  • 1
  • 2
  • 9
  • I remember that this method don't work if you have different file into different folder with the same name. – L. Ros. Dec 23 '17 at 07:59
1

What I understand from the answer https://stackoverflow.com/a/50632691/7362396 is that you need to include files based on the directory of the entrypoint script.

A solution for this without the need for Apache or php.ini auto_prepend_file could be to use getcwd(). It returns the current working directory, which should be the path of the entrypoint/main script, even when called in included files.

Can you try if simply using getcwd() instead of $baseDir works?:

include_once getcwd().'/functions/includes.php';

include_once getcwd().'/functions/get.php';
Tobias K.
  • 2,997
  • 2
  • 12
  • 29
0

Using Apache to fix your app is solving it at the wrong level.

If you have to update a bunch of files in your code when the location of a file changes, that is your code telling you that you have made a bad architectural decision. So fix the actual problem and stop repeating yourself.

Define where your includes live in one place, and then when needed, update that one place accordingly.

One way to do this is set a constant at the root of your app. This assumes you have a bit of code at the root of your app that is called on every page. This would likely be index.php or a script included by index.php:

// index.php or a file included by index.php
const MY_INCLUDE_PATH = __DIR__ . '/path/to/subfolder`

Then your other scripts can call include using the constant:

// some other script included to handle the page
include MY_INCLUDE_PATH . '/config.php';
include MY_INCLUDE_PATH . '/some-other-include.php';

Although if they all want to include the config.php file, maybe just go ahead and include it in your index.php.

This is not a "bad" global you want to avoid. It is using constants as they are intended. Constants are part of the namespace, if you are using a namespace for your app.

This assumes there is one include subfolder that sometimes changes places and a script somewhere that is a part of every request. Is that correct? If not, please post your directory structure.

A function would also work, and could include logic based on things such as the path of the calling script:

// index.php or a file included by index.php
my_include_function($path) {
  //do stuff
}

The other scripts might call this function like so:

// some other script included to handle the request
my_include_function(__FILE__);

Then when things change, you simply update one function in one file.

This all assumes you have an index.php or similar script that handles every request and can be the single point of control for defining the function or constant. If that's not the case, it should be!

Updating your code to use a router (here is one) would take maybe 10 minutes and potentially simplify that gnarly .htaccess file you posted.

jstur
  • 659
  • 6
  • 12