Arrays indexados y asociativos
Un array es una variable que guarda una colección ordenada de valores. PHP los crea
con corchetes [] (sustituyendo a la antigua array(), aún válida). Hay dos
familias:
1.1 · Arrays indexados (listas)
Cada elemento tiene un índice numérico automático que empieza en 0:
$paises = ["España", "Francia", "Italia"];
echo $paises[0]; // "España"
echo $paises[2]; // "Italia"
echo count($paises); // 3 — cuántos elementos hay
$paises[] = "Portugal"; // se añade al final
var_dump($paises);
1.2 · Arrays asociativos (mapas clave → valor)
En lugar de números, cada elemento tiene una clave con nombre (key => value).
Son perfectos para representar a una persona, un producto, un usuario…:
$usuario = [
"nombre" => "Raúl",
"edad" => 34,
"ciudad" => "Madrid",
];
echo $usuario["nombre"]; // "Raúl"
echo $usuario["edad"]; // 34
1.3 · Arrays multidimensionales
Un array cuyos elementos son a su vez arrays: la forma natural de modelar «una lista de usuarios» o «una lista de productos». Los usarás constantemente con bases de datos:
$productos = [
["nombre" => "Ratón", "precio" => 9.99],
["nombre" => "Teclado","precio" => 24.50],
["nombre" => "Monitor","precio" => 129.00],
];
echo $productos[0]["nombre"]; // "Ratón"
echo $productos[2]["precio"]; // 129
$_POST,
$_GET) y las sesiones. Domina esta sintaxis.Funciones de arrays y ordenación
2.1 · Añadir y quitar elementos
$frutas = ["manzana", "pera"];
array_push($frutas, "uva"); // añade al final: [.., "uva"]
$frutas[] = "naranja"; // igual que arriba
array_pop($frutas); // quita el último → "naranja"
array_shift($frutas); // quita el primero → "manzana"
in_array("pera", $frutas); // true — está dentro
array_sum([2, 3, 4]); // 9 — suma
count([1, 2]); // 2 — longitud
2.2 · Recorrer con foreach (ambos formatos)
$usuario = ["nombre" => "Raúl", "edad" => 34];
// solo valores
foreach ($usuario as $valor) {
echo "$valor ";
}
// clave => valor
foreach ($usuario as $clave => $valor) {
echo "$clave: $valor\n";
}
2.3 · Ordenar arrays
Existen funciones de ordenación para cada caso; lo importante es recordar cuál trabaja sobre el array in situ (lo modifica) y su familia:
| Función | Qué ordena | Dirección |
|---|---|---|
sort() | Valores (reindexa) | Ascendente |
rsort() | Valores (reindexa) | Descendente |
asort() | Valores (conserva claves) | Ascendente |
arsort() | Valores (conserva claves) | Descendente |
ksort() | Claves | Ascendente |
krsort() | Claves | Descendente |
$notas = [8, 3, 9, 5];
sort($notas); // [3, 5, 8, 9]
$frutas = ["pera", "uva", "manzana"];
sort($frutas); // ['manzana', 'pera', 'uva'] — alfabético
$n = [1..5]; // PHP 8.1+: range literal 1..5 = [1,2,3,4,5]
$rev = array_reverse($n); // [5,4,3,2,1]
sort() y rsort() reindexan: si usas claves con
nombre en un array asociativo, se las pierde. Emplea asort()/arsort() para
conservarlas.Ficheros: leer y escribir
Con PHP puedes leer y escribir archivos en el servidor: guardar datos de un formulario, contadores de visitas, logs, configuraciones… Estas funciones lo hacen muy sencillo.
3.1 · Escribir un fichero: file_put_contents
// Crea o sobrescribe el archivo con el contenido dado
file_put_contents("datos.txt", "Hola, fichero!\n");
file_put_contents("datos.txt", "Más texto\n", FILE_APPEND); // añade al final
3.2 · Leer un fichero: file_get_contents y file
// Todo el contenido en un string
$contenido = file_get_contents("datos.txt");
echo $contenido;
// Cada línea en un elemento de array
$lineas = file("datos.txt"); // ["Hola...","Más texto\n"]
// Comprobar que existe
if (file_exists("datos.txt")) {
echo "El archivo existe.\n";
} else {
echo "El archivo no existe.\n";
}
3.3 · Serializar datos: cuando guardas arrays/objetos
Para guardar un array o un objeto en un fichero y poder recuperarlo tal cual, se usa
serialize()/unserialize(), o el superobjeto json_encode()/
json_decode() (el más recomendado para intercambiar con otras herramientas):
$usuario = ["nombre" => "Raúl", "edad" => 34];
// Guardar como JSON
file_put_contents("usuario.json", json_encode($usuario));
// Recuperar
$json = file_get_contents("usuario.json");
$datos = json_decode($json, true); // true → array asociativo
echo $datos["nombre"];
Sesiones, cookies y autenticación
HTTP es un protocolo sin memoria: cada petición es independiente. Para que una web «recuerde» quién eres o qué tienes en el carrito, usamos cookies (datos en el navegador) y sesiones (datos guardados en el servidor, asociados a un identificador enviado por cookie).
4.1 · Sesiones: la memoria del servidor
// SIEMPRE al principio, antes de CUALQUIER salida HTML
session_start();
// Guardar datos en la sesión
$_SESSION["usuario"] = "raul";
$_SESSION["carrito"] = ["raton" => 2, "monitor" => 1];
// Leer
echo $_SESSION["usuario"]; // raul
4.2 · Borrar y destruir la sesión
session_start();
// Vaciar las variables
$_SESSION = [];
// Borrar la cookie de sesión del navegador
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), "", time() - 42000, $params["path"]);
}
session_destroy(); // destruye los datos en el servidor
4.3 · Cookies con setcookie
// setcookie(nombre, valor, expiración); tiempo en segundos
setcookie("idioma", "es", time() + 3600 * 24 * 30); // 30 días
// La cookie solo está disponible en la SIGUIENTE carga
echo $_COOKIE["idioma"] ?? "es por defecto";
setcookie() y session_start() deben ejecutarse antes
de enviar cualquier HTML (incluso un espacio en blanco antes de <?php) porque
modifican las cabeceras HTTP. Si ves el aviso «headers already sent», es por eso.4.4 · Autenticación básica en memoria
Un patrón de login mínimo: comprobar credenciales y guardar la decisión en sesión. En el Bloque 3 lo harás contra una base de datos y con contraseñas con hash (nunca en claro):
session_start();
// Usuarios «de ejemplo» (¡en el Bloque 3 vendrán de la BD con hash!)
$usuarios = [
"raul" => "secreto123",
"alba" => "otrapass",
];
$enviado = $_SERVER["REQUEST_METHOD"] === "POST";
$nombre = $_POST["usuario"] ?? "";
$clave = $_POST["clave"] ?? "";
if ($enviado && isset($usuarios[$nombre]) &&
$usuarios[$nombre] === $clave) {
$_SESSION["logueado"] = true;
$_SESSION["usuario"] = $nombre;
header("Location: area-privada.php"); // redirigir tras login
exit;
}
// Comprobar en páginas protegidas
if (empty($_SESSION["logueado"])) {
header("Location: login.php");
exit;
}
$_POST, $_GET, $_SESSION, $_COOKIE,
$_SERVER… son los llamados superglobales: arrays asociativos automáticos que
PHP prepara en cada petición. Son la puerta de entrada de los datos del usuario (¡y de su ataque favorito,
la inyección, que verás en el Bloque 3!).Incluir plantillas y modularizar
Para no repetir la cabecera, el menú y el pie en cada página, PHP permite incluir
otros archivos PHP. La diferencia entre include y require: si el archivo falta,
require provoca un error fatal que detiene todo, mientras que include solo lanza
un aviso y continúa. Hay variantes _once para evitar cargarlos dos veces.
| Instrucción | Si el archivo no existe | Úsala para… |
|---|---|---|
include | Aviso y sigue | Plantillas no críticas |
require | Error fatal y para | Código imprescindible |
include_once / require_once | - | Cuando puede cargarse en varios puntos |
5.1 · Dividir la interfaz en plantillas
Creamos plantillas reutilizables y cada página las «monta»:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title><?= $titulo ?></title>
</head>
<body>
<nav><a href="index.php">Inicio</a></nav>
<footer>© <?= date("Y") ?> TécnicoWeb</footer>
</body>
</html>
<?php
$titulo = "Inicio";
require "header.php"; // si falta, error fatal: es vital
?>
<main>
<h1>Bienvenido</h1>
<p>Contenido propio de esta página.</p>
</main>
<?php
include "footer.php"; // no crítico: include basta
?>
require las variables declaradas en el script que incluye quedan
disponibles dentro del archivo incluido (por eso $titulo llega a header.php).
Es una forma rudimentaria de «plantillas» que perfeccionarás con POO y Composer en el Bloque 3.✍️ Los 18 ejercicios del bloque
Crea la carpeta php-b2/ dentro de htdocs y abre cada archivo a través de
localhost/php-b2/…. Los ejercicios de formularios y sesiones necesitan una petición real al
servidor (no bastan en la consola).
Sección A · Arrays
1 Lista de frutas
Crea un array indexado $frutas con al menos 4 frutas. Muestra la primera, la última
(usa count() para el índice final) y el total con count().
Ver solución
$frutas = ["manzana", "pera", "uva", "naranja"];
echo "Primera: {$frutas[0]}\n";
echo "Última: {$frutas[count($frutas) - 1]}\n";
echo "Total: " . count($frutas) . "\n";
2 Ficha de usuario
Crea un array asociativo $usuario con nombre, edad y
ciudad. Muestra cada valor por separado y después recórrelo con foreach ($usuario as
$clave => $valor) mostrando clave: valor en cada línea.
Ver solución
$usuario = [
"nombre" => "Raúl",
"edad" => 34,
"ciudad" => "Madrid",
];
foreach ($usuario as $clave => $valor) {
echo "$clave: $valor\n";
}
3 Suma de notas con array_sum
Ten el array $notas = [8, 9, 6, 10, 5]. Calcula y muestra la suma con
array_sum(), el total de notas con count() y la media (divisiones). Imprime
la media con dos decimales usando number_format().
Ver solución
$notas = [8, 9, 6, 10, 5];
$suma = array_sum($notas);
$total = count($notas);
$media = $suma / $total;
echo "Suma: $suma\n";
echo "Media: " . number_format($media, 2) . "\n";
4 Lista de productos
Crea un array multidimensional $productos con 3 productos, cada uno con
nombre y precio. Recórrelo con foreach mostrando
«nombre — precio €» por línea. Añade un producto nuevo usando array_push() y muestra de
nuevo la lista.
Ver solución
$productos = [
["nombre" => "Ratón", "precio" => 9.99],
["nombre" => "Teclado","precio" => 24.50],
["nombre" => "Monitor","precio" => 129.00],
];
foreach ($productos as $p) {
echo $p["nombre"] . " — " . $p["precio"] . " €\n";
}
array_push($productos, ["nombre" => "Webcam", "precio" => 39.90]);
foreach ($productos as $p) {
echo $p["nombre"] . " — " . $p["precio"] . " €\n";
}
5 ¿Está en la lista?
Con el array $paises = ["España", "Francia", "Italia"], comprueba con
in_array() si «España» y «Japón» están en la lista y muestra un mensaje en cada caso con
un ternario o if/else.
Ver solución
$paises = ["España", "Francia", "Italia"];
echo in_array("España", $paises) ? "España: sí\n" : "España: no\n";
echo in_array("Japón", $paises) ? "Japón: sí\n" : "Japón: no\n";
6 Ordenar y dar la vuelta
Con $notas = [8, 3, 9, 5]: muéstralas ordenadas de menor a mayor con sort(),
usa rsort() para de mayor a menor y array_reverse() para invertir. Comenta
qué cambia en cada paso.
Ver solución
$notas = [8, 3, 9, 5];
sort($notas); var_dump($notas); // [3,5,8,9]
rsort($notas); var_dump($notas); // [9,8,5,3]
$invertidas = array_reverse($notas);
var_dump($invertidas); // [3,5,8,9] (no modifica el original)
Sección B · Ficheros
7 Guardar un mensaje
Usa file_put_contents() para guardar en mensajes.txt una línea con tu
nombre y la fecha actual con date("Y-m-d H:i"). Ejecuta el script dos veces y luego lee
y muestra el contenido con file_get_contents().
Ver solución
$nombre = "Raúl";
$mensaje = "$nombre — " . date("Y-m-d H:i") . "\n";
file_put_contents("mensajes.txt", $mensaje, FILE_APPEND); // añade (no sobrescribe)
$contenido = file_get_contents("mensajes.txt");
echo "Contenido:\n$contenido";
8 Contador de visitas
Crea contador.php que lea un número de visitas.txt, le sume 1, lo guarde y
muestre «Has visitado esta página N veces.». Pista: lee con file_get_contents(), suma,
guarda con file_put_contents(). La primera vez el archivo no existe, usa
file_exists() para empezar en 0.
Ver solución
$archivo = "visitas.txt";
$visitas = file_exists($archivo) ?
(int)file_get_contents($archivo) : 0;
$visitas++;
file_put_contents($archivo, $visitas);
echo "Has visitado esta página $visitas veces.\n";
9 Guardar un array en JSON
Ten un array asociativo con tu ficha. Guárdalo en ficha.json con
json_encode() + file_put_contents(), luego léelo y recupéralo con
json_decode(..., true). Muestra el nombre recuperado y el JSON en bruto.
Ver solución
$ficha = ["nombre" => "Raúl", "edad" => 34, "ciudad" => "Madrid"];
file_put_contents("ficha.json", json_encode($ficha));
$datos = json_decode(file_get_contents("ficha.json"), true);
echo "Nombre: " . $datos["nombre"] . "\n";
echo "JSON: " . file_get_contents("ficha.json") . "\n";
10 Leer línea a línea
Crea un archivo frutas.txt a mano (o con PHP) con 3 frutas, una por línea. Luego con
file() léelo en un array y recórrelo con foreach mostrando cada fruta con su
número de línea (1-based).
Ver solución
// creamos el archivo
file_put_contents("frutas.txt", "manzana\npera\nuva\n");
$lineas = file("frutas.txt");
foreach ($lineas as $indice => $fruta) {
echo ($indice + 1) . ": " . trim($fruta) . "\n";
}
Sección C · Sesiones, cookies y login
11 Sesión con tu nombre
Crea sesion.php que llame a session_start() al principio, guarde en
$_SESSION["nombre"] tu nombre y lo muestre. Crea leer.php (también con
session_start()) que muestre $_SESSION["nombre"]. Visita primero
sesion.php y luego leer.php: deberías ver tu nombre en ambos.
Ver solución
// sesion.php
session_start();
$_SESSION["nombre"] = "Raúl";
echo "Guardado: " . $_SESSION["nombre"] . "\n";
// leer.php
session_start();
echo "Hola, " . ($_SESSION["nombre"] ?? "visitante") . "\n";
12 Preferencia en cookie
Crea cookie.php que establezca con setcookie() una cookie idioma
con valor "es" que dure 30 días. En la misma página muestra la cookie si ya existe (usa
$_COOKIE["idioma"] ?? "sin preferencia"). Recarga varias veces y comenta cuándo aparece.
Ver solución
$idioma = $_COOKIE["idioma"] ?? "";
if ($idioma === "") {
setcookie("idioma", "es", time() + 3600 * 24 * 30);
echo "Cookie creada. Recarga para verla.\n";
} else {
echo "Tu idioma: $idioma\n";
}
13 Login en memoria
Crea login.php (con session_start()) con un array de usuarios, un formulario
muy simple y la lógica del patrón visto en la lección 4.4. Si las credenciales coinciden, guarda
$_SESSION["logueado"] = true y muestra «Bienvenido». Si no, muestra un error.
Ver solución
session_start();
$usuarios = ["raul" => "secreto123", "alba" => "otrapass"];
$mensaje = "";
$nombre = $_POST["usuario"] ?? "";
$clave = $_POST["clave"] ?? "";
if ($nombre !== "") {
if (isset($usuarios[$nombre]) && $usuarios[$nombre] === $clave) {
$_SESSION["logueado"] = true;
$_SESSION["usuario"] = $nombre;
$mensaje = "Bienvenido, $nombre";
} else {
$mensaje = "Credenciales incorrectas.";
}
}
?>
<form method="post">
<input name="usuario" placeholder="usuario">
<input name="clave" type="password" placeholder="clave">
<button>Entrar</button>
</form>
<p><?= $mensaje ?></p>
14 Página protegida
Con sesion.php del ejercicio 12 que marca protección, crea privada.php que
compruebe $_SESSION["logueado"]; si no está, muestre «Acceso denegado», y si está muestre
«Área privada». Prueba con y sin haber «logueado».
Ver solución
session_start();
if (empty($_SESSION["logueado"])) {
echo "Acceso denegado.\n";
} else {
echo "Área privada. Bienvenido, " . $_SESSION["usuario"] . "\n";
}
15 Cerrar sesión
Crea logout.php que vacíe $_SESSION, borre la cookie de sesión y destruya
la sesión, mostrando «Sesión cerrada». Enlázalo desde la página privada del ejercicio anterior.
Ver solución
session_start();
$_SESSION = [];
$params = session_get_cookie_params();
setcookie(session_name(), "", time() - 42000, $params["path"]);
session_destroy();
echo "Sesión cerrada.\n";
Sección D · Plantillas y modularización
16 Header y footer reutilizables
Crea header.php y footer.php (como en la lección 5) y dos páginas
inicio.php y acerca.php que los incluyan con require/
include, diferenciándose solo en el contenido central. Comprueba que el menú aparece en
ambas sin repetirlo.
Ver solución
// header.php
<!DOCTYPE html>
<html lang="es">
<head><meta charset="UTF-8"><title><?= $titulo ?></title></head>
<body><nav><a href="inicio.php">Inicio</a> <a href="acerca.php">Acerca</a></nav>
// footer.php
<footer>© <?= date("Y") ?> TécnicoWeb</footer>
</body></html>
// inicio.php
<?php $titulo = "Inicio"; require "header.php"; ?>
<h1>Bienvenido a mi web</h1>
<?php include "footer.php"; ?>
17 include vs require
Crea un script que intente include "no-existe.php" y muestre «Sigo vivo» después, y otro
que haga require "no-existe.php" y muestre «No llego aquí». Compara los errores y
explica en un comentario cuándo usarías cada uno.
Ver solución
// con_include.php → muestra aviso y continúa
include "no-existe.php";
echo "Sigo vivo tras include.\n";
// con_require.php → error fatal y se detiene
require "no-existe.php";
echo "No llego aquí.\n"; // no se mostrará
18 🏆 Proyecto integrador: «carrito.php»
Monta un mini carrito de compra con sesión que acumule productos entre recargas:
- Declara un
$productosmultidimensional (nombre + precio) con 3+ productos. - Llama a
session_start()al principio. - Usa al menos una función de arrays:
count(),in_array(),array_sum(),array_push()… - Guarda y acumula el carrito en
$_SESSION["carrito"](un array asociativo con cantidades). - Recorre el carrito con
foreachmostrando cada producto y su total. - Calcula el total general acumulando con un bucle o
array_sum(). - Lee/escribe al menos una vez un fichero (p. ej. un log de ventas con
file_put_contents(..., FILE_APPEND)).
Este ejercicio es el reto del laboratorio del examen: la validación automática comprobará estos
criterios sobre el código dentro de las etiquetas <?php ... ?>.
📝 Examen del Bloque 2
Dos partes: un test teórico autoevaluable (mínimo 70 %) y un reto práctico de autocorrección con checklist.
Parte B · Reto práctico final
Construye el ejercicio 18 («carrito.php») sin mirar soluciones y valida tú mismo/a estos criterios
sobre el contenido de tus etiquetas <?php ... ?>. Mínimo para aprobar:
6 de 7 casillas.
Cumplidos: 0 / 7