PHP - 下載文件

你好,有抱負的PHP開發者們!今天,我們將要深入一個令人興奮的主題,讓你能在你的網站中加入一些很酷的功能 - 使用PHP下載文件。作為你們友善的鄰居電腦老師,我將在這次旅程中一步步地指導你們。所以,拿起你們最喜歡的飲料,放鬆身心,讓我們開始編程吧!

PHP - Download File

readfile() 函數

在PHP中實現文件下載的核心是 readfile() 函數。這個小巧的函數是你的首选工具,當你需要讀取文件並將其內容寫入輸出緩衝區時。現在,別擔心這聽起來有點專業 - 我們會一起剖析它!

基本使用

讓我們從一個簡單的例子開始:

<?php
readfile("example.txt");
?>

在這段代碼中,readfile() 讀取 "example.txt" 的內容並直接輸出到瀏覽器。這就像魔法一樣 - 文件的內容會出現在屏幕上!

下載文件

現在我们來看看更有趣的部分。我們可以使用 readfile() 來提示文件下載。讓我們看一個更完整的例子:

<?php
$file = "myfile.pdf";

if(file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>

哇,這有很多要吸收的!讓我們分解一下:

  1. 我們指定我們想要下載的文件 ($file = "myfile.pdf")。
  2. 我們使用 file_exists() 來檢查文件是否存在。
  3. 如果存在,我們設置一系列的頭部信息:
  • Content-Description 告訴瀏覽器這是一個文件傳輸。
  • Content-Type 設置MIME類型為通用二進制文件。
  • Content-Disposition 導致瀏覽器下載文件。
  • 其他頭部信息確保文件不被緩存並被正確對待。
  1. 最後,我們使用 readfile() 來輸出文件內容。

常見文件類型

不同的文件類型可能需要不同的頭部信息。這裡有一個常用文件類型和對應的 Content-Type 頭部信息的便捷表格:

文件類型 Content-Type 頭部信息
PDF application/pdf
ZIP application/zip
JPEG image/jpeg
PNG image/png
MP3 audio/mpeg
MP4 video/mp4

創建下載鏈接

現在我們知道如何觸發下載,讓我們創建一個用戶友好的下載鏈接:

<!DOCTYPE html>
<html>
<body>

<h2>下載文件</h2>
<p><a href="download.php?file=myfile.pdf">下載 PDF</a></p>

</body>
</html>

在這個HTML中,我們創建一個鏈接指向一個PHP腳本 (download.php) 來處理文件下載。我們在URL中傳遞文件名作為參數。

現在,讓我們創建 download.php 腳本:

<?php
if(isset($_GET['file'])) {
$file = $_GET['file'];
$filepath = "uploads/" . $file;

if(file_exists($filepath)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
exit;
} else {
echo "文件未找到。";
}
}
?>

這個腳本會執行以下操作:

  1. 檢查URL中是否有文件參數。
  2. 構建完整的文件路徑(假設文件在 "uploads" 目錄中)。
  3. 如果文件存在,它設置頭部信息並觸發下載。
  4. 如果文件不存在,它顯示一個錯誤消息。

安全考慮

現在我知道你在想什麼 - "但是老師,這不是有點風險嗎?如果有人試圖下載他們不應該下載的文件怎麼辦?" 好問題!你完全正確,這就是我們需要談論安全性的原因。

驗證文件路徑

我們絕對不應該直接信任用戶輸入。這裡是我們下載腳本的改進版本:

<?php
if(isset($_GET['file'])) {
$file = basename($_GET['file']);
$filepath = "uploads/" . $file;

// 驗證文件路徑
$realPath = realpath($filepath);
$uploadDir = realpath("uploads/");

if($realPath === false || strpos($realPath, $uploadDir) !== 0) {
die("無效的文件路徑。");
}

if(file_exists($filepath)) {
// ...(下載代碼的其余部分)
} else {
echo "文件未找到。";
}
}
?>

在這個版本中:

  1. 我們使用 basename() 來刪除任何目錄遍歷嘗試。
  2. 我們使用 realpath() 來獲得文件的實際路徑和上傳目錄的路徑。
  3. 我們檢查文件的實際路徑是否以上傳目錄路徑開始,確保我們不會訪問到指定目錄之外的文件。

結論

好了,各位!我們已經穿越了PHP文件下載的領地,從 readfile() 的基礎知識到創建下載鏈接,甚至觸及了一些重要的安全考慮。記住,能力越大,責任越大 - 當你處理文件下載時,總是要驗證用戶輸入並考慮安全性。

我希望你們喜歡這個課程,就像我喜歡教這個課程一樣。持續練習,持續編程,在你們知道之前,你們將會創建有各種酷炫下載功能的PHP應用程序。下次見,快樂編程!

Credits: Image by storyset