iT邦幫忙

0

php 根目錄的路徑問題

我的 localhost 是 D:/001_htdocs,
在 D:/001_htdocs/path 資料夾內有放3個檔案,
檔名分別是:
index.php
require.php
image.gif

請問我在 index.php 內設定:

require_once( $_SERVER['DOCUMENT_ROOT'] . '/path/require.php' );
require_once( 'D:/001_htdocs/path/require.php' );
require_once( '/require.php' );

都可以正常執行。

但為何同樣在 index.php 內設定:

echo '<img src="' . $_SERVER['DOCUMENT_ROOT'] . '/path/image.gif" />';
echo '<img src="D:/001_htdocs/path/image.gif" />';
echo '<img src="/image.gif" />';

卻都無法顯示圖片,必須要設定下面這樣才行:

echo '<img src="/path/image.gif" />';

根目錄路徑觀念不太懂,請問可以教我一下嗎?
謝謝!

1
weiclin
iT邦高手 4 級 ‧ 2018-02-21 18:24:40
最佳解答

在 Server 上面,Document root 是 D:/001_htdocs/,PHP 若沒額外限制的話,是可以讀取 Document root 外面的檔案的。當然你也可以隨意的更換 Document root 的位置。

在瀏覽器,Document root 永遠是 /,瀏覽器不會知道(也不需要知道)你實際把檔案放在什麼位置,他就是在 Document root 底下找檔案而已。

所以當你使用路徑的時候,要區分清楚這個路徑是在 Server 端解釋,還是在瀏覽器端解釋。

瀏覽器看到的 /path/index.php 對應於 Server 的 {$document_root}/path/index.php。對瀏覽器來說,絕對路徑都是 / 開頭的。這應該沒什麼問題。

/path/index.php 裡面若有個圖片路徑是 path/example.jpg,因為是相對路徑,瀏覽器會先轉成絕對路徑,去 /path/path/example.jpg 找檔案。

而當瀏覽器看到一個路徑是 d:/htdocs/.... 這樣的時候,你認為他會跑去讀取 Server 的 d:/ 還是瀏覽器所在電腦的 d:/

答案是瀏覽器那台電腦的 d:/。所以你那樣做是行不通的。

很久以前有一個很紅的網站為了節省流量,就利用這點將網站圖片另外做成安裝包,讓用戶安裝以後網站直接顯示用戶本地的圖檔,這樣就不會吃到 Server 的流量了。

看更多先前的回應...收起先前的回應...
froce iT邦研究生 1 級 ‧ 2018-02-21 21:26:08 檢舉

所以說那個很紅的網站是 windows only?XD

weiclin iT邦高手 4 級 ‧ 2018-02-21 22:16:46 檢舉

froce 我記得他是有個選項可以切換從本機讀取圖片, 那個年代不光網站想省流量, 用戶頻寬也不高, 只是我已經忘記網站名稱了

samjam iT邦新手 5 級 ‧ 2018-02-22 10:13:40 檢舉

謝謝 weiclin:
您說在 Server 上面,Document root 是 D:/001_htdocs/
所以以下2種方式都可以執行,這我了解了

require_once( $_SERVER['DOCUMENT_ROOT'] . '/path/require.php' );
require_once( 'D:/001_htdocs/path/require.php' );

而這邊不懂:
如果根目錄 / 的路徑是 D:/001_htdocs/
那麼

require_once( '/require.php' );

應該等於是

require_once( 'D:/001_htdocs/require.php' );

但為何他可以執行呢?
不是應該要從根目錄進到 path 資料夾找到 require.php 這個檔案才對嗎?
像是這樣

require_once( 'D:/001_htdocs/path/require.php' );
weiclin iT邦高手 4 級 ‧ 2018-02-22 11:02:40 檢舉

因為 php 不是單純找你指定的地方而已,官方文件裡面有這句: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.

samjam iT邦新手 5 級 ‧ 2018-02-22 11:23:33 檢舉

可是這樣子反而會錯誤,請問是為什麼呢?

require_once( '/path/require.php' ); 
weiclin iT邦高手 4 級 ‧ 2018-02-22 11:33:54 檢舉

因為你又把瀏覽器的路徑跟 Server 的路徑搞混了吧,Server 在收到瀏覽器要求的時候,會把 / 變成 {$document_root}/,但是在 php 裡面你打 / 就是 /

