📖 Introducción
En un mundo dominado por frameworks y librerías, dominar las tecnologías fundamentales del desarrollo web es más valioso que nunca.
¿Por qué aprender Vanilla?
Mayor control: Entiendes exactamente qué sucede.
Mejor rendimiento: Sin overhead de frameworks.
Depuración fácil: Menos abstracciones.
Fundamento sólido: Los fundamentos permanecen.
🏗️ HTML5
Estructura Básica
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mi Página Web</title> <link rel="stylesheet" href="estilos.css"> </head> <body> <!-- Contenido visible --> <script src="script.js"></script> </body> </html>
Formularios
<form action="procesar.php" method="POST"> <div> <label for="nombre">Nombre:</label> <input type="text" id="nombre" name="nombre" required> </div> <div> <label for="email">Email:</label> <input type="email" id="email" name="email" required> </div> <div> <label for="mensaje">Mensaje:</label> <textarea id="mensaje" name="mensaje" rows="4"></textarea> </div> <button type="submit">Enviar</button> </form>
🎨 CSS3
Selectores
/* Selector de elemento */ p { color: #333; font-size: 16px; } /* Selector de clase */ .destacado { font-weight: bold; color: #e74c3c; } /* Selector de ID */ #header { background: #2c3e50; padding: 20px; } /* Selector descendente */ article p { line-height: 1.8; } /* Múltiples selectores */ h1, h2, h3 { font-family: Arial, sans-serif; }
Box Model
.caja { /* Contenido */ width: 300px; height: 200px; /* Espacio interno */ padding: 20px; /* Borde */ border: 2px solid #333; /* Espacio externo */ margin: 10px; } /* box-sizing: border-box incluye padding y border */ * { box-sizing: border-box; }
Flexbox
/* Contenedor flex */ .contenedor { display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap; } /* Item flex */ .item { flex: 1; flex-shrink: 0; flex-basis: 200px; } /* Responsive */ @media (min-width: 768px) { .contenedor { flex-direction: column; } }
Variables CSS
/* Definir variables */ :root { --color-primario: #3498db; --color-secundario: #2ecc71; --espaciado: 16px; --sombra: 0 4px 6px rgba(0,0,0,0.1); } .boton { background: var(--color-primario); padding: var(--espaciado); box-shadow: var(--sombra); }
⚡ JavaScript
Fundamentos
// Variables let nombre = "Juan"; const PI = 3.1416; var edad = 25; // Tipos de datos let texto = "Hola"; let numero = 42; let boolean = true; let array = [1, 2, 3]; let objeto = {clave: "valor"}; // Condicionales if (edad >= 18) { console.log("Mayor de edad"); } else if (edad >= 13) { console.log("Adolescente"); } else { console.log("Niño"); } // Operador ternario let tipo = edad >= 18 ? "adulto" : "menor";
Funciones
// Función tradicional function saludar(nombre) { return "Hola, " + nombre; } // Función flecha (arrow) const saludarFlecha = (nombre) => { return `Hola, ${nombre}`; }; // Parámetros por defecto function crearUsuario(nombre, rol = "usuario") { return { nombre, rol }; } // Async/await async function fetchData() { const res = await fetch("/api/data"); return await res.json(); }
Arrays y Métodos
const numeros = [1, 2, 3, 4, 5]; // map - transformar const dobles = numeros.map(n => n * 2); // [2,4,6,8,10] // filter - filtrar const pares = numeros.filter(n => n % 2 === 0); // [2,4] // find - encontrar primero const encontrado = numeros.find(n => n > 3); // 4 // reduce - acumular const suma = numeros.reduce((acc, n) => acc + n, 0); // 15 // some y every const hayPar = numeros.some(n => n % 2 === 0); // true const todosPares = numeros.every(n => n % 2 === 0); // false
Manipulación del DOM
// Seleccionar elementos const elem = document.getElementById("miId"); const elems = document.querySelectorAll(".clase"); // Modificar contenido elem.textContent = "Nuevo texto"; elem.innerHTML = "<strong>HTML</strong>"; // Modificar clases elem.classList.add("activo"); elem.classList.remove("oculto"); elem.classList.toggle("visible"); // Crear elemento const div = document.createElement("div"); div.textContent = "Nuevo"; elem.appendChild(div);
Fetch API
// GET - obtener datos fetch("https://api.ejemplo.com/users") .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error(err)); // POST - enviar datos fetch("https://api.ejemplo.com/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ nombre: "Juan", email: "juan@ejemplo.com" }) }) .then(res => res.json()) .then(data => console.log(data));
🐘 PHP
Fundamentos
<?php // Variables $nombre = "Juan"; $edad = 25; $activo = true; // Arrays $frutas = ["manzana", "pera", "uva"]; $usuario = [ "nombre" => "Juan", "email" => "juan@ejemplo.com" ]; // Condicionales if ($edad >= 18) { echo "Mayor de edad"; } else { echo "Menor de edad"; } // Null coalescing (PHP 7+) $valor = $_GET["id"] ?? "default"; ?>
Funciones
<?php // Función básica function saludar($nombre) { return "Hola, $nombre"; } // Tipado y valor por defecto function sumar(int $a, int $b = 0): int { return $a + $b; } // Arrow function (PHP 7.4+) $doble = fn($x) => $x * 2; // Argumentos variables function sumarTodo(...$numeros) { return array_sum($numeros); } ?>
Clases y Objetos
<?php class Usuario { private $nombre; private $email; public function __construct($nombre, $email) { $this->nombre = $nombre; $this->email = $email; } public function getNombre(): string { return $this->nombre; } public function setNombre($nombre): void { $this->nombre = $nombre; } } // Uso $usuario = new Usuario("Juan", "juan@email.com"); echo $usuario->getNombre(); ?>
MySQL con PDO
<?php // Conexión PDO try { $pdo = new PDO( "mysql:host=localhost;dbname=mi_db;charset=utf8mb4", "usuario", "contraseña", [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ] ); } catch (PDOException $e) { die("Error: " . $e->getMessage()); } // Prepared statement - SELECT $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE id = ?"); $stmt->execute([$id]); $usuario = $stmt->fetch(); // Prepared statement - INSERT $stmt = $pdo->prepare( "INSERT INTO usuarios (nombre, email) VALUES (?, ?)" ); $stmt->execute([$nombre, $email]); $nuevoId = $pdo->lastInsertId(); ?>
🗄️ MySQL
Crear Tablas
CREATE DATABASE mi_aplicacion CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE mi_aplicacion; CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, rol ENUM('usuario','admin') DEFAULT 'usuario', creado_en TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; CREATE TABLE posts ( id INT AUTO_INCREMENT PRIMARY KEY, usuario_id INT NOT NULL, titulo VARCHAR(200) NOT NULL, contenido TEXT, FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ); CREATE INDEX idx_email ON usuarios(email);
Consultas Básicas (CRUD)
-- INSERT - Crear INSERT INTO usuarios (nombre, email, password) VALUES ('Juan', 'juan@email.com', 'hash_password'); -- SELECT - Leer SELECT * FROM usuarios WHERE activo = TRUE; SELECT * FROM usuarios WHERE email LIKE '%@gmail.com'; SELECT * FROM usuarios ORDER BY creado_en DESC LIMIT 10; -- UPDATE - Actualizar UPDATE usuarios SET nombre = 'Juan Carlos' WHERE id = 1; -- DELETE - Eliminar DELETE FROM usuarios WHERE id = 5;
JOINs
SELECT p.titulo, p.creado_en, u.nombre AS "autor" FROM posts AS p INNER JOIN usuarios AS u ON p.usuario_id = u.id; SELECT u.nombre, COUNT(p.id) AS "total_posts" FROM usuarios u LEFT JOIN posts p ON u.id = p.usuario_id GROUP BY u.id, u.nombre HAVING COUNT(p.id) > 0;
🔗 Conexión Frontend-Backend
Flujo de datos
Flujo típico:
1. Usuario interactúa con HTML/CSS
2. JavaScript captura el evento
3. JavaScript envía HTTP al servidor
4. PHP procesa y consulta MySQL
5. PHP responde con JSON
6. JavaScript actualiza el DOM
Ejemplo: Formulario de Contacto
const form = document.getElementById("contactForm"); form.addEventListener("submit", async (e) => { e.preventDefault(); // Obtener datos del formulario const formData = new FormData(form); const data = Object.fromEntries(formData.entries()); try { const response = await fetch("procesar.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); const result = await response.json(); // Mostrar resultado document.getElementById("mensaje").textContent = result.mensaje; if (result.exito) { form.reset(); } } catch (error) { console.error(error); } });
<?php header("Content-Type: application/json; charset=UTF-8"); // Solo aceptar POST if ($_SERVER["REQUEST_METHOD"] !== "POST") { http_response_code(405); echo json_encode(["exito" => false, "mensaje" => "Método no permitido"]); exit; } // Obtener datos JSON $json = file_get_contents("php://input"); $data = json_decode($json, true); // Validar if (!isset($data["nombre"]) || !isset($data["email"])) { echo json_encode(["exito" => false, "mensaje" => "Datos incompletos"]); exit; } // Guardar en BD... echo json_encode(["exito" => true, "mensaje" => "Mensaje enviado"]); ?>
🛡️ Seguridad Web
SQL Injection
❌ Código vulnerable - NUNCA hacer esto:
// ¡PELIGRO! Concatenación directa $query = "SELECT * FROM users WHERE email = '" . $_POST["email"] . "'"; // Un atacante puede injectar: ' OR '1'='1 // Resultado: SELECT * FROM users WHERE email = '' OR '1'='1'
✅ Solución segura - Prepared Statements:
// Prepared statement seguro $stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?"); $stmt->execute([$_POST["email"]]); $user = $stmt->fetch();
XSS (Cross-Site Scripting)
// ✅ Usar textContent en vez de innerHTML elem.textContent = userInput; // ✅ Función para escapar HTML const escapeHTML = (str) => { return str .replace(/&/g, "&") .replace(/, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); };
Passwords Seguros
<?php // Hash password con bcrypt $hash = password_hash($password, PASSWORD_DEFAULT); // Verificar password if (password_verify($password, $hash)) { // Password correcto } // Verificar y rehash si necesario if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { $nuevoHash = password_hash($password, PASSWORD_DEFAULT); // Actualizar en BD } ?>
Checklist de Seguridad:
- Usar HTTPS en producción
- Prepared statements para TODAS las queries SQL
- Escapar outputs antes de mostrarlos
- Hash bcrypt para passwords
- Validar y sanitizar TODOS los inputs