9. Ficheros
Es posible importar o llamar el código desde otro archivo con PHP. De esta manera conseguiremos dividir nuestras página dinámicas en fragmentos más pequeños y fáciles de gestionar evitando el famoso código Spaghetti (escribir todo nuestro código en un solo fichero con un interminable número de líneas). Para esta buena práctica disponemos en nuestro bat-cinturón de hasta 4 herramientas diferentes.
| Función | Descripción | Caso de error | Ejemplo |
|---|---|---|---|
include '' |
Incluye el fichero en cada ocasión. | Da una advertenia, pero continua la ejecución. | include 'tu_archivo.php' |
include_once '' |
Incluye el fichero en una ocasión. | Da una advertenia, pero continua la ejecución. | include_once 'tu_archivo.php' |
require '' |
Incluye el fichero en cada ocasión. | Para la ejecución (Error fatal). | require 'tu_archivo.php' |
require_once '' |
Incluye el fichero en una ocasión. | Para la ejecución (Error fatal). | require_once 'tu_archivo.php' |
Veamos con un ejemplo como funciona. Voy a tener un archivo llamado header.php con el siguiente contenido.
<html>
<head>
</head>
<body>
Otro con el nombre footer.php.
<footer>Soy yo</footer>
</body>
</html>
Ahora creo un fichero nuevo.
<?php include 'header.php'; ?>
<h1>Inicio</h1>
<?php include 'footer.php'; ?>
Me daria el siguiente HTML.
<html>
<head>
</head>
<body>
<h1>Inicio</h1>
<footer>Soy yo</footer>
</body>
</html>
Potente, ¿verdad? Evitaremos repartir partes de nuestro código que sean muy reiterativas.
En esta ocasión voy a repetir el include de footer.
Ahora creo un fichero nuevo.
<?php include 'header.php'; ?>
<h1>Inicio</h1>
<?php include 'footer.php'; ?>
<?php include 'footer.php'; ?>
Lo que me generaría un pie duplicado.
<html>
<head>
</head>
<body>
<h1>Inicio</h1>
<footer>Soy yo</footer>
</body>
</html>
<footer>Soy yo</footer>
</body>
</html>
Lo podemos prevenir con include_once.
<?php include 'header.php'; ?>
<h1>Inicio</h1>
<?php include_once 'footer.php'; ?>
<?php include_once 'footer.php'; ?>
Si ya ha sido llamado, lo ingora.
<html>
<head>
</head>
<body>
<h1>Inicio</h1>
<footer>Soy yo</footer>
</body>
</html>
Subir un archivo
Un fichero es un elemento en binario que no es ni un número o ni un texto: imagen, video, música, doc, iso... Nosotros somos incapaces de leerlo a no ser que tengamos un ojo biónico y un chip en el cerebro. Si careces de estos dos requisitos solo podrás subirlo, por medio de un formulario, y almacenarlo en una carpeta.
Se debe tratar de una forma especial. Necesitaremos usar siempre el method POST y añadir enctype="multipart/form-data". Por último usar el input de tipo archivo (file).
<!-- Formulario -->
<form method="post" enctype="multipart/form-data">
<p>
<!-- Campo imagen -->
<input type="file" name="fichero_usuario">
</p>
<p>
<!-- Botón submit -->
<input type="submit" value="Enviar">
</p>
</form>
Cuando nuestro formulario sea enviado el archivo estará almacenado en una variable llamada $_FILES. La cual es un array con toda la información que vas a necesitar.
| Nombre | Ejemplo de contenido | Descripción |
|---|---|---|
| $_FILES['fichero_usuario']['name'] | 'foto_en_la_playa.jpg' | Nombre del archivo |
| $_FILES['fichero_usuario']['type'] | 'image/png' | MIME (formato del archivo) |
| $_FILES['fichero_usuario']['size'] | 3232424 | Tamaño en bytes (5MB -> 5 x 1024 x 1024 bytes) |
| $_FILES['fichero_usuario']['error'] | 0 | Código de error. El 0 es que todo ha ido bien, los otros puedes encontrarlos aquí |
| $_FILES['fichero_usuario']['tmp_name'] | 213 | Nombre temporal |
Ahora solo tendremos que moverlo de la carpeta temporal a la definitiva, usando el método move_uploaded_file().
move_uploaded_file($_FILES['fichero_usuario']['tmp_name'], $fichero_subido);
Aquí puedes ver un ejemplo completo.
<html>
<body>
<?php
//======================================================================
// PROCESAR IMAGEN
//======================================================================
// Comprobamos si nos llega los datos por POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Definir directorio donde se guardará
$dir_subida = './subidos/';
// Definir la ruta final del archivo
$fichero_subido = $dir_subida . basename($_FILES['fichero_usuario']['name']);
// Mueve el archivo de la carpeta temporal a la ruta definida
if (move_uploaded_file($_FILES['fichero_usuario']['tmp_name'], $fichero_subido)) {
// Mensaje de confirmación donde todo ha ido bien
echo '<p>Se subió perfectamente.</p>';
// Muestra la imagen que acaba de ser subida
echo '<p><img width="500" src="' . $fichero_subido . '"></p>';
} else {
// Mensaje de error: ¿Límite de tamaño? ¿Ataque?
echo '<p>¡Ups! Algo ha pasado.</p>';
}
}
?>
<!-- Formulario -->
<form method="post" enctype="multipart/form-data">
<p>
<!-- Campo imagen -->
<input type="file" name="fichero_usuario">
</p>
<p>
<!-- Botón submit -->
<input type="submit" value="Enviar">
</p>
</form>
</body>
</html>
Multiarchivo (subir varios archivos)
Es posible subir varios archivos bajo el mismo nombre. Solo habrá que añadir unos corchetes ([]) después del name como si fuera un array.
<!-- Formulario -->
<form method="post" enctype="multipart/form-data">
<p>
<!-- Campos de imágenes -->
<input type="file" name="imagen[]">
<input type="file" name="imagen[]">
<input type="file" name="imagen[]">
</p>
<p>
<!-- Botón submit -->
<input type="submit" value="Enviar">
</p>
</form>
Al recibir los datos tendremos que iterar la variable, igual que un array. Es recomendable comprobar en cada caso que el archivo se ha subido correctamente.
// Comprobamos si nos llega los datos por POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Iteramos todos los archivos
foreach ($_FILES["imagen"]["error"] as $posicion => $error) {
// Comprobamos si se ha subido correctamente
if ($error == UPLOAD_ERR_OK) {
// Definir directorio donde se guardará
$dir_subida = './subidos/';
// Definir la ruta final del archivo
$fichero_subido = $dir_subida . basename($_FILES['imagen']['name'][$posicion]);
// Mueve el archivo de la carpeta temporal a la ruta definida
if (move_uploaded_file($_FILES['imagen']['tmp_name'][$posicion], $fichero_subido)) {
// Mensaje de confirmación donde todo ha ido bien
echo '<p>Se subió perfectamente' . $_FILES['imagen']['name'][$posicion] . '.</p>';
// Muestra la imagen que acaba de ser subida
echo '<p><img width="500" src="' . $fichero_subido . '"></p>';
} else {
// Mensaje de error: ¿Límite de tamaño? ¿Ataque?
echo '<p>¡Ups! Algo ha pasado.</p>';
}
}
}
}
Junto quedaría de la siguiente forma.
<html>
<body>
<?php
//======================================================================
// PROCESAR IMAGENES
//======================================================================
// Comprobamos si nos llega los datos por POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Iteramos todos los archivos
foreach ($_FILES["imagen"]["error"] as $posicion => $error) {
// Comprobamos si se ha subido correctamente
if ($error == UPLOAD_ERR_OK) {
// Definir directorio donde se guardará
$dir_subida = './subidos/';
// Definir la ruta final del archivo
$fichero_subido = $dir_subida . basename($_FILES['imagen']['name'][$posicion]);
// Mueve el archivo de la carpeta temporal a la ruta definida
if (move_uploaded_file($_FILES['imagen']['tmp_name'][$posicion], $fichero_subido)) {
// Mensaje de confirmación donde todo ha ido bien
echo '<p>Se subió perfectamente' . $_FILES['imagen']['name'][$posicion] . '.</p>';
// Muestra la imagen que acaba de ser subida
echo '<p><img width="500" src="' . $fichero_subido . '"></p>';
} else {
// Mensaje de error: ¿Límite de tamaño? ¿Ataque?
echo '<p>¡Ups! Algo ha pasado.</p>';
}
}
}
}
?>
<!-- Formulario -->
<form method="post" enctype="multipart/form-data">
<p>
<!-- Campos de imágenes -->
<input type="file" name="imagen[]">
<input type="file" name="imagen[]">
<input type="file" name="imagen[]">
</p>
<p>
<!-- Botón submit -->
<input type="submit" value="Enviar">
</p>
</form>
</body>
</html>
Borrar archivos
Para eliminar un archivo debemos usar el método unlink.
unlink('archivo');
Tan solo hay que dar la ruta que deseamos.
unlink('subidos/coche_rojo.jpg');
Evitar que se sobrescriba
¿Qué pasa si subimos dos archivos con el mismo nombre? Pues que el anterior desaparecería, se sobrescribiría por tener el mismo nombre y guardarse en el mismo lugar. Debemos garantiza que el archivo posee un nombre único.
Un truco para solucionarlo generando un hash, o una secuencia alfanumérica única por cada archivo que sustituya al nombre. Un algoritmo muy popular es SHA-1.
En criptografía, SHA-1 (Secure Hash Algorithm 1) es una función hash criptográfica que ha sido rota, pero que sigue siendo ampliamente utilizada para generar un número hexadecimal de 40 dígitos. Su autor fue la Agencia de Seguridad Nacional de Estados Unidos, siendo usando para el procesamiento de información de Estados Unidos.
Si quisiéramos obtener un hash de un texto, deberíamos usar sha1().
echo sha1('texto');
// ea631551f5569f612dd702b900c596c2a99c0dfd
Para archivos disponemos de una función determinada llamada hash_file(). En este ejemplo usamos el algoritmo SHA-256, más seguro que SHA-1.
echo hash_file('sha256', $_FILES['fichero_usuario']['tmp_name']);
// f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2ef
Si tuvieramos un archivo llamado reloj.jpg.
$fichero_subido = $dir_subida . hash_file('sha256', $_FILES['fichero_usuario']['tmp_name']) . basename($_FILES['fichero_usuario']['name']);
echo $fichero_subido;
// subidos/f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2efreloj.jpg
Por muchos archivos reloj.jpg que suban nunca se sobrescribirán, a no ser que a nivel binario sean exactamente iguales (lo cual tampoco sería un problema porque sería el mismo fichero).
Tamaño máximo
Si quieres limitar el tamaño de todos los archivos puedes hacerlo añadiendo un input especial.
<input type="hidden" name="MAX_FILE_SIZE" value="20000" />
El value se mide en bytes.
Si un archivo supera nuestra frontera dará un error, pero nunca llegará a subirse.
Otra forma de cambiarlo, en este caso permanente, es modificando unas variables de PHP en su archivo de configuración.
sudo nano /etc/php/{versión}/cli/php.ini
Edita las siguientes variables si quieres limitarlo a 100Mb.
upload_max_filesize=100Mb
post_max_size=100Mb
Igualmente valida el tamaño con PHP, es fácil manipular el límite dentro del navegador. Recuerda: nunca te fíes del usuario.
Procesamiento de imágenes
PHP no esta solamente limitado a la generación de HTML y mover archivos, también puede procesar imágenes. Existen una multitud de posibilidades.
- Redimensionar (utilizado para crear miniaturas).
- Recortar.
- Aplicar filtros de color.
- Crear imágenes (como suena).
- Añadir marcas de agua.
- Cambiar de formato.
Para crear una minuatura podrías hacerlo usando la libreria nativa Imagick.
Primero tendremos que instalarla en el sistema. Con Ubuntu o Debian es muy sencillo.
sudo apt install php-imagick
Aahora ya puedes trabajar con ella. En el siguiente ejemplo se captura imagen.jpg y se redimensiona a 100px de ancho. Por último se guarda con el nombre de miniatura.jpg.
$imagen = new Imagick('imagen.jpg');
// Si se proporciona 0 como parámetro de ancho o alto,
// se mantiene la proporción de aspecto
$imagen->thumbnailImage(100, 0);
// La guarda
file_put_contents('miniatura.jpg', $imagen);
Dispone de diversas herramientas para manipular formatos tan conocidos como: JPEG, GIF, PNG y WebP (entre otros). Puedes ver más en la documentación.
Ejemplo completo
Puedes ver un ejemplo que recoge todos los casos anteriores.
- Valida que se ha adjuntado una imagen en el formulario.
- Valida que sea una imagen en jpg o png.
- Valida que no supere cierto tamaño. En este caso 2Mb.
- Crea una miniatura. En este caso de 100px de ancho.
- Cambia el nombre aleatorio para evitar posibles conflictos con otros archivos.
- Muestra la miniatura en el HTML.
<?php
//======================================================================
// VARIABLES
//======================================================================
$errorAvatar = 0;
$avatar = null;
$rutaThumbnail = null;
// Definir directorio donde se guardará
define('PATH_AVATAR', './subidos/');
define('PATH_AVATAR_THUMBNAIL', './subidos/thumbnails/');
// Tamanyo max avatar: 2 Mb
define('MAX_SIZE_AVATAR_MB', 2);
define('MAX_SIZE_AVATAR', MAX_SIZE_AVATAR_MB * 1024 * 1024);
// En /etc/php/7.4/cli/php.ini edita las siguientes variables
// upload_max_filesize=100Mb
// post_max_size=100Mb
// Anchura miniatura
define('WIDTH_THUMBNAIL', 100);
//======================================================================
// PROCESAR FORMULARIO
//======================================================================
// Comprobamos si nos llega los datos por POST
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES)) {
//-----------------------------------------------------
// Recoger avatar
//-----------------------------------------------------
// Verifica si existe el directorio, y en caso contrario lo crea
if (!is_dir(PATH_AVATAR_THUMBNAIL)) {
mkdir(PATH_AVATAR_THUMBNAIL, 0775, true);
}
// Definir la ruta final del archivo
$nombreFoto = hash_file('sha256', $_FILES['avatar']['tmp_name']) . basename($_FILES['avatar']['name']);
$ficheroSubido = PATH_AVATAR . $nombreFoto;
//-----------------------------------------------------
// Control de errores
//-----------------------------------------------------
// Tamanyo maximo
if ($_FILES['avatar']['size'] > MAX_SIZE_AVATAR) {
$errorAvatar = 1;
}
// Solo JPG y PNG
if ($_FILES['avatar']['type'] !== 'image/png' && $_FILES['avatar']['type'] !== 'image/jpeg') {
$errorAvatar = 2;
}
// Obligatorio
if ($_FILES['avatar']['size'] === 0) {
$errorAvatar = 3;
}
//-----------------------------------------------------
// Procesar imagen
//-----------------------------------------------------
if ($errorAvatar === 0) {
if (move_uploaded_file($_FILES['avatar']['tmp_name'], $ficheroSubido)) {
// Mueve el archivo de la carpeta temporal a la ruta definida
$avatar = $ficheroSubido;
// Creamos una miniatura
// No olvides instalarlo con: sudo apt install php-imagick
$imagen = new Imagick($avatar);
// Si se proporciona 0 como parámetro de ancho o alto,
// se mantiene la proporción de aspecto
$imagen->thumbnailImage(WIDTH_THUMBNAIL, 0);
$rutaThumbnail = PATH_AVATAR_THUMBNAIL . $nombreFoto;
file_put_contents($rutaThumbnail, $imagen);
}
}
}
?>
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Perfil</title>
</head>
<body>
<?php if (isset($rutaThumbnail)): ?>
<img src="<?= $rutaThumbnail; ?>" alt="mi avatar" width="<?= WIDTH_THUMBNAIL ?>">
<?php endif; ?>
<form method="post" enctype="multipart/form-data">
<p>
<label>
Foto:
<input type="file" name="avatar">
</label>
</p>
<?php if ($errorAvatar === 1): ?>
<p style="color: red">
Tamaño demasiado grande, intente que tenga menos de <?= MAX_SIZE_AVATAR_MB ?>Mb
</p>
<?php elseif ($errorAvatar === 2): ?>
<p style="color: red">
Solo admitido imagenes en JPG o PNG.
</p>
<?php elseif ($errorAvatar === 3): ?>
<p style="color: red">
Debes incluir una imagen
</p>
<?php endif; ?>
<p>
<input type="submit" value="Guardar">
</p>
</form>
</body>
</html>
Validación y Seguridad
Subir archivos sin validarlos correctamente es una de las vulnerabilidades más peligrosas en una aplicación web. Un atacante podría subir código malicioso (por ejemplo un archivo PHP disfrazado de imagen) y ejecutarlo en tu servidor. Por eso es fundamental validar siempre los archivos que subes.
Regla de oro: Nunca confíes en los datos que vienen del cliente. Un usuario puede modificar fácilmente el tipo MIME desde el navegador.
Validar el tipo MIME real
El tipo MIME que viene en $_FILES['archivo']['type'] puede ser falsificado por el cliente. Para validar correctamente debemos usar funciones de PHP que analicen el contenido real del archivo.
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$archivoTemporal = $_FILES['imagen']['tmp_name'];
// Obtener el tipo MIME real del archivo
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeReal = finfo_file($finfo, $archivoTemporal);
finfo_close($finfo);
// Lista blanca de tipos permitidos
$tiposPermitidos = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($mimeReal, $tiposPermitidos)) {
die('Error: Solo se permiten imágenes (JPG, PNG, GIF, WEBP)');
}
echo "Tipo MIME válido: $mimeReal";
}
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="imagen">
<input type="submit" value="Subir">
</form>
Validar tamaño del archivo
Limita el tamaño máximo para evitar que alguien sature tu servidor con archivos enormes.
<?php
// Tamaño máximo: 5MB
$tamañoMaximo = 5 * 1024 * 1024; // 5MB en bytes
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($_FILES['imagen']['size'] > $tamañoMaximo) {
die('Error: El archivo excede el tamaño máximo de 5MB');
}
if ($_FILES['imagen']['size'] === 0) {
die('Error: El archivo está vacío');
}
echo 'Tamaño válido: ' . round($_FILES['imagen']['size'] / 1024, 2) . ' KB';
}
?>
Sanitizar el nombre del archivo
Los nombres de archivo pueden contener caracteres peligrosos o rutas relativas (../../../etc/passwd). Siempre debes generar un nombre seguro.
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Obtener la extensión real
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeReal = finfo_file($finfo, $_FILES['imagen']['tmp_name']);
finfo_close($finfo);
// Mapear MIME a extensión
$extensiones = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp'
];
$extension = $extensiones[$mimeReal] ?? 'bin';
// Generar nombre único y seguro
$nombreSeguro = uniqid('img_', true) . '.' . $extension;
$rutaDestino = './subidos/' . $nombreSeguro;
if (move_uploaded_file($_FILES['imagen']['tmp_name'], $rutaDestino)) {
echo "Archivo subido correctamente: $nombreSeguro";
}
}
?>
¿Por qué no usar el nombre original? Porque podría contener caracteres especiales, espacios, rutas relativas o extensiones peligrosas. Un atacante podría subir
shell.php.jpgesperando que tu servidor lo ejecute como PHP.
Almacenar fuera del webroot
La forma más segura de almacenar archivos subidos es guardarlos fuera de la carpeta pública de tu servidor web. Así, aunque alguien suba un archivo PHP malicioso, el servidor web no podrá ejecutarlo.
<?php
// Directorio fuera del webroot (no accesible directamente desde el navegador)
$directorioSeguro = '../uploads_privados/';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$nombreSeguro = uniqid('doc_', true) . '.pdf';
$rutaCompleta = $directorioSeguro . $nombreSeguro;
if (move_uploaded_file($_FILES['documento']['tmp_name'], $rutaCompleta)) {
// Guardar el nombre en la base de datos para recuperarlo después
echo "Documento guardado de forma segura";
}
}
?>
Para servir el archivo después, crea un script que lo lea y lo envíe con los headers correctos:
<?php
// download.php
$archivoId = $_GET['id'] ?? '';
// Aquí validarías que el usuario tiene permiso para descargar este archivo
// y obtendrías el nombre real desde la base de datos
$rutaArchivo = '../uploads_privados/' . $archivoId;
if (file_exists($rutaArchivo)) {
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="documento.pdf"');
readfile($rutaArchivo);
exit;
}
?>
Ejemplo completo y seguro
Aquí tienes un ejemplo que combina todas las mejores prácticas:
<?php
// Configuración
$directorioSubidas = './subidos/';
$tamañoMaximo = 5 * 1024 * 1024; // 5MB
$tiposPermitidos = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$extensiones = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp'
];
$error = '';
$exito = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['imagen'])) {
// 1. Verificar que no hubo errores en la subida
if ($_FILES['imagen']['error'] !== UPLOAD_ERR_OK) {
$error = 'Error al subir el archivo';
}
// 2. Validar tamaño
elseif ($_FILES['imagen']['size'] === 0) {
$error = 'El archivo está vacío';
}
elseif ($_FILES['imagen']['size'] > $tamañoMaximo) {
$error = 'El archivo excede el tamaño máximo de 5MB';
}
else {
// 3. Validar tipo MIME real
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeReal = finfo_file($finfo, $_FILES['imagen']['tmp_name']);
finfo_close($finfo);
if (!in_array($mimeReal, $tiposPermitidos)) {
$error = 'Solo se permiten imágenes (JPG, PNG, GIF, WEBP)';
}
else {
// 4. Generar nombre seguro
$extension = $extensiones[$mimeReal];
$nombreSeguro = uniqid('img_', true) . '.' . $extension;
$rutaDestino = $directorioSubidas . $nombreSeguro;
// 5. Mover el archivo
if (move_uploaded_file($_FILES['imagen']['tmp_name'], $rutaDestino)) {
$exito = "Imagen subida correctamente: $nombreSeguro";
} else {
$error = 'Error al mover el archivo';
}
}
}
}
?>
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Subida segura de imágenes</title>
</head>
<body>
<h1>Subir imagen (con validación segura)</h1>
<?php if ($error): ?>
<p style="color: red; font-weight: bold;"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<?php if ($exito): ?>
<p style="color: green; font-weight: bold;"><?= htmlspecialchars($exito) ?></p>
<img src="<?= htmlspecialchars($directorioSubidas . basename($nombreSeguro)) ?>" width="400" alt="Imagen subida">
<?php endif; ?>
<form method="post" enctype="multipart/form-data">
<label>
Selecciona una imagen (JPG, PNG, GIF, WEBP, máx 5MB):
<input type="file" name="imagen" accept="image/*" required>
</label>
<button type="submit">Subir imagen</button>
</form>
</body>
</html>
Recuerda: La seguridad es como las capas de una cebolla. Cada capa de validación suma. Nunca confíes solo en validaciones del lado del cliente (HTML5
accept, JavaScript), siempre valida en el servidor.
Actividad 1
- Crea una web donde se pida un usuario y una contraseña.
- Si es correcto debe llegar a una página protegida por sesión.
- Añade un botón para cerrar la sesión.
This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.
Desafíos de programación atemporales y multiparadigmáticos
Te encuentras ante un librillo de actividades, divididas en 2 niveles de dificultad. Te enfrentarás a los casos más comunes que te puedes encontrar en pruebas técnicas o aprender conceptos elementales de programación.
Buy the book
Support me on Ko-fi
Comments
There are no comments yet.