Rutas en PHP: dirname(), basename(), pathinfo() y realpath()

Manejar rutas de ficheros de forma portable y segura en PHP requiere cuatro funciones: dirname() para subir en el árbol de directorios, basename() para obtener el nombre del fichero, pathinfo() para descomponer una ruta en sus partes, y realpath() para resolver rutas absolutas y detectar ataques de path traversal.

dirname(): obtener el directorio padre

<?php
$ruta = '/var/www/app/src/Controllers/UserController.php';

echo dirname($ruta);        // /var/www/app/src/Controllers
echo dirname($ruta, 2);     // /var/www/app/src    (subir 2 niveles)
echo dirname($ruta, 3);     // /var/www/app
echo dirname($ruta, 4);     // /var/www
echo dirname($ruta, 5);     // /var

// Uso habitual en autoloaders y configuraciones
define('BASE_DIR', dirname(__DIR__));        // directorio padre del script actual
define('CONFIG_DIR', dirname(__DIR__) . '/config');
define('STORAGE_DIR', dirname(__DIR__, 2) . '/storage');
?>

basename(): obtener el nombre del fichero

<?php
$ruta = '/var/www/app/uploads/imagen-portada.jpg';

echo basename($ruta);              // imagen-portada.jpg
echo basename($ruta, '.jpg');      // imagen-portada  (sin extensión)

// Con directorios
echo basename('/var/www/app/src'); // src

// Uso en uploads: generar nombre único manteniendo la extensión original
$original  = $_FILES['foto']['name'] ?? '';
$extension = strtolower(pathinfo($original, PATHINFO_EXTENSION));
$nombre    = uniqid('img_', true) . '.' . $extension;
?>

pathinfo(): descomponer una ruta en sus partes

<?php
$ruta = '/var/www/app/uploads/informe-2026.pdf';

// Descomposición completa: devuelve array
$partes = pathinfo($ruta);
echo $partes['dirname'];    // /var/www/app/uploads
echo $partes['basename'];   // informe-2026.pdf
echo $partes['filename'];   // informe-2026
echo $partes['extension'];  // pdf

// Obtener solo una parte (más eficiente)
echo pathinfo($ruta, PATHINFO_DIRNAME);   // /var/www/app/uploads
echo pathinfo($ruta, PATHINFO_BASENAME);  // informe-2026.pdf
echo pathinfo($ruta, PATHINFO_FILENAME);  // informe-2026
echo pathinfo($ruta, PATHINFO_EXTENSION); // pdf
?>

realpath(): resolver rutas absolutas

realpath() resuelve ., .., enlaces simbólicos y convierte una ruta relativa en absoluta. Devuelve false si el fichero no existe:

<?php
// Resolver rutas con puntos
echo realpath('/var/www/../www/app');     // /var/www/app
echo realpath('/var/www/app/./src');      // /var/www/app/src
echo realpath('/no/existe');              // false

// Ruta relativa a absoluta
chdir('/var/www/app');
echo realpath('src/Controllers');         // /var/www/app/src/Controllers

// Resolver enlace simbólico
echo realpath('/var/www/html');           // /var/www/app/public (si hay symlink)
?>

Protección contra ataques de path traversal

Path traversal es un ataque donde el usuario proporciona rutas con ../ para acceder a ficheros fuera del directorio permitido. realpath() es la forma más sencilla de detectarlo:

<?php
function rutaSegura(string $nombreFichero, string $directorioBase): string
{
    // Eliminar caracteres nulos (bypass conocido)
    $nombreFichero = str_replace("", '', $nombreFichero);

    // Resolver la ruta completa
    $rutaCompleta = realpath($directorioBase . '/' . $nombreFichero);

    if ($rutaCompleta === false) {
        throw new RuntimeException('El fichero no existe');
    }

    // Verificar que la ruta resuelta está dentro del directorio base
    $directorioBase = realpath($directorioBase);
    if (!str_starts_with($rutaCompleta, $directorioBase . '/')) {
        throw new RuntimeException('Acceso denegado: ruta fuera del directorio permitido');
    }

    return $rutaCompleta;
}

// Ejemplo de uso
$base = '/var/www/app/uploads';

// Petición legítima
$segura = rutaSegura('documentos/informe.pdf', $base);
// /var/www/app/uploads/documentos/informe.pdf  ?

// Intento de path traversal
rutaSegura('../../../etc/passwd', $base);
// RuntimeException: Acceso denegado  ?
?>

Combinar las cuatro funciones

<?php
// Cambiar la extensión de un fichero manteniendo el directorio
function cambiarExtension(string $ruta, string $nuevaExt): string
{
    $dir      = dirname($ruta);
    $nombre   = pathinfo($ruta, PATHINFO_FILENAME);
    $nuevaExt = ltrim($nuevaExt, '.');
    return "$dir/$nombre.$nuevaExt";
}

echo cambiarExtension('/var/www/app/img/foto.jpg', 'webp');
// /var/www/app/img/foto.webp

// Convertir ruta relativa a absoluta y verificar que existe en el proyecto
function resolverRutaProyecto(string $relativa): string
{
    $base     = realpath(dirname(__DIR__));
    $candidata = $base . '/' . ltrim($relativa, '/');
    $real      = realpath($candidata);

    if ($real === false || !str_starts_with($real, $base)) {
        throw new RuntimeException("Ruta no válida: $relativa");
    }

    return $real;
}
?>

La documentación de realpath() y la de pathinfo() incluyen notas sobre el comportamiento en Windows (separadores de ruta) y con enlaces simbólicos.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP