1

I've never seen anything like this.

File structure:

  • somefolder/base.php
  • includes/stuff.php
  • includes/constants.php

base.php:

<?php require("../includes/stuff.php"); ?>

stuff.php:

<?php 
   require("constants.php"); 
   echo "Welcome to stuff.php";
?>

constants.php:

<?php echo "IMPORTANT CONSTANTS DEFINED HERE!";  ?>

Result:

Welcome to stuff.php

Why doesn't it display the constant.php message?! I'll tell you what isn't the problem: it isn't the php code.

I started off with some complex files where the constants file was actually DEFINE()-ing some constants and for some reason the only the first few constants were working. I ended up disabling all the extraneous code including the DEFINE()'s and just having echo statements and this problem still kept staring me in the face. And by the way how could some of the defined constants make it through but not any echo's, regardless of the order of the code?

So I finally realized this was absurd and decided to just create some new files as a test. Those ones worked. Or maybe they didn't, I forget. Anyway I have had some measure of success by creating new files and experimenting with moving them around and copying code from one file to another but there hardly seems to be any rhyme or reason to it.

Wow, this just in: I got the constants.php file working under a different name but when I changed it to constants.php it stopped working! I tried clearing the cache/opening in a different browser and restarting the server but none of it helps. I feel like either I or my computer is on drugs. Gaaaahh!!!


EDIT

Aha. I left out one very important piece of information it looks like. One file I didn't mention.

  • somefolder/constants.php

That file was being included instead of the includes/constants.php. That's why I wasn't getting any missing file errors. That was totally confusing things! I expected that sub-includes happen before higher level includes so stuff.php would look for constants.php in it's own directory but I guess base.php includes stuff.php and THEN base.php does the include specified in stuff.php which means the include is relative to base.php. So absolute paths is the solution after all.

Additional edit:

Very interesting. I was still puzzled why it worked before when I simply changed the name of includes/constants.php (to constanza.php for example). It looks like file inclusion isn't so cut and dry. If there are two files with the same name it will prefer the one relative to the parent file doing the including. But if it has no choice it will do it relative to the child just fine.

Moss
  • 3,695
  • 6
  • 40
  • 60
  • Enable error reporting by setting error_reporting and display_errors. – Sjoerd Jun 23 '10 at 06:42
  • I already had it displaying warnings and errors but I added error_reporting(E_ALL); ?> to the top of every file just to see. No difference. But the reporting does work. If I use the full original constants.php it complains "Notice: Use of undefined constant TBL_USERS" when I try to echo the constant from the base file. – Moss Jun 23 '10 at 07:10
  • @Moss, I just tried your scenario and it works??! Maybe they fixed it, I am using PHP 5.6. – Black May 16 '19 at 11:22

2 Answers2

6

The path used in your includes are not relative to the file the includes are : they are relative to the include_path.

Which means that using relative paths with includes/requires will generally not do what you expect it to...


The solution that's generally used is to work with absolute paths ; this way, you are sure what gets included.

Of course, using absolute paths in your code is bad (it will work on one server, but not another, when your application is deployed to another path) ; so, the solution is to :

  • get the absolute path to the file you're in
  • use that, in addition to a relative path to another file, to include that file.


The full path to the file you're in can be obtained with __FILE__.

Which means the directory to the current file (the file that instruction is written in) can be obtained with dirname(__FILE__).

After that, it's only a matter of writing the correct paths.
For example, in stuff.php, you'd use :

require(dirname(__FILE__) . "/constants.php"); 

While, in base.php , you'd use :

require(dirname(__FILE__) . "/../includes/stuff.php");
Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
  • `dirname(dirname(__FILE__))` will get you the parent directory. I tend to store just the applications' base directory and then use paths relative to that. – nikc.org Jun 23 '10 at 06:54
  • That sounds all very reasonable and good except I already got it working as long as the file isn't named constant.php. The files are getting included fine. There are no errors about missing files. I tried your suggestion, I also used $_SERVER['DOCUMENT_ROOT'] before. Neither one makes a difference. – Moss Jun 23 '10 at 07:30
  • 2
    I'm sorry. You were right. I didn't try absolute paths on everything just on base.php. See my edit note on my original question. I guess I needed a nights rest to make sense of this one. By the way, with PHP 5.3.0 `__DIR__` would be the simplest way to do what you suggest. – Moss Jun 23 '10 at 18:26
  • @Pascal Martin, why not using `__DIR__` instead of `dirname(__FILE__) ` ? – Black May 16 '19 at 11:14
0

Something that I found helpful was checking getcwd() (get current working directory) which would return the folder path of the file from which it was included from. If the include file was being called beneath (down a level) of my top directory, then I could calculate and prepend the appropriate number of ../s.

I.e., if I know my include's files were in topfolder/css/blah.css then I could check the value of getcwd() in my included file like this:

$leaveDirectoryIfNecessary = "";
// Grab the last 9 characters of the directory name
if (substr(getcwd(), -9) != "topfolder") {
    $leaveDirectoryIfNecessary = "../";
}

And then I would echo $leaveDirectoryIfNecessary before every file I was referencing in the include file like so:

<link rel="stylesheet" type="text/css" href="<?php echo $leaveDirectoryIfNecessary; ?>css/goodstuff.css">

Notably, this presumes you don't duplicate the name of your parent / top level folder anywhere in your subfolder tree.

You would also need to have some sort of loop and count the number of forward slashes in the current working directory after 'topfolder' if you happen to have a deeper folder structure beyond one level deep that the include file is included from.

veeTrain
  • 2,915
  • 2
  • 26
  • 43