由於現在的網頁瀏覽器幾乎都有內建PDF reader,在網站上下載PDF檔案可能會直接開啟路徑來做瀏覽,
但如果要讓使用者強制下載檔案的話要怎麼辦呢?

我們可以使用MIME Type中的application/octet-stream來達成文檔下載的效果

$file = '/path/yourfile';
$file_name = basename(yourfile);

header("Expires: 0");
header("Cache-Control: no-cache, no-store, must-revalidate");
header('Cache-Control: pre-check=0, post-check=0, max-age=0', false);
header("Pragma: no-cache");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename={$file_name}");
header('Content-Length: ' . filesize($file));

readfile("{$file}");

既然是用header做檔案下載,那勢必要有引導頁面做這個工作,開頭說到想讓使用者下載也是有個原因,大家都知道下載檔案只要將檔案路徑放進連結,點擊時就可以下載

<a href='YourFilePath' target='_blank'>Download</a>

但以安全性的角度來看這件事情就非常不OK,因為你的檔案路徑會直接外洩,如果你的檔案命名是有規則性的話,很容易被有心的使用者去猜到,或者在路徑存取權限沒設定好,一進入路徑就全部看光光了

解決方法

定義檔案唯一的對應碼

我們可以替每個檔案定義一個唯一碼,這裡我在上傳檔案時會產生一個UUID來作對應,這樣資料就會像下方這樣

pk uid file
1 1e644ab039ca92bbc1d7e5928b56cf1d /path/file1
2 ba84026871e6278dcafd8abd99a16d1e /path/file2
3 b05b99b80ee987b23539752efa91ac52 /path/file3

接著我們來修改View的連結

<a href='download.php?token=1e644ab039ca92bbc1d7e5928b56cf1d' target='_blank'>Download</a>

實作下載頁面

這裡只要接收參數並參考開頭提供的方式就可以讓使用者直接下載文檔

如果你是使用Auto increment的Primary Key當作唯一碼也是可以的,這取決你的檔案要不要輕易讓其他人下載,只要你在後端做好所需要的權限判定即可