Cuando trabajamos con cadenas con acentos, eñes y otros símbolos no compatibles en ciertos entornos, en ocasiones, hemos de sustituirlas por sus equivalentes para poder ofrecer el resultado deseado (por ejemplo, sustituir á por a).
Cuando trabajamos con cadenas en UTF-8 (si queréis más información sobre juegos de caracteres os recomiendo esta entrada: Entender los juegos de caracteres y “collation” I y II que escribí hace tiempo) no podemos usar la función típica para hacer subcadenas de PHP: substr, ya que en el caso de que el corte caiga justo en un carácter no ASCII, habrá un problema en la representación y aparecerá un carácter extraño.
El origen de este problema es que se trata de un juego de caracteres en el que cada carácter no tiene por qué tener un sólo byte de tamaño, si no que puede llegar a ocupar 4 bytes como máximo, es decir, también puede ocupar 2 o 3 bytes.
La importancia de los juegos de caracteres y los collation es algo básico para tratar con cadenas de textos y más aún si hablamos un lenguaje que no “entra” dentro del ASCII como es nuestro caso. En Linux Hispano ya hablamos en su momento de este tema:
Hoy volvemos a hablar, pero en un contexto más práctico. Cuando trabajamos con PHP, tenemos instrucciones que nos permiten codificar o decodificar texto en diferentes formatos, por ejemplo: utf8_decode o utf8_encode. Sin embargo, no existe un método que nos confirme de manera directa si el texto está en cierta codificación o no.
En PHP y Otras Yerbas, nos muestran una serie de funciones de gran interés para conseguir justo esto, detectar la codificación que usa un texto:
<?php define("UTF_8", 1); define("ASCII", 2); define("ISO_8859_1", 3); function codificacion($texto) { $c = 0; $ascii = true; for ($i = 0;$i<strlen($texto);$i++) { $byte = ord($texto[$i]); if ($c>0) { if (($byte>>6) != 0x2) { return ISO_8859_1; } else { $c--; } } elseif ($byte&0x80) { $ascii = false; if (($byte>>5) == 0x6) { $c = 1; } elseif (($byte>>4) == 0xE) { $c = 2; } elseif (($byte>>3) == 0x1E) { $c = 3; } else { return ISO_8859_1; } } } return ($ascii) ? ASCII : UTF_8; } ?>
Puede que en más de una ocasión os hayáis encontrado con problemas de juegos de caracteres utilizando MySQL. Si el problema es que tenéis una arquitectura en un juego de caracteres determinados, con un collation determinado, y necesitáis hacer una modificación de ambos en caliente sin tener que ir tabla a tabla, necesitaréis de este script que os dejo a continuación.