PHP - Tải xuống tệp

Xin chào các bạn đang học PHP! Hôm nay, chúng ta sẽ cùng nhau khám phá một chủ đề thú vị giúp bạn thêm một tính năng tuyệt vời cho website của mình - tải xuống tệp bằng PHP. Là người giáo viên máy tính gần gũi của bạn, tôi sẽ hướng dẫn bạn từng bước trong hành trình này. Hãy chuẩn bị đồ uống yêu thích của bạn, thư giãn và cùng bắt đầu lập mã nhé!

PHP - Download File

Hàm readfile()

Tại trung tâm của việc tải xuống tệp trong PHP là hàm readfile(). Hàm nhỏ gọn này là công cụ lý tưởng khi bạn muốn đọc một tệp và ghi nội dung của nó vào bộ nhớ đệm đầu ra. Đừng lo lắng nếu điều này听起来 có vẻ kỹ thuật - chúng ta sẽ cùng phân tích nó!

Cách sử dụng cơ bản

Hãy bắt đầu với một ví dụ đơn giản:

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

Trong đoạn mã này, readfile() đọc nội dung của "example.txt" và xuất nó trực tiếp ra trình duyệt. Đó như một phép màu - nội dung của tệp xuất hiện trên màn hình của bạn!

Tải xuống tệp

Bây giờ, hãy xem điều thú vị hơn. Chúng ta có thể sử dụng readfile() để yêu cầu tải xuống tệp. Hãy xem một ví dụ đầy đủ hơn:

<?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;
}
?>

Wow, có vẻ như rất nhiều thông tin! Hãy cùng phân tích nó:

  1. Chúng ta xác định tệp chúng ta muốn tải xuống ($file = "myfile.pdf").
  2. Chúng ta kiểm tra xem tệp có tồn tại hay không bằng file_exists().
  3. Nếu có, chúng ta thiết lập một loạt các phần header:
  • Content-Description cho biết đây là một quá trình truyền tệp.
  • Content-Type thiết lập loại MIME thành tệp nhị phân通用.
  • Content-Disposition yêu cầu trình duyệt tải tệp xuống.
  • Các phần header khác đảm bảo tệp không bị lưu trong bộ nhớ cache và được xử lý đúng cách.
  1. Cuối cùng, chúng ta sử dụng readfile() để xuất nội dung tệp.

Các loại tệp phổ biến

Các loại tệp khác nhau có thể yêu cầu các phần header khác nhau. Dưới đây là bảng tiện ích của các loại tệp phổ biến và phần header Content-Type tương ứng:

Loại tệp Phần header Content-Type
PDF application/pdf
ZIP application/zip
JPEG image/jpeg
PNG image/png
MP3 audio/mpeg
MP4 video/mp4

Tạo liên kết tải xuống

Bây giờ chúng ta đã biết cách kích hoạt việc tải xuống, hãy tạo một liên kết tải xuống thân thiện với người dùng:

<!DOCTYPE html>
<html>
<body>

<h2>Tải xuống tệp</h2>
<p><a href="download.php?file=myfile.pdf">Tải xuống PDF</a></p>

</body>
</html>

Trong HTML này, chúng ta tạo một liên kết đến một script PHP (download.php) sẽ xử lý việc tải xuống tệp. Chúng ta truyền tên tệp dưới dạng tham số trong URL.

Bây giờ, hãy tạo script 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 "Tệp không tìm thấy.";
}
}
?>

Script này thực hiện các bước sau:

  1. Kiểm tra xem có tham số tệp được truyền trong URL hay không.
  2. Xây dựng đầy đủ đường dẫn tệp (giả sử tệp nằm trong thư mục "uploads").
  3. Nếu tệp tồn tại, nó thiết lập các phần header và kích hoạt việc tải xuống.
  4. Nếu tệp không tồn tại, nó hiển thị thông báo lỗi.

Vấn đề bảo mật

Bây giờ, tôi biết bạn đang nghĩ gì - "Nhưng thầy, có phải điều này có phần nguy hiểm không? What if someone tries to download files they shouldn't?" Câu hỏi tuyệt vời! Bạn hoàn toàn đúng, và đó là lý do chúng ta cần thảo luận về bảo mật.

Xác thực đường dẫn tệp

Chúng ta không bao giờ nên tin tưởng vào đầu vào của người dùng trực tiếp. Dưới đây là phiên bản cải tiến của script tải xuống của chúng ta:

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

// Xác thực đường dẫn tệp
$realPath = realpath($filepath);
$uploadDir = realpath("uploads/");

if($realPath === false || strpos($realPath, $uploadDir) !== 0) {
die("Đường dẫn tệp không hợp lệ.");
}

if(file_exists($filepath)) {
// ... (phần còn lại của mã tải xuống)
} else {
echo "Tệp không tìm thấy.";
}
}
?>

Trong phiên bản này:

  1. Chúng ta sử dụng basename() để loại bỏ bất kỳ nỗ lực truy cập ngược thư mục nào.
  2. Chúng ta sử dụng realpath() để lấy đường dẫn thực tế của tệp và thư mục tải lên.
  3. Chúng ta kiểm tra xem đường dẫn thực tế của tệp có bắt đầu từ thư mục tải lên hay không, đảm bảo chúng ta không truy cập vào các tệp ngoài thư mục ý định.

Kết luận

Và thế là chúng ta đã cùng nhau đi qua thế giới tải xuống tệp bằng PHP, từ cơ bản của readfile() đến việc tạo liên kết tải xuống và thậm chí触及 một số vấn đề bảo mật quan trọng. Nhớ rằng, với quyền lực lớn đi kèm với trách nhiệm - luôn xác thực đầu vào của người dùng và nghĩ về bảo mật khi làm việc với việc tải xuống tệp.

Tôi hy vọng bạn đã thích bài học này như tôi đã thích dạy nó. Hãy tiếp tục thực hành, tiếp tục lập mã, và trước khi bạn biết, bạn sẽ tạo ra các ứng dụng PHP tuyệt vời với nhiều tính năng tải xuống thú vị. Đến gặp lại bạn vào lần tới, chúc bạn lập mã vui vẻ!

Credits: Image by storyset