Giới thiệu hàm scandir trong PHP là gì và mục đích sử dụng
Bạn đã bao giờ cần quét danh sách file hoặc thư mục trong PHP chưa? Trong quá trình phát triển ứng dụng web, việc xử lý file và thư mục là một nhiệm vụ thường xuyên mà mọi lập trình viên đều phải đối mặt. Từ việc tạo gallery ảnh động đến quản lý file upload, chúng ta thường cần lấy danh sách các file trong một thư mục cụ thể.

Hàm scandir chính là công cụ giúp bạn lấy danh sách đầy đủ file và thư mục trong thư mục cụ thể một cách nhanh chóng và hiệu quả. Đây là một trong những hàm built-in (có sẵn) của PHP, được thiết kế để đơn giản hóa quá trình đọc nội dung thư mục. Thay vì phải sử dụng các hàm phức tạp như opendir, readdir và closedir, scandir cho phép bạn lấy toàn bộ danh sách chỉ với một dòng lệnh duy nhất.
Bài viết này sẽ giải thích chi tiết cách hoạt động, cú pháp và ứng dụng của scandir trong các tình huống thực tế. Chúng ta sẽ đi qua từ những khái niệm cơ bản nhất đến các kỹ thuật nâng cao, kèm theo những ví dụ minh họa cụ thể mà bạn có thể áp dụng ngay vào dự án của mình.
Cú pháp chuẩn và mô tả các tham số
Cú pháp hàm scandir
Trước khi bắt đầu sử dụng bất kỳ hàm nào, việc hiểu rõ cú pháp là điều quan trọng nhất. Hàm scandir có cú pháp khá đơn giản như sau:
scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, resource $context = null): array|false

Trong đó các tham số được mô tả như sau:
$directory: Đây là tham số bắt buộc, chỉ định đường dẫn (path) đến thư mục mà bạn muốn đọc. Có thể là đường dẫn tương đối hoặc đường dẫn tuyệt đối.
$sorting_order: Tham số tùy chọn để xác định thứ tự sắp xếp kết quả. Mặc định là SCANDIR_SORT_ASCENDING (sắp xếp tăng dần theo tên file).
$context: Tham số tùy chọn ít được sử dụng, dành cho các ngữ cảnh đặc biệt như truy cập file qua stream.
Mô tả chi tiết các tham số
Tham số $directory chính là trái tim của hàm scandir. Bạn có thể truyền vào các định dạng đường dẫn khác nhau như:
- Đường dẫn tương đối:
./uploads/, ../images/, documents/
- Đường dẫn tuyệt đối:
/var/www/html/uploads/, C:\xampp\htdocs\project\files\
Tham số $sorting_order có ba giá trị có thể sử dụng:
SCANDIR_SORT_ASCENDING (0): Sắp xếp tăng dần theo tên (A-Z)
SCANDIR_SORT_DESCENDING (1): Sắp xếp giảm dần theo tên (Z-A)
SCANDIR_SORT_NONE (2): Không sắp xếp, trả về theo thứ tự của hệ thống file
Giá trị trả về và ý nghĩa
Kết quả trả về là gì?
Hàm scandir sẽ trả về một mảng (array) chứa tên của tất cả các file và thư mục có trong đường dẫn được chỉ định. Điều đặc biệt cần lưu ý là kết quả luôn bao gồm hai mục đặc biệt:
- “.” : Đại diện cho thư mục hiện tại
- “..” : Đại diện cho thư mục cha

Trong trường hợp có lỗi xảy ra (như đường dẫn không tồn tại, không có quyền truy cập), hàm sẽ trả về giá trị false. Đây là điểm quan trọng mà bạn cần kiểm tra trước khi xử lý kết quả.
Cách xử lý kết quả hàm scandir
Để xử lý kết quả một cách hiệu quả, bạn thường sẽ cần lọc bỏ các mục "." và ".." vì chúng không phải là file hoặc thư mục thực sự mà chúng ta quan tâm. Đây là một ví dụ cơ bản:
$files = scandir('./uploads/');if ($files !== false) { foreach ($files as $file) { if ($file != '.' && $file != '..') { echo $file . "\n"; } }}
Việc sử dụng vòng lặp foreach kết hợp với điều kiện lọc giúp bạn duyệt qua từng item một cách an toàn và hiệu quả.
Ví dụ sử dụng cơ bản, nâng cao minh họa thực tế
Ví dụ cơ bản: lấy danh sách file trong thư mục
Hãy bắt đầu với một ví dụ đơn giản để hiểu cách hoạt động của scandir:
<?php// Ví dụ 1: Lấy danh sách file cơ bản$directory = './images/';$files = scandir($directory);if ($files !== false) { echo "Danh sách file trong thư mục $directory:\n"; foreach ($files as $file) { if ($file != '.' && $file != '..') { echo "- $file\n"; } }} else { echo "Không thể đọc thư mục hoặc thư mục không tồn tại!";}?>

Đoạn code trên sẽ hiển thị tất cả các file và thư mục con trong thư mục ./images/. Chúng ta sử dụng điều kiện kiểm tra $files !== false để đảm bảo hàm thực thi thành công trước khi xử lý kết quả.
Ví dụ nâng cao: lọc file theo đuôi mở rộng và sắp xếp kết quả
Trong thực tế, bạn thường cần lọc file theo loại cụ thể. Đây là một ví dụ nâng cao hơn:
<?php// Ví dụ 2: Lọc file ảnh và sắp xếp giảm dầnfunction getImageFiles($directory) { $files = scandir($directory, SCANDIR_SORT_DESCENDING); $imageFiles = []; if ($files !== false) { $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; foreach ($files as $file) { if ($file != '.' && $file != '..') { $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (in_array($extension, $allowedExtensions)) { $imageFiles[] = $file; } } } } return $imageFiles;}// Sử dụng hàm$imageFiles = getImageFiles('./gallery/');foreach ($imageFiles as $image) { echo "Tìm thấy ảnh: $image\n";}?>

Ví dụ này cho thấy cách kết hợp scandir với các hàm PHP khác như pathinfo() và in_array() để tạo ra một công cụ lọc file mạnh mẽ.
Hướng dẫn lọc file/thư mục, sắp xếp kết quả với scandir
Việc lọc và sắp xếp kết quả là một kỹ năng quan trọng khi làm việc với scandir. Có nhiều cách tiếp cận khác nhau tùy thuộc vào yêu cầu cụ thể:
Cách 1: Sử dụng array_filter() để lọc nhanh
$files = scandir('./documents/');$filteredFiles = array_filter($files, function($file) { return !in_array($file, ['.', '..']) && pathinfo($file, PATHINFO_EXTENSION) == 'pdf';});
Cách 2: Sử dụng preg_grep() để lọc theo pattern
$files = scandir('./logs/');$logFiles = preg_grep('/\.log$/', $files);$logFiles = array_diff($logFiles, ['.', '..']);

Để phân biệt file và thư mục, bạn có thể sử dụng hàm is_file() và is_dir():
$items = scandir('./mixed/');foreach ($items as $item) { if ($item != '.' && $item != '..') { $fullPath = './mixed/' . $item; if (is_file($fullPath)) { echo "File: $item\n"; } elseif (is_dir($fullPath)) { echo "Thư mục: $item\n"; } }}
Lưu ý khi sử dụng (bảo mật, lỗi phổ biến)
Bảo mật khi dùng scandir
Bảo mật là một vấn đề cực kỳ quan trọng khi làm việc với file system. Hàm scandir có thể trở thành lỗ hổng bảo mật nếu không được sử dụng cẩn thận:

Nguy cơ Path Traversal: Không bao giờ sử dụng input trực tiếp từ user làm đường dẫn:
// NGUY HIỂM - Không làm như thế này!$userInput = $_GET['dir'];$files = scandir($userInput);// AN TOÀN - Luôn validate và sanitize input$allowedDirs = ['uploads', 'documents', 'images'];$userInput = $_GET['dir'];if (in_array($userInput, $allowedDirs)) { $files = scandir('./' . $userInput . '/');}
Kiểm tra quyền truy cập: Luôn kiểm tra quyền đọc thư mục trước khi gọi scandir:
$directory = './sensitive/';if (is_readable($directory)) { $files = scandir($directory);} else { echo "Không có quyền truy cập thư mục này!";}
Lỗi phổ biến khi sử dụng scandir
Lỗi 1: Không kiểm tra giá trị trả về
// SAI$files = scandir('./nonexistent/');foreach ($files as $file) { // Lỗi fatal nếu scandir trả về false echo $file;}// ĐÚNG$files = scandir('./nonexistent/');if ($files !== false) { foreach ($files as $file) { echo $file; }}
Lỗi 2: Quên lọc bỏ “.” và “..”
// SAI - Có thể gây vòng lặp vô tận hoặc logic sai$files = scandir('./');foreach ($files as $file) { processFile($file); // Xử lý cả "." và ".."}// ĐÚNG$files = scandir('./');foreach ($files as $file) { if ($file != '.' && $file != '..') { processFile($file); }}
So sánh scandir với các hàm đọc thư mục khác trong PHP
PHP cung cấp nhiều cách để đọc thư mục, mỗi cách có ưu nhược điểm riêng:

scandir vs opendir/readdir/closedir:
- scandir: Đơn giản, một lời gọi duy nhất, trả về toàn bộ danh sách
- opendir/readdir/closedir: Kiểm soát tốt hơn, xử lý từng file một, tiết kiệm bộ nhớ với thư mục lớn
Khi nào nên dùng scandir?
- Thư mục có ít file (dưới 1000 file)
- Cần danh sách đầy đủ để xử lý
- Muốn code đơn giản, dễ đọc
- Cần sắp xếp kết quả ngay từ đầu
Khi nào nên tránh scandir?
- Thư mục có rất nhiều file (trên 10,000 file)
- Chỉ cần tìm một số file cụ thể
- Cần xử lý file theo real-time
- Bộ nhớ server bị hạn chế
// Ví dụ với thư mục lớn - nên dùng opendir$handle = opendir('./big_directory/');if ($handle) { while (($file = readdir($handle)) !== false) { if ($file != '.' && $file != '..' && pathinfo($file, PATHINFO_EXTENSION) == 'txt') { processFile($file); break; // Dừng khi tìm thấy file đầu tiên } } closedir($handle);}
Câu hỏi thường gặp (FAQ) về scandir
Q: scandir có hỗ trợ đệ quy không?
A: Không, scandir chỉ đọc thư mục cấp 1. Để đọc đệ quy, bạn cần kết hợp với RecursiveDirectoryIterator hoặc viết hàm đệ quy tự tạo.
Q: Làm sao để lọc chỉ lấy file, không lấy thư mục?
A: Sử dụng hàm is_file() để kiểm tra:
$items = scandir('./');$filesOnly = array_filter($items, function($item) { return $item != '.' && $item != '..' && is_file('./' . $item);});
Q: Có cách nào sắp xếp theo thời gian sửa đổi file?
A: scandir không hỗ trợ sắp xếp theo thời gian. Bạn cần sử dụng filemtime() để lấy thời gian và sắp xếp thủ công.

Q: Có thể dùng scandir để đọc thư mục mạng không?
A: Có, nếu thư mục mạng được mount hoặc truy cập qua UNC path, nhưng cần cẩn thận về performance và timeout.
Tổng kết và lời khuyên
Hàm scandir là một công cụ cực kỳ hữu ích cho việc lấy danh sách file và thư mục một cách nhanh gọn trong PHP. Với cú pháp đơn giản và khả năng sắp xếp tự động, nó là lựa chọn tốt cho hầu hết các tình huống thường gặp trong phát triển web.

Tuy nhiên, để sử dụng scandir một cách hiệu quả và an toàn, bạn cần ghi nhớ những điểm quan trọng sau:
- Luôn kiểm tra giá trị trả về: Đảm bảo hàm thực thi thành công trước khi xử lý kết quả
- Lọc bỏ “.” và “..”: Tránh xử lý các thư mục ảo không cần thiết
- Validate đường dẫn: Không bao giờ sử dụng input từ user trực tiếp làm đường dẫn
- Cân nhắc performance: Với thư mục lớn, hãy xem xét sử dụng các phương pháp khác
- Kết hợp với các hàm khác: Sử dụng
pathinfo(), is_file(), is_dir() để xử lý kết quả hiệu quả hơn
Áp dụng đúng cách những kiến thức này sẽ giúp bạn tăng hiệu quả lập trình và bảo trì dự án một cách tốt hơn. Hàm scandir không chỉ giúp code của bạn trở nên ngắn gọn hơn mà còn dễ đọc và dễ hiểu hơn so với các phương pháp truyền thống.
Hãy thử ngay những ví dụ mình đã giới thiệu để làm quen với scandir nhé! Bắt đầu với các ví dụ cơ bản rồi dần dần ứng dụng vào dự án thực tế của bạn. Đừng quên theo dõi blog để nhận thêm nhiều kiến thức PHP và lập trình hữu ích hơn nữa như Hàm trong Python và Phần tử HTML.

Với những kiến thức đã chia sẻ, bạn đã có thể tự tin sử dụng hàm scandir trong các dự án PHP của mình. Hãy thực hành thường xuyên và không ngại thử nghiệm để trở thành một lập trình viên PHP giỏi hơn!
Bạn cũng có thể tham khảo thêm Ứng dụng của Python để mở rộng kiến thức lập trình đa ngôn ngữ.
Chúc bạn thành công!
Chia sẻ Tài liệu học PHP