¿Por qué tus tildes y eñes se convierten en "ñ" y cómo solucionarlo para siempre
\n\n¿Alguna vez has abierto tu sitio web en PHP y en lugar de ver "¡Hola, mundo!" has visto algo como ¡Hola, mundo!? Si es así, ¡enhorabuena! Te has topado con el clásico problema del UTF-8 end-to-end. Es esa situación en la que la codificación se rompe en algún punto entre la base de datos y el navegador, y todos tienen la culpa, pero nadie quiere asumirla.
En Stack Overflow, esta pregunta acumula miles de visitas y cientos de respuestas. Y no es para menos. Incluso desarrolladores experimentados se confunden a veces con la configuración de codificación. En este tutorial, te daremos una receta paso a paso para que PHP, MySQL y el navegador trabajen juntos y UTF-8 funcione en todas partes y siempre. Sin magia: solo la configuración correcta.
\n\nPaso 1. Base de datos: el cimiento de tu codificación
\n\nTodo empieza en la base de datos. Si en MySQL almacenas datos en latin1 o cp1251 e intentas mostrarlos en UTF-8, obtendrás caracteres extraños. Pero incluso si la base está en UTF-8, hay un detalle: la codificación antigua utf8 de MySQL no soporta emojis ni algunos caracteres especiales. La solución es utf8mb4.
1.1. Crear tablas con la codificación correcta
\n\nAl crear una nueva tabla, especifica siempre:
\n\nCREATE TABLE articulos (\n id INT AUTO_INCREMENT PRIMARY KEY,\n titulo VARCHAR(255) NOT NULL,\n contenido TEXT NOT NULL\n) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nOtra opción es definir la codificación por defecto para toda la base de datos:
\n\nALTER DATABASE nombre_de_tu_base CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nImportante: utf8mb4_unicode_ci es el collation (regla de comparación). Maneja correctamente todos los caracteres Unicode. Si no necesitas ordenación multilingüe, también puedes usar utf8mb4_general_ci.
1.2. Convertir tablas existentes
\n\nSi ya tienes datos en otra codificación, conviértelos primero:
\n\nALTER TABLE articulos CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nPero ten cuidado: si la tabla ya contenía datos en latin1, podrían convertirse en doble codificación (por ejemplo, ¡). En ese caso, primero debes pasar las columnas a binary y luego a utf8mb4. Es otra historia, pero para simplificar, asumamos que empiezas desde cero.
Paso 2. Conexión PHP con la base: configurar PDO
\n\nEn PHP moderno usas PDO (o mysqli). Aquí hay un punto crítico: después de conectarte a la base, debes indicar explícitamente la codificación. De lo contrario, PHP se comunicará con MySQL en la codificación por defecto (generalmente latin1).
\n\n2.1. Cadena de conexión PDO correcta
\n\n$host = 'localhost';\n$dbname = 'tu_base';\n$username = 'root';\n$password = '';\n\n$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";\n\n$options = [\n PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n PDO::ATTR_EMULATE_PREPARES => false,\n];\n\ntry {\n $pdo = new PDO($dsn, $username, $password, $options);\n} catch (PDOException $e) {\n echo "Conexión fallida: " . $e->getMessage();\n}\n\nFíjate en charset=utf8mb4 en el DSN. Esto obliga a PHP y MySQL a acordar la codificación a nivel de conexión.
2.2. Método alternativo (si el DSN no funciona)
\n\nA veces, versiones antiguas de PHP o servidores no leen el charset del DSN. En ese caso, añade después de la conexión:
\n\n$pdo->exec("SET NAMES 'utf8mb4'");\n\nPero el primer método es preferible: es más limpio y moderno.
\n\nPaso 3. Cabeceras HTTP y HTML: decirle la verdad al navegador
\n\nIncluso si la base y PHP funcionan en UTF-8, el navegador podría decidir que