Pregunta UTF-8 todo el camino


Estoy configurando un nuevo servidor y quiero soportar UTF-8 completamente en mi aplicación web. Lo he intentado en el pasado en servidores existentes y siempre parece que tengo que recurrir a ISO-8859-1.

¿Dónde exactamente necesito configurar la codificación / conjuntos de caracteres? Soy consciente de que necesito configurar Apache, MySQL y PHP para hacer esto. ¿Existe alguna lista de verificación estándar que pueda seguir, o tal vez solucionar dónde se producen los desajustes?

Esto es para un nuevo servidor Linux, ejecutando MySQL 5, PHP 5 y Apache 2.


986
2017-11-10 21:04


origen


Respuestas:


Almacenamiento de datos:

  • Especifica el utf8mb4 conjunto de caracteres en todas las tablas y columnas de texto en su base de datos. Esto hace que MySQL físicamente almacene y recupere valores codificados de forma nativa en UTF-8. Tenga en cuenta que MySQL usará implícitamente utf8mb4 codificación si utf8mb4_* se especifica la intercalación (sin ningún conjunto de caracteres explícitos).

  • En versiones anteriores de MySQL (<5.5.3), desafortunadamente se verá forzado a usar simplemente utf8, que solo admite un subconjunto de caracteres Unicode. Ojalá estuviera bromeando.

Acceso a los datos:

  • En el código de su aplicación (por ejemplo, PHP), en cualquier método de acceso DB que use, tendrá que configurar el juego de caracteres de conexión para utf8mb4. De esta forma, MySQL no realiza conversiones desde su UTF-8 original cuando transfiere datos a su aplicación y viceversa.

  • Algunos controladores proporcionan su propio mecanismo para configurar el juego de caracteres de la conexión, que actualiza su propio estado interno e informa a MySQL de la codificación que se utilizará en la conexión; este suele ser el enfoque preferido. En PHP:

    • Si estás usando el DOP capa de abstracción con PHP ≥ 5.3.6, puede especificar charset en el DSN:

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Si estás usando mysqli, Puedes llamar set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Si estás atrapado con llanura mysql pero sucede que ejecuta PHP ≥ 5.2.3, puede llamar mysql_set_charset.

  • Si el controlador no proporciona su propio mecanismo para establecer el conjunto de caracteres de la conexión, es posible que deba emitir una consulta para decirle a MySQL cómo su aplicación espera que se codifiquen los datos en la conexión: SET NAMES 'utf8mb4'.

  • La misma consideración con respecto a utf8mb4/utf8 aplica como arriba.

Salida:

  • Si su aplicación transmite texto a otros sistemas, también deberán estar informados de la codificación de caracteres. Con las aplicaciones web, el navegador debe ser informado de la codificación en la que se envían los datos (a través de encabezados de respuesta HTTP o Metadatos HTML)

  • En PHP, puedes usar el default_charset la opción php.ini, o emite manualmente Content-Type Encabezado MIME usted mismo, que es solo más trabajo, pero tiene el mismo efecto.

Entrada:

  • Lamentablemente, debe verificar cada cadena recibida como UTF-8 válida antes de intentar almacenarla o usarla en cualquier lugar. PHP mb_check_encoding() hace el truco, pero tienes que usarlo religiosamente. Realmente no hay forma de evitar esto, ya que los clientes maliciosos pueden enviar datos en cualquier codificación que deseen, y no he encontrado ningún truco para que PHP lo haga de manera confiable.

  • De mi lectura de la corriente Especificación de HTML, las siguientes sub-balas ya no son necesarias ni válidas para el HTML moderno. Según entiendo, los navegadores trabajarán con y enviarán datos en el juego de caracteres especificado para el documento. Sin embargo, si se dirige a versiones anteriores de HTML (XHTML, HTML4, etc.), estos puntos pueden ser útiles:

    • Solo para HTML antes de HTML5: desea que todos los datos que le envíen los navegadores estén en UTF-8. Desafortunadamente, si se pasa por la única forma confiable de hacerlo, agregue el accept-charset atribuir a todos sus <form> etiquetas: <form ... accept-charset="UTF-8">.
    • Solo para HTML antes de HTML5: tenga en cuenta que la especificación W3C HTML dice que los clientes "deben" establecer de forma predeterminada el envío de formularios al servidor en cualquier juego de caracteres que sirva el servidor, pero esto es aparentemente solo una recomendación, de ahí la necesidad de ser explícito en cada uno <form> etiqueta.

