Directory operations: mkdir, scandir, glob, RecursiveIteratorIterator
Intermediate5 min read·php-13-003
Concept
PHP provides functions for working with directories — listing contents, creating, removing, and navigating. Understanding these is essential for file management tasks in applications.
Directory reading:
scandir(string $dir): Returns an array of all files and directories in$dir, sorted alphabetically. Includes.and..entries — always filter those out.opendir()/readdir()/closedir(): Low-level handle-based directory reading.readdir()returns entries one at a time; returnsfalsewhen exhausted. Useful when memory matters with huge directories.glob(string $pattern): Returns files matching a glob pattern (*.php,uploads/**/*.jpg). Convenient for finding files by extension or pattern. Returns empty array (not false) when nothing matches (in PHP 8.0+ withGLOB_NOCHECK, returns the pattern; without flags, returns empty array).
Directory creation and removal:
mkdir(string $path, int $permissions = 0777, bool $recursive = false): Creates a directory.recursive: truecreates all parent directories. Permissions are modified byumask.rmdir(string $path): Removes a directory. The directory must be empty — fails if it has contents.unlink(string $path): Deletes a file (not directories).
Recursive removal: PHP has no built-in rm -rf. Use RecursiveDirectoryIterator + RecursiveIteratorIterator to delete contents before calling rmdir().
getcwd(): Returns current working directory. chdir(): Changes it. In web contexts, getcwd() is typically the document root. Prefer absolute paths to avoid CWD dependency.
Code Example
php
<?php
declare(strict_types=1);
// scandir — list directory contents
$entries = scandir('/var/www/uploads');
$files = array_filter($entries, fn($e) => $e !== '.' && $e !== '..' && is_file("/var/www/uploads/$e"));
// glob — find files by pattern
$phpFiles = glob('/var/www/src/**/*.php'); // may not recurse in all PHP versions
$jpegFiles = glob('/var/www/uploads/*.{jpg,jpeg,JPG}', GLOB_BRACE);
$configFiles = glob('/etc/app/config-*.json');
// mkdir with recursive creation
$uploadDir = '/var/www/storage/uploads/' . date('Y/m/d');
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, recursive: true);
}
// Note: 0755 is modified by umask (typically resulting in 0644 or 0755)
// opendir — memory-efficient enumeration
$dir = opendir('/var/www/uploads');
if ($dir === false) {
throw new \RuntimeException("Cannot open directory");
}
try {
while (($entry = readdir($dir)) !== false) {
if ($entry === '.' || $entry === '..') continue;
echo "$entry\n";
}
} finally {
closedir($dir);
}
// Recursive directory removal
function removeDirectory(string $path): void
{
if (!is_dir($path)) {
throw new \InvalidArgumentException("Not a directory: $path");
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST // delete children before parents
);
foreach ($iterator as $file) {
if ($file->isDir()) {
rmdir($file->getPathname());
} else {
unlink($file->getPathname());
}
}
rmdir($path);
}
// Copy directory recursively
function copyDirectory(string $src, string $dst): void
{
mkdir($dst, 0755, recursive: true);
foreach (new \DirectoryIterator($src) as $item) {
if ($item->isDot()) continue;
$destPath = $dst . '/' . $item->getFilename();
if ($item->isDir()) {
copyDirectory($item->getPathname(), $destPath);
} else {
copy($item->getPathname(), $destPath);
}
}
}