PHP

PHP 下載靜態檔案,隱藏實際檔案名稱、路徑教學

介紹如何透過 PHP 讓使用者下載靜態檔案,但隱藏實際檔案名稱與路徑,保護原始檔案資訊。

隱藏檔案名稱與路徑

假設我們想讓使用者從網頁伺服器上下載靜態的檔案,但是不要讓使用者看到該檔案在伺服器上的路徑與名稱,可以撰寫一個簡單的 PHP 指令稿,將靜態檔案透過 PHP 程式來遞送,屏蔽後方的靜態檔案資訊:

# 原始檔案位置
$filePath = '/secret_data/data1.zip';

# 檔案類型(一般性檔案)
$contentType="application/octet-stream";

# 下載後的檔名
$newFileName = 'your_data.zip';

# 各種檔案標頭
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: " . $contentType);
header("Content-Length: " .(string)(filesize($filePath)) );
header("Content-Transfer-Encoding: binary\n");

# 以附件方式下載檔案,並指定下載後的預設檔名
header('Content-Disposition: attachment; filename="' . $newFileName . '"');

# 輸出檔案內容
readfile($filePath);

exit();

這裡我們將靜態檔案移出網頁伺服器的網頁目錄,放在系統上的其他位置,因此該檔案無法直接被下載,然後我們再透過這個 PHP 程式將其內容讀取出來,搭配自訂的標頭資訊一起輸出,這樣使用者下載的檔案內容是相同的,但是看不到檔案名稱與實際路徑,藉以達到保護的目的。

瀏覽器撥放 MP4 影片檔

如果是 MP4 這類的影片檔,希望透過 PHP 下載之後,讓 Google Chrome 等瀏覽器直接以內建的撥放器直接撥放(不要另存檔案),可以將「檔案類型」修改一下,並且以一般的方式下載檔案:

# 原始檔案位置
$filePath = '/secret_data/data1.mp4';

# 檔案類型(MP4 影片檔)
$contentType="video/mp4";

# 各種檔案標頭
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: " . $contentType);
header("Content-Length: " .(string)(filesize($filePath)) );
header("Content-Transfer-Encoding: binary\n");

# 輸出檔案內容
readfile($filePath);

exit();

隱藏索引

提供資料下載的網頁,通常都會採用索引的方式來對應下的檔案,例如 https://your.com/down.php?id=12 就是用來下載編號 12 的檔案,但這種方式會暴露檔案的編碼方式,也可讓使用者輕易使用簡單的下載工具大量下載資料。

若要避免暴露檔案編碼索引,可以採用 AES 加密的方式,先將索引進行加密,這樣用於網頁的 URL 中就不會暴露相關的資訊。

首先自行定義 AES 加密與解密的函數:

# AES 加密
function encrypt($key, $payload) {
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
  $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
  return base64_encode($encrypted . '::' . $iv);
}

# AES 解密
function decrypt($key, $garble) {
  list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
  return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}

在網頁中需要建立下載超連結的地方,全部都以 AES 的方式將敏感的資訊加密,例如:

# 原始檔案位置
$filePath = '/secret_data/data1.mp4';

# 加密的下載位置
echo 'https://your.com/down.php?eid=' . urlencode(encrypt("YOUR_PASSWORD", $filePath));

加密過的網址會像這樣:

https://your.com/download.php?eid=MWM2RHcxV1VMOXR2ajZNclZoRGV6TlZ6Z0xZUXdKUWZ3ZlVIb29sRlZEYz06OhUUI2QzmPOAAE6v5GybvA8%3D

然後在 download.php 中取得加密後的檔案資訊,用同樣的密碼解密,取得下載的檔案資訊,最後再以前述的方式產生資料讓使用者下載:

# 解密後的下載位置
$filePath = decrypt("YOUR_PASSWORD", $_GET['eid']);

這樣的方式可讓所有的下載網址都沒有規則可循,基本上也無法直接以簡單的方式大量下載檔案。

參考資料:StackOverflow

Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

9 個月 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

9 個月 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

9 個月 ago

Windows 使用 TPM 虛擬智慧卡保護 SSH 金鑰教學與範例

本篇介紹如何在 Windows...

10 個月 ago

Linux 以 Shamir’s Secret Sharing 分割保存金鑰教學與範例

介紹如何在 Linux 中使用...

11 個月 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

11 個月 ago