weiclin iT邦高手 4 級 ‧ 2018-02-22 11:57:31 檢舉

另外我在想可能是你跑在 Windows 的關係,不然以 / 開頭的路徑是絕對路徑,按理說 require_once( '/require.php' ); 是找不到的,你可以上傳到 linux 之類的網頁空間試試

samjam iT邦新手 5 級 ‧ 2018-02-23 10:21:25 檢舉

謝謝 weiclin:
我還是弄不太懂,
請問以我這個例子來說,瀏覽器的根目錄和 Server 的根目錄分別是哪個資料夾呢?
而 / 對於瀏覽器和 Server 分別代表哪個資料夾呢?

weiclin iT邦高手 4 級 ‧ 2018-02-23 10:39:30 檢舉

你弄不懂的跟哪個資料夾無關,而是對每個環節的行為不清楚。

瀏覽器送來的路徑,經過 web server 處理,在 document root 裡面找到對應的 php 檔案,然後執行 php 程式。所以 web server 才是負責把瀏覽器的路徑轉換成 server 實際的檔案路徑的部份。

php 根本就不管 document root 的,頂多有個環境變數紀錄一下是哪一個資料夾而已。在 linux 的環境原本就有個 / 根目錄,執行在 linux 的 php 看到路徑 /path/ 會去找 linux 底下的 /path/,不會去找 $document_root/path/

samjam iT邦新手 5 級 ‧ 2018-02-27 10:49:01 檢舉

我了解囉,謝謝

3
froce
iT邦研究生 1 級 ‧ 2018-02-21 16:41:19

1.在 index.php 中,程式碼是在你主機中執行的。所以 require_once 會去讀取你主機中的檔案。
2.但 echo 出去的,是傳到 browser 上給你 browser 解析的 HTML code。
3.所以請問你跟你網站瀏覽者的 browser 說,顯示「D:/001_htdocs/path/image.gif」(<img src="D:/001_htdocs/path/image.gif" />),你網站瀏覽者有辦法找的到你主機D槽下的檔案嗎?

另外說一點,從你的檔案路徑,可以得知你使用windows,那你有沒有注意到 「D:/001_htdocs/path/image.gif」跟你在windows上顯示的斜線方向不同?這在 unix like os 上有沒有不同?

samjam iT邦新手 5 級 ‧ 2018-02-22 10:28:26 檢舉

謝謝 froce:
我昨天測試的時候有注意到了,謝謝提醒

echo  $_SERVER['SCRIPT_FILENAME'];
顯示 D:/001_htdocs/path/index.php

echo __FILE__;
顯示 D:\001_htdocs\path\index.php

兩種斜線相反,
所以如果我要放在 Linux 主機的話就要把 \ 全部轉成 / 才能正常顯示。
請問是這樣嗎?

0
浩瀚星空
iT邦新手 2 級 ‧ 2018-02-22 11:08:37

這邊可能需要說明所謂的路徑問題。
一般來說,我以前在教人的時候,會先教,何謂主機路徑跟何謂web路徑。
主機路徑來說,一般是要給在php內部上使用的。可以不受web路徑的影響讀取web路徑外的東西。
而一般瀏覽器,是無法使用主機路徑的。而是使用web路徑。
我相信一般初學者可能看到這,就花花的了。

簡單來說好了。用上面的說法。
你的DOCUMENT_ROOT是在 D:/001_htdocs/
那這個網站的主機路徑就是 D:/001_htdocs/
其web路徑就是 / (且它無法在其主機路徑讀取其它非其目錄下的東西)

這邊就說一下為何會這樣說
如果今天這是主機路徑的情況下,你下達了如 ../test.txt 的路徑命令。
其主機路徑就會變成是在 D:/test.txt
但WEB路徑還是會在 /test.txt (因為它無法在往上一層)
看到這是不是又更花了??

總之,我一般都會在/index.php內先宣告如下的常數。

define('FCPATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);

這樣我就可以很單純的去載入我要的程式碼

require_once( FCPATH . '/path/require.php' );

後面補錯了

require_once( FCPATH . 'path/require.php' );

多了一個/

samjam iT邦新手 5 級 ‧ 2018-02-27 10:48:43 檢舉

謝謝您的回答

我要發表回答

立即登入回答