Directorios en PHP
Directorios en PHP: guía de referencia completa para desarrolladores PHP.
PHP incluye un conjunto de funciones de directorio integradas que permiten a tus scripts inspeccionar, crear, leer y eliminar carpetas en el sistema de archivos del servidor, sin necesidad de llamar al sistema operativo. Esta página explica qué hace cada función principal, cuándo utilizarla y los errores comunes que debes evitar.
Esta página es un complemento de Manejo de archivos en PHP y la referencia más amplia del Sistema de archivos en PHP: los archivos viven dentro de los directorios, por lo que ambos temas casi siempre se usan juntos.
Por qué son importantes las operaciones con directorios
Casi cualquier aplicación no trivial interactúa con el sistema de archivos. Necesitas funciones de directorio para:
- Organizar archivos subidos — ordenar las cargas de usuarios en carpetas por usuario o por fecha (consulta Subida de archivos en PHP).
- Crear estructuras de proyecto al vuelo — generar carpetas de caché, registros o exportaciones la primera vez que se necesitan.
- Iterar sobre contenido — listar cada plantilla, imagen o archivo de datos en una carpeta para procesarlos en lote.
- Limpiar — eliminar directorios temporales una vez que un trabajo finaliza.
Como estas funciones forman parte del núcleo de PHP, funcionan igual en Linux, macOS y Windows (con / aceptado como separador en todos lados), lo que las hace más portables que ejecutar mkdir o ls a través de exec().
Funciones principales de directorio
| Función | Propósito |
|---|---|
mkdir($path, $mode, $recursive) | Crea un directorio. Pasa true en $recursive para crear directorios padres anidados. |
rmdir($path) | Elimina un directorio — debe estar vacío primero. |
is_dir($path) | Devuelve true si la ruta existe y es un directorio. |
scandir($path) | Devuelve un array con todas las entradas de un directorio (incluyendo . y ..). |
opendir() / readdir() / closedir() | Abre un manejador de directorio y lee las entradas de una en una. |
getcwd() | Devuelve el directorio de trabajo actual. |
chdir($path) | Cambia el directorio de trabajo actual. |
scandir() frente a opendir()
Ambas listan el contenido de un directorio, pero se adaptan a necesidades distintas:
scandir()carga todas las entradas en un array de una sola vez. Es concisa y fácil de ordenar, pero consume memoria proporcional al número de archivos. Ideal para carpetas pequeñas o medianas.opendir()/readdir()transmiten las entradas de una en una. Esto mantiene el uso de memoria constante incluso en directorios con decenas de miles de archivos. Ideal para carpetas muy grandes.
Ambas incluyen las entradas especiales . (directorio actual) y .. (directorio padre) — casi siempre querrás omitirlas.
Ejemplo: crear un directorio y listar su contenido
Este script comprueba si existe un directorio, lo crea (junto con las carpetas padres faltantes) si no existe, y luego imprime su contenido:
<?php
$dir = 'uploads/images';
// Create the directory and any missing parents if it doesn't exist
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
echo "Directory created: $dir\n";
}
// List directory contents, skipping the . and .. entries
$files = scandir($dir);
echo "Contents of $dir:\n";
foreach ($files as $file) {
if ($file !== '.' && $file !== '..') {
echo "- $file\n";
}
}
?>El tercer argumento de mkdir() (true) es el indicador recursivo: sin él, mkdir('uploads/images') falla si uploads no existe todavía. El 0755 es un modo de permisos octal (el propietario puede leer/escribir/ejecutar, otros pueden leer/ejecutar) y se ignora en Windows.
Ejemplo: transmisión con opendir()
Para directorios grandes, lee las entradas de una en una en lugar de construir un array completo:
<?php
$dir = __DIR__;
if ($handle = opendir($dir)) {
while (($entry = readdir($handle)) !== false) {
if ($entry !== '.' && $entry !== '..') {
$type = is_dir("$dir/$entry") ? 'dir ' : 'file';
echo "[$type] $entry\n";
}
}
closedir($handle);
}
?>Observa la comparación estricta !== false: un archivo llamado literalmente "0" es falsy, por lo que un while ($entry = readdir(...)) sin strictness se detendría antes de tiempo. Compara siempre explícitamente contra false.
Eliminar directorios
rmdir() solo elimina un directorio vacío. Para eliminar uno que todavía contiene archivos, borra el contenido primero, normalmente con un helper recursivo:
<?php
function removeDir(string $dir): void {
foreach (scandir($dir) as $entry) {
if ($entry === '.' || $entry === '..') {
continue;
}
$path = "$dir/$entry";
is_dir($path) ? removeDir($path) : unlink($path);
}
rmdir($dir);
}
?>Esta función recorre cada entrada, recursando en subdirectorios y eliminando archivos con unlink(), de modo que el directorio queda vacío cuando se ejecuta rmdir().
Errores comunes
mkdir()sin el indicador recursivo falla si falta alguna carpeta padre. Pasatrueal crear rutas anidadas.- Los permisos se restan con
umask— el modo real es$mode & ~umask(), por lo que0777puede resultar en0755. rmdir()en una carpeta no vacía devuelvefalsey emite una advertencia. Vacíala primero.scandir()incluye.y..— fíltralos antes de procesar.- Las rutas relativas dependen de
getcwd(), que es el directorio de trabajo del script, no la ubicación del archivo. Usa__DIR__para anclar las rutas al archivo actual.
Flujo de trabajo con directorios de un vistazo
graph TD
A[Check Directory] --> B{Exists?}
B -->|No| C[mkdir]
B -->|Yes| D[scandir / opendir]
C --> E[Create Subdirectories]
D --> F[Read Entries]
F --> G[Process Files]
G --> H[close / rmdir]Resumen
Las funciones de directorio de PHP te ofrecen una forma portable e integrada de gestionar carpetas: mkdir() y rmdir() las crean y eliminan, is_dir() las verifica, y scandir() u opendir()/readdir() listan su contenido. Usa scandir() en carpetas pequeñas por su simplicidad, y la transmisión con opendir() en carpetas grandes para mantener el uso de memoria constante. Combínalas con funciones de archivos de PHP y el manejo de archivos para crear funcionalidades robustas de carga, caché y exportación.