標準檔案下載(含快取控制)
<?php
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// 清除輸出緩衝,避免前有空白導致檔案損毀
ob_clean();
flush();
readfile($file); // 直接輸出檔案內容,效率優於 fread 迴圈
exit;
}
?>
線上預覽 PDF(inline 而非 attachment)
<?php
function previewPdf(string $pdfPath) {
if (!is_file($pdfPath) || !is_readable($pdfPath)) {
http_response_code(404);
exit('檔案不存在');
}
// IE 相容需加 public
header('Cache-Control: public');
header('Content-Type: application/pdf');
// inline 讓瀏覽器嘗試內嵌顯示(需瀏覽器支援 PDF Viewer)
header('Content-Disposition: inline; filename="' . basename($pdfPath) . '"');
header('Content-Length: ' . filesize($pdfPath));
readfile($pdfPath);
exit;
}
// 使用
// previewPdf($_SERVER['DOCUMENT_ROOT'] . '/pdf/fdd/sample.pdf');
?>
關鍵差異對照
| 標頭 | 下載 (attachment) | 預覽 (inline) |
Content-Disposition | `attachment; filename="..."` | `inline; filename="..."` |
| 瀏覽器行為 | 彈出下載對話框/直接存檔 | 嘗試在分頁/iframe 顯示 |
| 適用場景 | 任意二進位檔、壓縮包、安裝程式 | PDF、圖片、文字、影音(瀏覽器支援者) |
進階:支援 Range 斷點續傳的統一函數
<?php
function sendFile(string $path, string $disposition = 'attachment', ?string $mime = null) {
if (!is_file($path) || !is_readable($path)) { http_response_code(404); exit; }
$size = filesize($path);
$mime = $mime ?: mime_content_type($path);
$name = basename($path);
// Range 處理
$start = 0; $end = $size - 1; $code = 200;
if (isset($_SERVER['HTTP_RANGE'])) {
if (preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $m)) {
$start = (int)$m[1];
$end = $m[2] !== '' ? (int)$m[2] : $size - 1;
$code = 206;
}
}
$length = $end - $start + 1;
header('Content-Type: ' . $mime);
header('Content-Disposition: ' . $disposition . '; filename="' . rawurlencode($name) . '"');
header('Accept-Ranges: bytes');
header('Content-Length: ' . $length);
if ($code === 206) {
http_response_code(206);
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
}
$fp = fopen($path, 'rb');
fseek($fp, $start);
while (!feof($fp) && $length > 0) {
$chunk = min(1024 * 1024, $length);
echo fread($fp, $chunk);
$length -= $chunk;
}
fclose($fp);
exit;
}
// 下載
// sendFile('/data/report.pdf', 'attachment');
// 線上預覽
// sendFile('/data/report.pdf', 'inline', 'application/pdf');
?>