7. Manejo de Archivos
Manejo de Archivos en PHP
Section titled “Manejo de Archivos en PHP”PHP ofrece un conjunto completo de funciones para trabajar con archivos y directorios en el servidor. Estas funcionalidades permiten leer, escribir, modificar y eliminar archivos, así como gestionar directorios y sus contenidos. El manejo de archivos es esencial para muchas aplicaciones web, desde la simple lectura de configuraciones hasta sistemas complejos de gestión de contenidos.
Leer y Escribir Archivos
Section titled “Leer y Escribir Archivos”PHP proporciona varias formas de leer y escribir archivos, desde funciones básicas hasta métodos más avanzados.
Funciones Básicas para Archivos Pequeños
Section titled “Funciones Básicas para Archivos Pequeños”Para archivos pequeños, PHP ofrece funciones simples que cargan todo el contenido de una vez:
<?php// Leer todo el contenido de un archivo en una cadena$contenido = file_get_contents('archivo.txt');echo $contenido;
// Escribir una cadena completa a un archivo (sobrescribe el contenido existente)file_put_contents('nuevo_archivo.txt', 'Este es el contenido del archivo.');
// Agregar contenido al final de un archivo existentefile_put_contents('log.txt', "Nueva entrada de registro: " . date('Y-m-d H:i:s') . "", FILE_APPEND);
// Leer un archivo en un array (cada línea es un elemento)$lineas = file('archivo.txt');foreach ($lineas as $numero_linea => $linea) { echo "Línea #" . ($numero_linea + 1) . ": " . htmlspecialchars($linea) . "<br>";}?>Manejo de Archivos con Punteros
Section titled “Manejo de Archivos con Punteros”Para un control más preciso y eficiente, especialmente con archivos grandes, PHP proporciona un conjunto de funciones que trabajan con punteros de archivo:
<?php// Abrir un archivo para lectura$archivo = fopen('datos.txt', 'r');
// Verificar si se abrió correctamenteif ($archivo) { // Leer el archivo línea por línea while (($linea = fgets($archivo)) !== false) { echo htmlspecialchars($linea) . "<br>"; }
// Cerrar el archivo fclose($archivo);} else { echo "Error al abrir el archivo";}
// Abrir un archivo para escritura (crea el archivo si no existe, sobrescribe si existe)$archivo = fopen('salida.txt', 'w');
// Escribir en el archivofwrite($archivo, "Primera línea de texto");fwrite($archivo, "Segunda línea de texto");
// Cerrar el archivofclose($archivo);
// Abrir un archivo para agregar contenido al final$archivo = fopen('log.txt', 'a');fwrite($archivo, date('Y-m-d H:i:s') . " - Operación completada");fclose($archivo);?>Modos de Apertura de Archivos
Section titled “Modos de Apertura de Archivos”Al usar fopen(), el segundo parámetro especifica el modo de apertura del archivo:
- ‘r’: Abre para lectura. El puntero comienza al inicio del archivo.
- ‘w’: Abre para escritura. Crea el archivo si no existe o lo trunca si existe.
- ‘a’: Abre para escritura. Crea el archivo si no existe. El puntero comienza al final del archivo.
- ‘x’: Crea y abre para escritura. Devuelve FALSE si el archivo ya existe.
- ‘r+’: Abre para lectura y escritura. El puntero comienza al inicio.
- ‘w+’: Abre para lectura y escritura. Crea el archivo si no existe o lo trunca si existe.
- ‘a+’: Abre para lectura y escritura. Crea el archivo si no existe. El puntero comienza al final.
- ‘x+’: Crea y abre para lectura y escritura. Devuelve FALSE si el archivo ya existe.
Agregar ‘b’ a cualquier modo para abrir en modo binario:
- ‘rb’, ‘wb’, ‘ab’, etc.
- Importante en sistemas Windows para evitar transformaciones de caracteres de nueva línea.
Leer Datos Específicos
Section titled “Leer Datos Específicos”<?php// Abrir archivo$archivo = fopen('datos.bin', 'rb');
// Leer un solo carácter$caracter = fgetc($archivo); // Lee un byte
// Leer una cantidad específica de bytes$datos = fread($archivo, 1024); // Lee 1KB
// Mover el puntero del archivofseek($archivo, 100); // Mueve el puntero a la posición 100$datos = fread($archivo, 50); // Lee 50 bytes desde la posición 100
// Obtener la posición actual del puntero$posicion = ftell($archivo);echo "Posición actual: $posicion";
// Rebobinar el archivo (volver al inicio)rewind($archivo);
// Verificar si hemos llegado al final del archivoif (feof($archivo)) { echo "Fin del archivo alcanzado";}
fclose($archivo);?>Bloqueo de Archivos
Section titled “Bloqueo de Archivos”Cuando múltiples scripts pueden acceder al mismo archivo simultáneamente, es importante usar bloqueos para evitar problemas de concurrencia:
<?php$archivo = fopen('datos_compartidos.txt', 'r+');
// Intentar obtener un bloqueo exclusivo (para escritura)if (flock($archivo, LOCK_EX)) { // Realizar operaciones seguras en el archivo ftruncate($archivo, 0); // Vaciar el archivo fwrite($archivo, "Nuevos datos");
// Liberar el bloqueo flock($archivo, LOCK_UN); echo "Operación completada con éxito";} else { echo "No se pudo obtener el bloqueo";}
fclose($archivo);
// Ejemplo con bloqueo no bloqueante$archivo = fopen('otro_archivo.txt', 'r');
// Intentar obtener un bloqueo compartido (para lectura) sin bloquear la ejecuciónif (flock($archivo, LOCK_SH | LOCK_NB)) { // Leer datos... flock($archivo, LOCK_UN);} else { echo "El archivo está siendo modificado por otro proceso";}
fclose($archivo);?>Trabajar con CSV
Section titled “Trabajar con CSV”PHP tiene funciones específicas para trabajar con archivos CSV (valores separados por comas):
<?php// Leer un archivo CSV$archivo = fopen('datos.csv', 'r');
// Leer la primera línea como encabezados$encabezados = fgetcsv($archivo);
// Leer los datos$datos = [];while (($fila = fgetcsv($archivo)) !== false) { // Crear un array asociativo combinando encabezados con valores $datos[] = array_combine($encabezados, $fila);}
fclose($archivo);
// Mostrar los datosecho "<pre>";print_r($datos);echo "</pre>";
// Escribir un archivo CSV$archivo_salida = fopen('exportacion.csv', 'w');
// Escribir encabezados$encabezados = ['Nombre', 'Edad', 'Ciudad'];fputcsv($archivo_salida, $encabezados);
// Escribir datos$filas = [ ['María', 28, 'Madrid'], ['Juan', 35, 'Barcelona'], ['Ana', 42, 'Valencia']];
foreach ($filas as $fila) { fputcsv($archivo_salida, $fila);}
fclose($archivo_salida);?>Serializar Datos
Section titled “Serializar Datos”Para guardar estructuras de datos complejas en archivos:
<?php// Datos a guardar$datos = [ 'usuario' => [ 'id' => 123, 'nombre' => 'Carlos', 'roles' => ['editor', 'admin'] ], 'configuracion' => [ 'tema' => 'oscuro', 'notificaciones' => true ]];
// Serializar y guardar$serializado = serialize($datos);file_put_contents('datos_serializados.txt', $serializado);
// Leer y deserializar$contenido = file_get_contents('datos_serializados.txt');$datos_recuperados = unserialize($contenido);
echo "Tema: " . $datos_recuperados['configuracion']['tema'];
// Alternativa usando JSON (más portable)$json = json_encode($datos, JSON_PRETTY_PRINT);file_put_contents('datos.json', $json);
$contenido_json = file_get_contents('datos.json');$datos_json = json_decode($contenido_json, true); // true para obtener arrays asociativos
echo "Nombre de usuario: " . $datos_json['usuario']['nombre'];?>Subir Archivos
Section titled “Subir Archivos”La subida de archivos es una funcionalidad común en aplicaciones web. PHP facilita este proceso mediante el manejo de formularios con enctype="multipart/form-data" y la variable superglobal $_FILES.
Formulario Básico de Subida
Section titled “Formulario Básico de Subida”<!-- HTML del formulario --><form action="procesar_subida.php" method="post" enctype="multipart/form-data"> <label for="archivo">Seleccionar archivo:</label> <input type="file" name="archivo" id="archivo"> <br> <input type="submit" value="Subir Archivo"></form><?php// Verificar si se ha subido un archivoif (isset($_FILES['archivo']) && $_FILES['archivo']['error'] === UPLOAD_ERR_OK) { // Obtener detalles del archivo $nombre_temporal = $_FILES['archivo']['tmp_name']; $nombre_archivo = $_FILES['archivo']['name']; $tamano_archivo = $_FILES['archivo']['size']; $tipo_archivo = $_FILES['archivo']['type'];
// Directorio donde se guardará el archivo $directorio_destino = 'uploads/';
// Crear el directorio si no existe if (!is_dir($directorio_destino)) { mkdir($directorio_destino, 0755, true); }
// Ruta completa de destino $ruta_destino = $directorio_destino . $nombre_archivo;
// Mover el archivo subido al destino final if (move_uploaded_file($nombre_temporal, $ruta_destino)) { echo "Archivo subido con éxito a $ruta_destino"; echo "<br>Tamaño: $tamano_archivo bytes"; echo "<br>Tipo: $tipo_archivo"; } else { echo "Error al mover el archivo subido"; }} else { // Mostrar código de error si existe if (isset($_FILES['archivo'])) { $codigo_error = $_FILES['archivo']['error']; echo "Error en la subida. Código: $codigo_error";
// Mostrar mensaje según el código de error switch ($codigo_error) { case UPLOAD_ERR_INI_SIZE: echo " - El archivo excede el tamaño máximo permitido en php.ini"; break; case UPLOAD_ERR_FORM_SIZE: echo " - El archivo excede el tamaño máximo especificado en el formulario"; break; case UPLOAD_ERR_PARTIAL: echo " - El archivo se subió parcialmente"; break; case UPLOAD_ERR_NO_FILE: echo " - No se subió ningún archivo"; break; case UPLOAD_ERR_NO_TMP_DIR: echo " - Falta la carpeta temporal"; break; case UPLOAD_ERR_CANT_WRITE: echo " - Error al escribir el archivo en el disco"; break; case UPLOAD_ERR_EXTENSION: echo " - Una extensión de PHP detuvo la subida"; break; } } else { echo "No se ha enviado ningún archivo"; }}?>Validación y Seguridad en Subidas
Section titled “Validación y Seguridad en Subidas”La validación de archivos subidos es crucial para la seguridad:
<?php// Validación completa de archivos subidosfunction validar_archivo($archivo) { $errores = [];
// Verificar si hay errores en la subida if ($archivo['error'] !== UPLOAD_ERR_OK) { $errores[] = "Error en la subida del archivo (código: {$archivo['error']})"; return $errores; }
// Verificar tamaño (ejemplo: máximo 2MB) $tamano_maximo = 2 * 1024 * 1024; // 2MB en bytes if ($archivo['size'] > $tamano_maximo) { $errores[] = "El archivo es demasiado grande. Máximo: 2MB"; }
// Verificar tipo de archivo (ejemplo: solo imágenes) $tipos_permitidos = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($archivo['type'], $tipos_permitidos)) { $errores[] = "Tipo de archivo no permitido. Solo se aceptan: JPEG, PNG, GIF"; }
// Verificar extensión (doble verificación) $extension = strtolower(pathinfo($archivo['name'], PATHINFO_EXTENSION)); $extensiones_permitidas = ['jpg', 'jpeg', 'png', 'gif']; if (!in_array($extension, $extensiones_permitidas)) { $errores[] = "Extensión de archivo no permitida. Solo se aceptan: JPG, JPEG, PNG, GIF"; }
// Verificar que el archivo sea realmente una imagen (si aplica) if (function_exists('exif_imagetype')) { $tipo_imagen = @exif_imagetype($archivo['tmp_name']); if (!$tipo_imagen || !in_array($tipo_imagen, [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF])) { $errores[] = "El archivo no es una imagen válida"; } }
return $errores;}
// Uso de la funciónif (isset($_FILES['archivo'])) { $errores = validar_archivo($_FILES['archivo']);
if (empty($errores)) { // Generar nombre único para evitar sobrescrituras $nombre_unico = time() . '_' . bin2hex(random_bytes(8)) . '_' . basename($_FILES['archivo']['name']); $ruta_destino = 'uploads/' . $nombre_unico;
// Mover el archivo if (move_uploaded_file($_FILES['archivo']['tmp_name'], $ruta_destino)) { echo "Archivo subido y validado correctamente";
// Establecer permisos adecuados chmod($ruta_destino, 0644); // Solo lectura para grupo y otros } else { echo "Error al mover el archivo"; } } else { echo "Errores de validación:<br>"; foreach ($errores as $error) { echo "- $error<br>"; } }}?>Subida Múltiple de Archivos
Section titled “Subida Múltiple de Archivos”<!-- Formulario para subida múltiple --><form action="procesar_multiple.php" method="post" enctype="multipart/form-data"> <label for="archivos">Seleccionar archivos:</label> <input type="file" name="archivos[]" id="archivos" multiple> <br> <input type="submit" value="Subir Archivos"></form><?php// Verificar si hay archivos subidosif (isset($_FILES['archivos']) && !empty($_FILES['archivos']['name'][0])) { // Contar archivos $total_archivos = count($_FILES['archivos']['name']); echo "Total de archivos: $total_archivos<br>";
// Directorio de destino $directorio_destino = 'uploads/'; if (!is_dir($directorio_destino)) { mkdir($directorio_destino, 0755, true); }
// Procesar cada archivo $archivos_subidos = 0; for ($i = 0; $i < $total_archivos; $i++) { // Verificar si este archivo se subió sin errores if ($_FILES['archivos']['error'][$i] === UPLOAD_ERR_OK) { $nombre_temporal = $_FILES['archivos']['tmp_name'][$i]; $nombre_archivo = $_FILES['archivos']['name'][$i];
// Generar nombre único $nombre_unico = time() . '_' . $i . '_' . basename($nombre_archivo); $ruta_destino = $directorio_destino . $nombre_unico;
// Mover el archivo if (move_uploaded_file($nombre_temporal, $ruta_destino)) { $archivos_subidos++; echo "Archivo #$i: $nombre_archivo subido correctamente<br>"; } else { echo "Error al mover el archivo #$i: $nombre_archivo<br>"; } } else { echo "Error en la subida del archivo #$i. Código: {$_FILES['archivos']['error'][$i]}<br>"; } }
echo "<br>Total de archivos subidos con éxito: $archivos_subidos de $total_archivos";} else { echo "No se han seleccionado archivos para subir";}?>Funciones de Sistema de Archivos
Section titled “Funciones de Sistema de Archivos”PHP ofrece numerosas funciones para trabajar con el sistema de archivos, permitiendo operaciones como verificar la existencia de archivos, obtener información, manipular permisos y gestionar directorios.
Verificación de Archivos y Directorios
Section titled “Verificación de Archivos y Directorios”<?php// Verificar si un archivo existeif (file_exists('config.php')) { echo "El archivo config.php existe<br>";}
// Verificar si es un archivo regularif (is_file('datos.txt')) { echo "datos.txt es un archivo regular<br>";}
// Verificar si es un directorioif (is_dir('imagenes')) { echo "'imagenes' es un directorio<br>";}
// Verificar si un archivo es legibleif (is_readable('log.txt')) { echo "log.txt es legible<br>";}
// Verificar si un archivo es escribibleif (is_writable('config.ini')) { echo "config.ini es escribible<br>";}
// Verificar si un archivo es ejecutableif (is_executable('script.sh')) { echo "script.sh es ejecutable<br>";}?>Información de Archivos
Section titled “Información de Archivos”<?php// Obtener el tamaño de un archivo en bytes$tamano = filesize('documento.pdf');echo "Tamaño: $tamano bytes<br>";
// Obtener la fecha de última modificación$ultima_mod = filemtime('index.php');echo "Última modificación: " . date('Y-m-d H:i:s', $ultima_mod) . "<br>";
// Obtener la fecha de último acceso$ultimo_acceso = fileatime('datos.txt');echo "Último acceso: " . date('Y-m-d H:i:s', $ultimo_acceso) . "<br>";
// Obtener la fecha de creación (solo en algunos sistemas)$creacion = filectime('imagen.jpg');echo "Fecha de creación/cambio: " . date('Y-m-d H:i:s', $creacion) . "<br>";
// Obtener el tipo MIME de un archivoif (function_exists('mime_content_type')) { $tipo_mime = mime_content_type('documento.pdf'); echo "Tipo MIME: $tipo_mime<br>";}
// Obtener información completa del archivo$info = stat('archivo.zip');echo "<pre>";print_r($info);echo "</pre>";
// Obtener la extensión de un archivo$extension = pathinfo('documento.pdf', PATHINFO_EXTENSION);echo "Extensión: $extension<br>";
// Obtener el nombre del archivo sin la ruta$nombre_archivo = basename('/var/www/html/documentos/informe.docx');echo "Nombre del archivo: $nombre_archivo<br>";
// Obtener el nombre del archivo sin extensión$nombre_sin_extension = pathinfo('informe.docx', PATHINFO_FILENAME);echo "Nombre sin extensión: $nombre_sin_extension<br>";
// Obtener el directorio padre$directorio = dirname('/var/www/html/documentos/informe.docx');echo "Directorio: $directorio<br>";?>Manipulación de Archivos
Section titled “Manipulación de Archivos”<?php// Copiar un archivoif (copy('original.txt', 'copia.txt')) { echo "Archivo copiado con éxito<br>";}
// Renombrar o mover un archivoif (rename('antiguo.txt', 'nuevo.txt')) { echo "Archivo renombrado con éxito<br>";}
// Mover un archivo a otro directorioif (rename('archivo.txt', 'backup/archivo.txt')) { echo "Archivo movido con éxito<br>";}
// Eliminar un archivoif (unlink('temporal.tmp')) { echo "Archivo eliminado con éxito<br>";}
// Cambiar permisos de un archivo (modo octal)if (chmod('script.php', 0755)) { // rwxr-xr-x echo "Permisos cambiados con éxito<br>";}
// Cambiar propietario del archivo (solo en sistemas Unix/Linux)if (function_exists('chown') && chown('archivo.txt', 'nuevo_propietario')) { echo "Propietario cambiado con éxito<br>";}
// Cambiar grupo del archivo (solo en sistemas Unix/Linux)if (function_exists('chgrp') && chgrp('archivo.txt', 'nuevo_grupo')) { echo "Grupo cambiado con éxito<br>";}
// Truncar un archivo a una longitud específicaif (file_exists('log.txt')) { $archivo = fopen('log.txt', 'r+'); ftruncate($archivo, 100); // Truncar a 100 bytes fclose($archivo); echo "Archivo truncado<br>";}
// Crear un enlace simbólico (solo en sistemas Unix/Linux)if (function_exists('symlink') && symlink('archivo_original.txt', 'enlace.txt')) { echo "Enlace simbólico creado<br>";}
// Verificar si un archivo es un enlace simbólicoif (function_exists('is_link') && is_link('enlace.txt')) { echo "Es un enlace simbólico<br>";
// Obtener la ruta del enlace $destino = readlink('enlace.txt'); echo "Apunta a: $destino<br>";}?>Manejo de Directorios
Section titled “Manejo de Directorios”<?php// Crear un directorioif (!is_dir('nuevo_directorio')) { if (mkdir('nuevo_directorio', 0755)) { echo "Directorio creado con éxito<br>"; }}
// Crear directorios anidados (recursivo)if (!is_dir('ruta/a/directorio/profundo')) { if (mkdir('ruta/a/directorio/profundo', 0755, true)) { echo "Directorios anidados creados con éxito<br>"; }}
// Eliminar un directorio (debe estar vacío)if (is_dir('directorio_vacio')) { if (rmdir('directorio_vacio')) { echo "Directorio eliminado con éxito<br>"; }}
// Cambiar al directorio especificadochdir('/var/www/html');echo "Directorio actual: " . getcwd() . "<br>";
// Obtener el directorio de trabajo actual$directorio_actual = getcwd();echo "Estamos en: $directorio_actual<br>";
// Leer el contenido de un directorioif (is_dir('imagenes')) { echo "Contenido del directorio 'imagenes':<br>"; $archivos = scandir('imagenes');
foreach ($archivos as $archivo) { // Omitir . y .. if ($archivo != '.' && $archivo != '..') { $ruta_completa = 'imagenes/' . $archivo; $tipo = is_dir($ruta_completa) ? 'Directorio' : 'Archivo'; echo "- $archivo ($tipo)<br>"; } }}
// Alternativa usando glob() para listar archivos con un patrón$imagenes = glob('imagenes/*.{jpg,png,gif}', GLOB_BRACE);echo "Imágenes encontradas: " . count($imagenes) . "<br>";foreach ($imagenes as $imagen) { echo "- $imagen<br>";}
// Recorrer un directorio con RecursiveDirectoryIterator$directorio = new RecursiveDirectoryIterator('proyecto');$iterador = new RecursiveIteratorIterator($directorio);
echo "Listado recursivo de archivos:<br>";foreach ($iterador as $archivo) { // Omitir . y .. if ($archivo->isFile()) { echo $archivo->getPathname() . "<br>"; }}?>Función para Eliminar Directorios Recursivamente
Section titled “Función para Eliminar Directorios Recursivamente”<?php/*** Elimina un directorio y todo su contenido recursivamente* @param string $dir Ruta del directorio a eliminar* @return bool True si se eliminó correctamente, False en caso contrario*/function eliminar_directorio_recursivo($dir) { if (!file_exists($dir)) { return true; }
if (!is_dir($dir)) { return unlink($dir); }
foreach (scandir($dir) as $item) { if ($item == '.' || $item == '..') { continue; }
if (!eliminar_directorio_recursivo($dir . DIRECTORY_SEPARATOR . $item)) { return false; } }
return rmdir($dir);}
// Uso de la funciónif (eliminar_directorio_recursivo('directorio_temporal')) { echo "Directorio y todo su contenido eliminados con éxito";} else { echo "Error al eliminar el directorio";}?>Rutas y Directorios Temporales
Section titled “Rutas y Directorios Temporales”<?php// Obtener la ruta del directorio temporal del sistema$directorio_temporal = sys_get_temp_dir();echo "Directorio temporal del sistema: $directorio_temporal<br>";
// Crear un archivo temporal$archivo_temporal = tempnam(sys_get_temp_dir(), 'prefijo_');echo "Archivo temporal creado: $archivo_temporal<br>";
// Escribir en el archivo temporalfile_put_contents($archivo_temporal, "Datos temporales: " . date('Y-m-d H:i:s'));
// Leer el contenidoecho "Contenido: " . file_get_contents($archivo_temporal) . "<br>";
// Eliminar el archivo temporal cuando ya no se necesiteunlink($archivo_temporal);
// Crear un directorio temporal (PHP 7+)if (function_exists('random_bytes')) { $dir_temp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'tmp_' . bin2hex(random_bytes(8));} else { $dir_temp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'tmp_' . uniqid();}
mkdir($dir_temp);echo "Directorio temporal creado: $dir_temp<br>";
// Usar el directorio temporal...
// Eliminar el directorio temporal cuando ya no se necesitermdir($dir_temp);?>Resumen
Section titled “Resumen”El manejo de archivos en PHP es una funcionalidad poderosa que permite:
- Leer y escribir archivos con diferentes métodos según las necesidades
- Subir archivos de forma segura desde formularios web
- Manipular archivos y directorios en el servidor
- Obtener información detallada sobre archivos y directorios
- Trabajar con formatos específicos como CSV o JSON
- Gestionar permisos y propiedades de archivos