Hàm xoá file an toàn trong PHP (Tránh xoá nhầm cả server)

Xoá file là thao tác tưởng chừng vô hại nhưng lại là một trong những nguyên nhân gây thảm hoạ nhiều nhất trong các hệ thống PHP. Chỉ cần sai một biến, lệch một path, hoặc tin nhầm input từ người dùng, hậu quả có thể là: xoá nhầm file hệ thống, xoá nguyên thư mục upload, thậm chí dọn sạch cả project. Bài này tập trung vào cách xoá file an toàn, kiểm soát được, và không tự bóp cổ mình.

Hàm xoá file an toàn trong PHP (Tránh xoá nhầm cả server)

Vì sao xoá file trong PHP rất dễ toang

Những đoạn code kiểu này xuất hiện nhan nhản:

<?php
unlink($_GET['file']);

Chỉ cần user truyền vào:

../../../../index.php

Thế là xong. Đây là path traversal – lỗi kinh điển nhưng vẫn có người dẫm.

Nguyên tắc xoá file an toàn

  • Không bao giờ tin đường dẫn do người dùng gửi
  • Chỉ cho phép xoá trong thư mục được chỉ định
  • Dùng realpath() để resolve đường dẫn thật
  • Không xoá thư mục, chỉ xoá file
  • Kiểm tra file có tồn tại và có quyền xoá

Thư mục gốc được phép xoá

Đầu tiên, cần xác định rõ: chỉ xoá file trong một thư mục cụ thể, ví dụ thư mục upload:

<?php
define('UPLOAD_DIR', __DIR__ . '/uploads');

Mọi thao tác xoá đều phải nằm trong khu vực này. Ra ngoài là cấm.

Hàm xoá file an toàn

<?php
function safe_delete_file(string $relativePath): bool {
    // 1. không cho phép path rỗng
    if ($relativePath === '') {
        return false;
    }

    // 2. chuẩn hoá path tuyệt đối
    $baseDir = realpath(UPLOAD_DIR);
    if ($baseDir === false) {
        return false;
    }

    $targetPath = realpath($baseDir . DIRECTORY_SEPARATOR . $relativePath);

    // 3. file không tồn tại
    if ($targetPath === false) {
        return false;
    }

    // 4. đảm bảo file nằm trong thư mục cho phép
    if (strpos($targetPath, $baseDir) !== 0) {
        return false;
    }

    // 5. chỉ cho phép xoá file, không xoá thư mục
    if (!is_file($targetPath)) {
        return false;
    }

    // 6. kiểm tra quyền ghi
    if (!is_writable($targetPath)) {
        return false;
    }

    return unlink($targetPath);
}

Vì sao realpath là vũ khí sống còn

realpath() resolve toàn bộ:

  • ../
  • symlink
  • đường dẫn ảo

Nhờ đó, bạn so sánh được đường dẫn thật trên hệ thống, không bị đánh lừa bởi chuỗi path giả mạo.

Ví dụ sử dụng thực tế

<?php
$file = $_POST['file'] ?? '';

if (!safe_delete_file($file)) {
    die('Không thể xoá file');
}

echo 'Đã xoá file thành công';

Lưu ý: biến $file chỉ nên là đường dẫn tương đối bên trong thư mục upload, ví dụ:

<?php
avatars/user123.png

Những sai lầm cần tránh tuyệt đối

  • Dùng unlink() trực tiếp với input người dùng
  • Cho phép truyền path tuyệt đối
  • Xoá cả thư mục bằng rmdir() mà không kiểm soát
  • Không giới hạn thư mục gốc

Có nên cho xoá theo id thay vì path

Câu trả lời là: nên.

Thay vì nhận path từ client, hãy:

  • Nhận file_id
  • Lấy path từ database
  • Rồi mới gọi hàm xoá

Cách này giảm đáng kể rủi ro bị path traversal.

Kết luận

Xoá file trong PHP không khó, nhưng xoá an toàn mới là chuyện đáng nói. Chỉ cần một hàm cẩn thận, dùng realpath đúng chỗ và giới hạn thư mục rõ ràng, bạn có thể tránh được những tai nạn kiểu “deploy xong xoá luôn production”.

Nhớ kỹ một câu: xoá file sai một lần, debug cả đời!

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...