Otras consideraciones del código:

  • Obviamente, todos los archivos que va a servir (PHP, HTML, JavaScript, etc.) deben estar codificados en UTF-8 válido.

  • Debe asegurarse de que cada vez que procese una cadena UTF-8, lo haga de manera segura. Esta es, desafortunadamente, la parte difícil. Es probable que desee hacer un uso extenso de PHP mbstring extensión.

  • Las operaciones de cadenas incorporadas de PHP son no por defecto UTF-8 seguro.  Hay algunas cosas que puede hacer con seguridad con operaciones normales de cadenas PHP (como la concatenación), pero para la mayoría de las cosas debe usar el equivalente mbstring función.

  • Para saber lo que estás haciendo (léase: no estropearlo), realmente necesitas conocer UTF-8 y cómo funciona en el nivel más bajo posible. Echa un vistazo a cualquiera de los enlaces de utf8.com para algunos buenos recursos para aprender todo lo que necesita saber.


861
2017-11-10 21:43



Me gustaría agregar una cosa a excelente respuesta de chazomaticus:

No olvide tampoco la etiqueta META (como esta, o la versión HTML4 o XHTML de la misma)

<meta charset="utf-8">

Eso parece trivial, pero IE7 me ha dado problemas con eso antes.

Estaba haciendo todo bien; la base de datos, la conexión a la base de datos y el encabezado HTTP Content-Type estaban todos configurados en UTF-8, y funcionaba bien en todos los demás navegadores, pero Internet Explorer todavía insistía en usar la codificación "Western European".

Resultó que a la página le faltaba la etiqueta META. Agregar eso resolvió el problema.

Editar:

El W3C en realidad tiene un tamaño bastante grande sección dedicada a I18N. Tienen una serie de artículos relacionados con este tema, que describen el lado HTTP, (X) HTML y CSS de las cosas:

Recomiendan usar el encabezado HTTP y la metaetiqueta HTML (o la declaración XML en caso de que XHTML sirva como XML).


134
2017-11-12 19:27



Además de establecer default_charset en php.ini, puede enviar el juego de caracteres correcto usando header() desde dentro de su código, antes de cualquier salida:

header('Content-Type: text/html; charset=utf-8');

