简体   繁体   中英

PHP will include a file relative to a calling script, but not if the include path contains “../”

I have looked through many of the posts related to this question but haven't found any that quite address it...my apologies if I've missed the relevant one.

From what I gather from PHP's documentation and from other posts here, PHP's include (and include_once) do the following:

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

I have the following structure in a given directory:

  • index.php
  • /dirA (contains a.php and b.php)
  • /dirB (contains c.php)

From index.php include_once "dirA/a.php"

Here's what works from within a.php:
include_once "b.php"
include_once "dirB/c.php"

Here's what DOESN"T work from within a.php:
include_once "b.php"
include_once "../dirB/c.php"

The curious thing to me is that b.php is included relative to the "calling script's own directory" but c.php is only considered relative to the current working directory (which is the dir containing index.php). This seems to be a slight inconsistency to me. PHP will include a file relative to a calling script, but not if the include path contains ../ - why? Why won't the ../ parent directory directive work relative to the calling script but it will relative to the current working directory? (note: I tested it relative to the cwd but didn't include that file in my example above just to keep it cleaner. It worked just fine)

Can anyone shed some light as to why this is? Should it work this way, or is this a bug?

PHP's a bit odd in how it looks for files. If you include a file whose name starts with a slash or a dot , PHP ignores the include_path entirely. If a dot, it assumes the name is relative to the script that kicked off everything (ie: the one the web server decided to run).

If you want to specify a path relative to the included script and not the startup one, what you really want is an absolute include that specifies the full name of the file. That's easy to do with the __FILE__ and __DIR__ constants, which reflect the name and directory of the currently running script.

include __DIR__ . '/../dirB/c.php';

If you like, you can also set the include_path config setting to include the root of the app, and just specify all filenames relative to that.

It is because you have first included the dirA/a.php to index.php , so from now on the index.php is your base file from which all includes are taking place. And therefore if you include c.php from a.php it is like you do it from index.php

And that's why you are getting wrong results if you specify one level up with "../" . It searches one level above index.php and it finds nothing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM