List Files in a Directory
Lists regular files from an approved directory, skips dot entries, and optionally filters by extension.
Purpose
Lists regular files from an approved directory, skips dot entries, and optionally filters by extension.
Snippet details
ContextFilesystemLevelProductionCopy-and-paste statusMarked safe after review.Categories
- Forms and Validation
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* List Files in a Directory.
*
* Purpose:
* Lists files under an approved base directory without allowing arbitrary path
* traversal and without returning dot entries or subdirectories.
*
* @param string $base_directory Approved base directory.
* @param string $relative_directory Relative directory to list.
* @param string $extension_filter Optional extension without the leading dot.
* @return array File rows and count.
*/
function ogSnippetListFilesInDirectory(string $base_directory, string $relative_directory = '', string $extension_filter = ''): array {
$base_real = realpath($base_directory);
$relative_directory = trim($relative_directory);
$extension_filter = strtolower(trim($extension_filter));
if ($base_real === false || is_dir($base_real) === false) {
return array('success' => false, 'files' => array(), 'count' => 0, 'message' => 'Base directory is invalid.');
}
if ($relative_directory !== '' && (substr($relative_directory, 0, 1) === '/' || strpos($relative_directory, '..') !== false)) {
return array('success' => false, 'files' => array(), 'count' => 0, 'message' => 'Relative directory path is invalid.');
}
$target_path = $base_real;
if ($relative_directory !== '') {
$target_path .= DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $relative_directory);
}
$target_real = realpath($target_path);
if ($target_real === false || is_dir($target_real) === false || strpos($target_real, $base_real) !== 0) {
return array('success' => false, 'files' => array(), 'count' => 0, 'message' => 'Directory is not available inside the approved base path.');
}
$entries = scandir($target_real);
if ($entries === false) {
return array('success' => false, 'files' => array(), 'count' => 0, 'message' => 'Directory could not be read.');
}
$file_rows = array();
foreach ($entries as $entry_name) {
if ($entry_name === '.' || $entry_name === '..') {
continue;
}
$file_path = $target_real.DIRECTORY_SEPARATOR.$entry_name;
if (is_file($file_path) === false) {
continue;
}
$path_info = pathinfo($file_path);
$file_extension = '';
if (isset($path_info['extension']) === true) {
$file_extension = strtolower($path_info['extension']);
}
if ($extension_filter !== '' && $file_extension !== $extension_filter) {
continue;
}
$file_rows[] = array(
'name' => $entry_name,
'extension' => $file_extension,
'size_bytes' => filesize($file_path),
'modified_at' => date('Y-m-d H:i:s', filemtime($file_path))
);
}
return array(
'success' => true,
'files' => $file_rows,
'count' => count($file_rows),
'message' => count($file_rows).' file(s) found.'
);
}
/*
$result = ogSnippetListFilesInDirectory(__DIR__.'/data', 'reports', 'txt');
print_r($result['files']);
*/