Trabajar con Unicode en PHP es fácil siempre que te des cuenta de que la mayoría de las funciones de cadena no funcionan con Unicode, y algunas pueden manipular cadenas completamente. PHP considera que los "caracteres" son de 1 byte de longitud. A veces esto está bien (por ejemplo, explode() solo busca una secuencia de bytes y la usa como separador, por lo que no importa qué caracteres reales busque. Pero otras veces, cuando la función está realmente diseñada para funcionar en caracteres, PHP no tiene idea de que tu texto tenga caracteres de varios bytes que se encuentran con Unicode.

Una buena biblioteca para registrarse es phputf8. Esto reescribe todas las funciones "incorrectas" para que pueda trabajar con seguridad en cadenas UTF8. Hay extensiones como la extensión mbstring que intentan hacer esto por usted, también, pero prefiero usar la biblioteca porque es más portátil (pero escribo productos de mercado masivo, así que eso es importante para mí). Pero phputf8 puede usar mbstring detrás de escena, de todos modos, para aumentar el rendimiento.


55
2017-11-10 21:30



Viejo tema, lo sé. Encontró un problema con alguien que usa PDO y la respuesta fue usar esto para la cadena de conexión PDO:

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

El sitio del que tomé esto está inactivo, pude obtenerlo usando Google Cache por suerte.


26
2017-09-11 15:40



En mi caso, estaba usando mb_split, que usa expresiones regulares Por lo tanto, también tuve que asegurarme manualmente de que la codificación regex fuera utf-8 haciendo mb_regex_encoding('UTF-8');

Como nota al margen, también descubrí corriendo mb_internal_encoding() que la codificación interna no era utf-8, y lo cambié ejecutando mb_internal_encoding("UTF-8");.


20
2018-02-23 22:20



En primer lugar, si estás en <5.3PHP, entonces no. Tienes un montón de problemas que abordar.

Me sorprende que ninguno haya mencionado el intl biblioteca, la que tiene un buen soporte para Unicode, grafemas, operaciones de cuerda , localización y muchos más, ver abajo.

Citaré información sobre el soporte Unicode en PHP por Elizabeth Smith  diapositivas a PHPBenelux'14

INTL

Bueno:

  • Contenedor alrededor de la biblioteca de ICU
  • Configuración regional estandarizada, configuración regional por script
  • Formato numérico
  • Formato de moneda
  • Formato de mensaje (reemplaza gettext)
  • Calendarios, fechas, zona horaria y hora
  • Transcriptor
  • Spoofchecker
  • Paquetes de recursos
  • Convertidores
  • Soporte de IDN
  • Grafemes
  • Colación
  • Iteradores

Malo:

  • No es compatible con zend_multibite
  • No es compatible con la conversión de salida de entrada HTTP
  • No admite la sobrecarga de funciones

mb_string

  • Habilita el soporte de zend_multibyte
  • Admite la codificación de entrada / salida HTTP transparente
  • Proporciona algunos envoltorios para la funcionalidad, como strtoupper

ICONV

  • Principal para la conversión del juego de caracteres
  • Controlador de búfer de salida
  • funcionalidad de codificación de mimo
  • conversión
  • algunos ayudantes de cuerda (len, substr, strpos, strrpos)
  • Filtro de corriente stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

BASES DE DATOS

  • mysql: conjunto de caracteres y clasificación en las tablas y en la conexión (no la intercalación). Además, no use mysql - msqli o PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): asegúrese de que fue compilado con soporte unicode e intl

Algunas otras Gotchas

  • No puede usar nombres de archivos unicode con PHP y Windows a menos que use una extensión de tercera parte.
  • Envíe todo en ASCII si está utilizando exec, proc_open y otras llamadas de línea de comando
  • El texto simple no es texto simple, los archivos tienen codificaciones
  • Puede convertir archivos sobre la marcha con el filtro iconv

Actualizaré esta respuesta en caso de que las cosas cambien las características añadidas, etc.


19
2018-01-27 09:16



Recientemente descubrí que usando strtolower() puede causar problemas donde los datos se truncan después de un carácter especial.

La solución fue usar

mb_strtolower($string, 'UTF-8');

mb_ usa MultiByte. Admite más personajes, pero en general es un poco más lento.


13
2018-01-13 09:37



Lo único que agregaría a estas asombrosas respuestas es enfatizar en guardar sus archivos en la codificación utf8. He notado que los navegadores aceptan esta propiedad sobre la configuración de utf8 como codificación de código. Cualquier editor de texto decente le mostrará esto, por ejemplo Notepad ++ tiene una opción de menú para codificación de archivos, le muestra la codificación actual y le permite cambiarla. Para todos mis archivos php utilizo utf8 sin BOM.

Hace algún tiempo, alguien me pidió que añadiera soporte para utf8 para una aplicación php / mysql diseñada por otra persona, noté que todos los archivos estaban codificados en ANSI, así que tuve que usar ICONV para convertir todos los archivos, cambiar las tablas de la base de datos para usar el utf8 charset y utf8_general_ci intercalar, agregue 'SET NAMES utf8' a la capa de abstracción de la base de datos después de la conexión (si usa 5.3.6 o anterior, de lo contrario, debe usar charset = utf8 en la cadena de conexión) y cambie las funciones de cadena para usar php multibyte funciones de cadena equivalentes.


11
2017-09-10 03:39