9

It's very odd,has anyone ever sum up with a conclusion yet?

Sometimes it checks the directory of the included file,too.

But sometimes not.

D:\test\1.php

<?php

include('sub\2.php');

D:\test\2.php

<?php

include('3.php');

Where 3.php is in the same dir as 2.php.

The above works,but why?The current directory should be D:\test,but it can still find 3.php,which is in D:\test\sub

More story(final)

About a year ago I met this problem,and then I ended up fixed it with the hardcoding like below:

Common.php:

if (file_exists("../../../Common/PHP/Config.inc"))
    include('../../../Common/PHP/Config.inc');

if (file_exists("../../Common/PHP/Config.inc"))
    include('../../Common/PHP/Config.inc');

if (file_exists("../Common/PHP/Config.inc"))
    include('../Common/PHP/Config.inc');

if (file_exists("Common/PHP/Config.inc"))
    include('Common/PHP/Config.inc');

Where Config.inc is in the same directory as Common.php

user198729
  • 61,774
  • 108
  • 250
  • 348
  • 1
    Good question! I can confirm this on Windows and Linux. I have no idea why this is. – Pekka Mar 13 '10 at 12:03
  • Regarding your last example, if "Config.inc" is in the same directory as "Common.php" then this could be simplified to `include(dirname(__FILE__).'/Config.inc');` - this will always work, regardless of the `include_path` and which file "Common.php" is included into. If there is no chance "Config.inc" could be found in the `include_path` (in which the current directory is often included) then you could simply call `include 'Config.inc';`, although this is possibly less efficient since the `include_path` is first searched (which fails). – MrWhite Feb 10 '15 at 17:55
  • In your first example, I assume "D:\test\2.php" should be "D:\test\sub\2.php"? (Otherwise `include('sub\2.php');` would never work.) – MrWhite Feb 10 '15 at 17:58
  • I just experienced what you describe. I've always included files without the path, inside my included file (where both files exist in the same sub directory) and I have this working on multiple servers. On Friday, on one server, this suddenly stopped working. I now have to specify the path in the include, or it won't find it. I have no idea why. Exact same versions of PHP on all servers. If you ever figured this out, I'd love to get an update on your story. – Vincent Feb 09 '20 at 20:54

3 Answers3

2

If you take a look at the source code for php in main/fopen_wrappers.c you will find

/* check in calling scripts' current working directory as a fall back case
     */
    if (zend_is_executing(TSRMLS_C)) {
        char *exec_fname = zend_get_executed_filename(TSRMLS_C);
        int exec_fname_length = strlen(exec_fname);

        while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
        if (exec_fname && exec_fname[0] != '[' &&
            exec_fname_length > 0 &&
            exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
            memcpy(trypath, exec_fname, exec_fname_length + 1);
            memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
            actual_path = trypath;

This seems to be executed unconditionally and therefore will always make a file in the same path as the including/file-opening script accessible ...as the last choice after all possibilities specified in include_path. And only if you do not define a relative or absolute path in the include().

VolkerK
  • 95,432
  • 20
  • 163
  • 226
  • I dont seem to understand this code,are there some clues why sometimes it doesn't check the directory of the included file? – user198729 Mar 13 '10 at 13:45
  • For `3.php` it first tests all locations given in the include\_path. A relative path given there, e.g. `include_path=.;..;lalala` would be relative to the current working directory (which is not changed by an include()). Only the last (additional) option is to look in the same directory as the including file is in. It "takes" the first `3.php` it can find. Is that your problem: php grabs another 3.php as you'd expect? Your other questions seem to indicate that... – VolkerK Mar 13 '10 at 13:50
  • My problem is sometimes it won't find 3.php,but I can't reproduce it easily.But it's in the same directory as the including file is in.Maybe when the `include` is in a function/method,I guess... – user198729 Mar 13 '10 at 13:58
  • So, for clarification: It doesn't find _any_ 3.php in that case (not simply the "wrong" one but none at all). You can't reproduce it easily... hm. Does it happen on different servers/versions/configurations? Or is it like a heisenbug that happens on the _same machine_ with the _same code_ without touching anything that seems to be related? – VolkerK Mar 13 '10 at 14:04
  • Yes.It happens on different servers,I don't think it's a heisenbug – user198729 Mar 13 '10 at 14:09
  • And you're sure the problem really boils down to the example you've provided in the question? (Sorry for me nagging, but I have the feeling there's something missing in the example and the question "The above works,but why?" as it is right now is answered ;-) ) – VolkerK Mar 13 '10 at 14:17
  • @VolkerK ,this answers half the question(why it works),did you miss the **But sometimes not.** part in my post?:-) – user198729 Mar 13 '10 at 14:20
  • Yes I did ;-) But since I have no further clue maybe there's some information you can add. E.g. "It happens on different servers" is something that should make you hit the "edit" button of your original question. Maybe you have noticed some/any pattern. The php version, something in the setting of include\_path on the servers, something remarkable about the "configure command" in the output of phpoinfo() on the different servers ...anything ;-) Because as you can see from all the answers so far this behaviour of php is not something too obvious. – VolkerK Mar 13 '10 at 14:35
  • I've provided the whole story(imo) here:http://stackoverflow.com/questions/2438356/is-debug-backtrace-safe-for-serious-usage-in-production-environment – user198729 Mar 13 '10 at 14:35
  • Ok, that's the story of the hack you want add to your code. I meant the story of how you discovered _and explored_ the underlying problem. It may be just me but I've never seen code before that had to resort to debug\_backtrace() to get an include right ;-) Right now you're working on a hack around the problem. And as hacks go they come back at you at the least favorable time in the least favorable manner. – VolkerK Mar 13 '10 at 14:44
  • Yes,glad you've fully understood my problem(which can't be reproduced with ease:():-)Finally I manually changed the cwd by `chdir()` as a workaround,which is much safer/efficient(imo).. – user198729 Mar 13 '10 at 14:49
  • Just one last question... which versions of php are involved? There have been some patches (and reverts) in the 4.3/5.0 branch that might affect whether php is executing the code I quoted above at all or not. – VolkerK Mar 13 '10 at 15:04
  • @VolkerK ,PHP 5.3.0.But I don't think it's related with OOP,because I noticed this before using classes,but I didn't stop to think about the reason at that time:-) – user198729 Mar 13 '10 at 15:08
  • Each and every server involved is php 5.3? Ok, then I don't have a clue (and no I didn't mean oop, but zend\_stream\_open\_function ;-)) – VolkerK Mar 13 '10 at 15:11
  • +1 never knew that php would use the directory of the file that did the include as a last resort. I always thought the cwd and include_path were the only choices. – goat Mar 13 '10 at 18:07
1

It checks in the current path, and the directories listed in include_path.

You can run a phpinfo() to see your include path.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • This doesn't explain the problem I described:( – user198729 Mar 13 '10 at 11:44
  • @user as far as I know, that's all there is to it. Please show some examples of when files get loaded, and when they don't. – Pekka Mar 13 '10 at 11:46
  • Will `getcwd()` change during a request if we don't explicitly change it(like `chdir()`).I'll give an example soon. – user198729 Mar 13 '10 at 11:51
  • If by "current path" you mean the _current working directory_ then it only checks the CWD if it's included as part of the `include_path` (which it is by default). However, if by "current path" you mean the directory that contains the script (ie. `dirname(__FILE__)` - which has the `include` statement and is not necessarily the same as the CWD) then this is only checked after it fails to find it in the `include_path`. – MrWhite Feb 10 '15 at 19:22
1

Sometimes directory of the included file being current working directory and sometimes not
Current directory can be checked with getcwd()

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345