包含路径解析如何在 require_once 中工作?
Posted
技术标签:
【中文标题】包含路径解析如何在 require_once 中工作?【英文标题】:How does include path resolution work in require_once? 【发布时间】:2021-09-20 06:12:33 【问题描述】:当我遇到一个奇怪的情况时,我正在用 php 编写一个 Web 应用程序。为了说明我的问题,请考虑这种结构的网络应用程序:
/
index.php
f1/
f1.php
f2/
f2.php
这些文件的内容:
index.php:
<?php require_once("f1/f1.php"); ?>
f1.php:
<?php require_once("../f2/f2.php"); ?>
f2.php: 空白
现在,当我尝试在浏览器中打开 index.php 时,出现此错误:
Warning: require_once(../f2/f2.php) [function.require-once]:
failed to open stream: No such file or directory in /var/www/reqtest/f1/f1.php on line 2
Fatal error: require_once() [function.require]:
Failed opening required '../f2/f2.php' (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/reqtest/f1/f1.php on line 2
我有什么明显的遗漏吗?包含路径在 PHP 中是如何工作的?
在我问这个问题之前,我尝试过尝试并找出答案。我设置了另一个测试,如下所示:
/
index.php
f1/
f1.php
f2.php
index.php:
<?php require_once("f1/f1.php"); ?>
f1.php:
<?php require_once("f2.php"); ?>
f2.php: 空白
令我惊讶(和完全困惑),结果很好!
那么,路径解析背后的秘密是什么?
PS 我看到了this question,但它仍然没有回答我在这里所说的第二种情况。
【问题讨论】:
我已经绕过了这个问题(使用目录名)。我想知道的是为什么第二种情况不会失败。是错误还是功能? 编辑了我的答案以涵盖第二个示例。 我找不到记录从 f1.php 成功调用 require_once('f2.php') 的手册页。文档说当没有提供路径信息时会忽略 include_path(无论如何,从 include_path 中删除 '.' 无效)并且 getcwd() 表明工作目录在包含链周围都是相同的。说真的,它看起来像是一个未记录的功能。 实用文章:cjhaas.com/2019/05/21/php-include-path-surprises 【参考方案1】:通常在你的旧结构中
<?php require_once("f2/f2.php"); ?>
而不是
<?php require_once("../f2/f2.php"); ?>
应该可以。据我所知,php 从初始脚本中获取路径
【讨论】:
我知道。我真正想知道的是为什么第二种情况没有失败。这不是问题,它是一种痒:)【参考方案2】:当您打开 index.php 时,工作目录被设置为该文件所在的文件夹。在插入的 f1.php 中,这个工作目录不会改变。
您可以使用相对于当前包含文件的绝对路径来包含文件,如下所示:
require_once(dirname(__FILE__).'/../../test/file.php')
但如果这些文件包含类,最好考虑使用自动加载器。
【讨论】:
尝试添加'echo getcwd();'到您的脚本以查看当前工作目录如何更改以及是否更改。 php.net/manual/en/function.getcwd.php - cmets 这里说,例如,它的行为从 PHP4 更改为 PHP5。【参考方案3】:听起来您的服务器在 PHP 配置中启用了open_basedir 设置。这使得无法在目录结构中包含(和打开)您上方的文件夹中的文件(即,您不能使用 ../ 进入文件夹结构)。
【讨论】:
在我的服务器中,open_basedir 设置“没有价值”。这意味着什么?【参考方案4】:如果您包含另一个文件,则工作目录将保留在包含文件所在的位置。
您的示例按预期工作。
编辑:第二个示例有效,因为 . (实际目录)在您的包含路径中(请参阅您的错误消息)。
编辑2: 在您的第二个示例中,您感兴趣的关键点是这一行:
<?php require_once("f2.php"); ?>
首先它会在当前工作目录(/var/www/req_path_test
)中查找,但没有找到 f2.php。
作为后备,它会尝试在您的 include_path ('.:/usr/share/php:/usr/share/pear'
) 中查找 f2.php,以 '.' 开头(相对于实际文件,而不是包括文件)。
所以 './f2.php' 有效,并且 require 不会失败。
【讨论】:
我在 index.php 和 f1.php 中尝试了 echo:ing getcwd()。两个地方的输出都是/var/www/req_path_test
所以“。”在包含路径中可能意味着“/var/www/req_path_test”在包含路径中。
为了支持这一事实,我尝试了require_once("f2/f2.php")
。当我打开 index.php 时它起作用了,但当我打开 f1/f1.php 时它不起作用。
嗯,这似乎是最合适的解释..你能引用任何来源吗?
我认为这与其他语言相反。因此,我将其称为设计缺陷。此评论的作者正在演示其他语言/系统会做什么。【参考方案5】:
来自 PHP 文档PHP include
根据给定的文件路径包含文件,如果没有给出,则根据指定的 include_path。如果在 include_path 中找不到该文件,则 include 最终会在失败前检查调用脚本自己的目录和当前工作目录。
如果没有给出文件路径,即 require_once("f2.php");
第一。 include_path 被选中
第二。检查调用脚本自己的目录
第三。最后检查当前工作目录
如果找不到文件,则 PHP 会在文件包含时抛出警告,并且在需要时抛出致命错误
如果定义了路径——无论是绝对路径(在 Windows 上以驱动器号或 \ 开头,或在 Unix/Linux 系统上以 / 开头)还是相对于当前目录(以 . 或 .. 开头)——include_path 都将被忽略共。例如,如果文件名以 ../ 开头,解析器将在父目录中查找请求的文件。
如果您包含/要求您的文件以 .或 .. 或 ./ 然后 PHP 的解析器将在当前工作目录的父目录中查找,即 require_once("../f2/f2.php"),php 将在根目录中查找调用脚本 index.php在那个目录中。
现在您还没有在 PHP 脚本中定义任何包含路径,因此它总是回退到调用脚本,然后进入当前工作目录。
// Check your default include path, most likely to be C:\xampp\php\PEAR
echo get_include_path();
// To set include path
set_include_path ( string $new_include_path ) : string
当前工作目录源自您的主要调用脚本 index.php。
// The Current Working Directory can be checked
echo getcwd();
在第一个示例中,所需文件“../f2/f2.php”来自 f1.php
您的代码不起作用,因为 -
-
指定的路径被 PHP 忽略,因为您的文件名以 ../ 开头
f1/ 调用脚本自己的目录也会被忽略。
解析器目录查找父目录以查找请求的文件。当前工作目录是根目录,这是您启动工作脚本 index.php 的位置。该文件不在此目录下,路径错误。
因此你得到了致命错误
在第二个示例中,您已经从 f1.php 更改了目录 & 您 require_once("f2.php")。
您的代码有效,因为 -
-
这一次你 require("f2.php") 没有前导 ../ 或 ./ 这一次 PHP 检查 include_path 但确实在那里找到它,因为你没有定义它并且文件不在默认值中预设 include_path。
这次调用脚本f1.php的目录是f1/。并且您需要的文件(“f2.php”)位于此目录中。 PHP 这次检查这个目录下的文件,找到了。
发现文件时,PHP 不必检查工作目录。
因此您的代码工作正常!
【讨论】:
以上是关于包含路径解析如何在 require_once 中工作?的主要内容,如果未能解决你的问题,请参考以下文章