Question UTF-8 tout au long de


Je suis en train de mettre en place un nouveau serveur, et je veux soutenir complètement UTF-8 dans mon application web. J'ai essayé dans le passé sur des serveurs existants et je devais toujours revenir à ISO-8859-1.

Où dois-je exactement définir l'encodage / les jeux de caractères? Je suis conscient que j'ai besoin de configurer Apache, MySQL et PHP pour cela - y a-t-il une liste de contrôle standard que je peux suivre, ou peut-être dépanner où les discordances se produisent?

C'est pour un nouveau serveur Linux, exécutant MySQL 5, PHP 5 et Apache 2.


986
2017-11-10 21:04


origine


Réponses:


Stockage de données:

  • Spécifie le utf8mb4 jeu de caractères sur toutes les tables et colonnes de texte de votre base de données. Ceci fait que MySQL stocke et récupère physiquement les valeurs codées nativement en UTF-8. Notez que MySQL utilisera implicitement utf8mb4 codage si un utf8mb4_* l'assemblage est spécifié (sans jeu de caractères explicite).

  • Dans les anciennes versions de MySQL (<5.5.3), vous serez malheureusement obligé d'utiliser simplement utf8, qui ne supporte qu'un sous-ensemble de caractères Unicode. Je voudrais que je plaisante.

Accès aux données:

  • Dans votre code d'application (par exemple PHP), quelle que soit la méthode d'accès à la base de données que vous utilisez, vous devez définir le jeu de caractères de connexion sur utf8mb4. De cette façon, MySQL ne fait aucune conversion à partir de son UTF-8 natif lorsqu'il transmet les données à votre application et vice versa.

  • Certains pilotes fournissent leur propre mécanisme de configuration du jeu de caractères de connexion, qui met à jour son propre état interne et informe MySQL de l'encodage à utiliser sur la connexion, ce qui est généralement l'approche préférée. En PHP:

    • Si vous utilisez le AOP couche d'abstraction avec PHP ≥ 5.3.6, vous pouvez spécifier charset dans le DSN:

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Si vous utilisez mysqli, tu peux appeler set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Si vous êtes coincé avec plaine mysql mais arrive à courir PHP ≥ 5.2.3, vous pouvez appeler mysql_set_charset.

  • Si le pilote ne fournit pas son propre mécanisme de définition du jeu de caractères de connexion, vous devrez peut-être émettre une requête pour indiquer à MySQL comment votre application s'attend à ce que les données de la connexion soient codées: SET NAMES 'utf8mb4'.

  • La même considération concernant utf8mb4/utf8 s'applique comme ci-dessus.

Sortie:

  • Si votre application transmet du texte à d'autres systèmes, ils devront également être informés de l'encodage des caractères. Avec les applications Web, le navigateur doit être informé du codage dans lequel les données sont envoyées (via les en-têtes de réponse HTTP ou Métadonnées HTML).

  • En PHP, vous pouvez utiliser le default_charset option php.ini ou lancez manuellement le Content-Type En-tête MIME vous-même, qui est juste plus de travail, mais a le même effet.

Contribution:

  • Malheureusement, vous devriez vérifier chaque chaîne reçue comme UTF-8 valide avant d'essayer de la stocker ou de l'utiliser n'importe où. PHP mb_check_encoding() fait le tour, mais vous devez l'utiliser religieusement. Il n'y a vraiment aucun moyen de contourner cela, car les clients malveillants peuvent soumettre des données quel que soit l'encodage qu'ils veulent, et je n'ai pas trouvé de truc pour que PHP le fasse pour vous de manière fiable.

  • De ma lecture du courant Spécification HTML, les sous-puces suivantes ne sont pas nécessaires ou même plus valides pour le HTML moderne. Ma compréhension est que les navigateurs vont travailler avec et soumettre des données dans le jeu de caractères spécifié pour le document. Toutefois, si vous ciblez des versions plus anciennes de HTML (XHTML, HTML4, etc.), ces points peuvent toujours être utiles:

    • Pour HTML avant HTML5 uniquement: vous voulez que toutes les données qui vous sont envoyées par les navigateurs soient en UTF-8. Malheureusement, si vous passez par le seul moyen de le faire de manière fiable est d'ajouter le accept-charset attribuer à tous vos <form> Mots clés: <form ... accept-charset="UTF-8">.
    • Pour HTML avant HTML5 uniquement: notez que la spécification HTML du W3C indique que les clients "devraient" par défaut renvoyer des formulaires au serveur quel que soit le jeu de caractères utilisé par le serveur, mais il ne s'agit apparemment que d'une recommandation, d'où le besoin d'être explicite. <form> marque.

Autres considérations de code:

  • De toute évidence, tous les fichiers que vous allez servir (PHP, HTML, JavaScript, etc.) doivent être encodés en UTF-8 valide.

  • Vous devez vous assurer qu'à chaque fois que vous traitez une chaîne UTF-8, vous le faites en toute sécurité. C'est malheureusement la partie difficile. Vous voudrez probablement faire un usage intensif de PHP mbstring extension.

  • Les opérations de chaînes intégrées de PHP sont ne pas par défaut UTF-8 coffre-fort.  Il y a certaines choses que vous pouvez faire en toute sécurité avec les opérations de chaînes PHP normales (comme la concaténation), mais pour la plupart des choses, vous devez utiliser l'équivalent mbstring fonction.

  • Pour savoir ce que vous faites (lire: ne pas le gâcher), vous avez vraiment besoin de connaître UTF-8 et comment cela fonctionne au niveau le plus bas possible. Découvrez l'un des liens de utf8.com pour de bonnes ressources pour apprendre tout ce que vous devez savoir.


861
2017-11-10 21:43



Je voudrais ajouter une chose à L'excellente réponse de Chazomaticus:

Ne pas oublier la balise META soit (comme ceci, ou la version HTML4 ou XHTML de celui-ci):

<meta charset="utf-8">

Cela semble trivial, mais IE7 m'a donné des problèmes avec cela avant.

Je faisais tout bien; la base de données, la connexion à la base de données et l'en-tête HTTP Content-Type étaient tous définis sur UTF-8 et fonctionnaient parfaitement dans tous les autres navigateurs, mais Internet Explorer insistait toujours sur l'utilisation de l'encodage «Western European».

Il s'est avéré que la balise META manquait à la page. Ajoutant cela a résolu le problème.

Modifier:

Le W3C a en fait un assez grand section dédiée à I18N. Ils ont un certain nombre d'articles liés à ce problème - décrivant le côté HTTP, (X) HTML et CSS des choses:

Ils recommandent d'utiliser à la fois l'en-tête HTTP et la balise méta HTML (ou déclaration XML dans le cas de XHTML servi en XML).


134
2017-11-12 19:27



En plus de définir default_charset dans php.ini, vous pouvez envoyer le jeu de caractères correct en utilisant header() à partir de votre code, avant toute sortie:

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

Travailler avec Unicode en PHP est facile tant que vous réalisez que la plupart des les fonctions de chaîne ne fonctionnent pas avec Unicode, et certaines peuvent complètement supprimer les chaînes. PHP considère que les "caractères" ont une longueur de 1 octet. Parfois c'est correct (par exemple, explode() recherche uniquement une séquence d'octets et l'utilise comme séparateur - peu importe donc les caractères réels que vous recherchez). Mais d'autres fois, lorsque la fonction est réellement conçue pour fonctionner sur personnages, PHP n'a aucune idée que votre texte a des caractères multi-octets qui sont trouvés avec Unicode.

Une bonne bibliothèque à vérifier est phputf8. Cela réécrit toutes les «mauvaises» fonctions afin que vous puissiez travailler en toute sécurité sur les chaînes UTF8. Il y a des extensions comme l'extension mbstring qui essaye de faire ça aussi pour vous, mais je préfère utiliser la librairie parce qu'elle est plus portable (mais j'écris des produits grand public, donc c'est important pour moi). Mais phputf8 peut utiliser mbstring en coulisse, de toute façon, pour augmenter les performances.


55
2017-11-10 21:30



Vieux sujet, je sais. Trouvé un problème avec quelqu'un utilisant PDO et la réponse était d'utiliser ceci pour la chaîne de connexion PDO:

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

Le site que j'ai pris est en panne, a été en mesure de l'obtenir en utilisant google cache heureusement.


26
2017-09-11 15:40



Dans mon cas, j'utilisais mb_split, qui utilise regex. Par conséquent, j'ai également dû manuellement vérifier que l'encodage regex était utf-8 en faisant mb_regex_encoding('UTF-8');

Comme note de côté, j'ai aussi découvert en courant mb_internal_encoding() que le codage interne n'était pas utf-8, et j'ai changé cela en courant mb_internal_encoding("UTF-8");.


20
2018-02-23 22:20



Tout d'abord si vous êtes <5.3PHP alors non. Vous avez une tonne de problèmes à résoudre.

Je suis surpris que personne n'ait mentionné le intl bibliothèque, celle qui a un bon support pour unicode, graphèmes, opérations de chaîne , localisation et beaucoup plus, voir ci-dessous.

Je vais citer quelques informations sur le support unicode en PHP par Elizabeth Smith's  glisse à PHPBenelux'14

INTL

Bien:

  • Wrapper autour de la bibliothèque ICU
  • Paramètres régionaux normalisés, définissez les paramètres régionaux par script
  • Formatage des nombres
  • Formatage de devise
  • Formatage des messages (remplace gettext)
  • Calendriers, dates, fuseau horaire et heure
  • Translitteur
  • Spoofchecker
  • Bundles de ressources
  • Convertisseurs
  • Support IDN
  • Graphemes
  • Collation
  • Iterators

Mal:

  • Ne supporte pas zend_multibite
  • Ne prend pas en charge la conversion de sortie d'entrée HTTP
  • Ne supporte pas la surcharge de fonction

mb_string

  • Active le support zend_multibyte
  • Prend en charge le codage HTTP in / out transparent
  • Fournit des wrappers pour funtionallity tels que strtoupper

ICONV

  • Primaire pour la conversion de jeu de caractères
  • Gestionnaire de tampon de sortie
  • fonctionnalité d'encodage mime
  • conversion
  • quelques aides de chaîne (len, substr, strpos, strrpos)
  • Filtre de flux stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

BASES DE DONNÉES

  • mysql: Charset et collation sur les tables et sur la connexion (pas la collation). N'utilisez pas non plus mysql - msqli ou PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): Assurez-vous qu'il a été compilé avec le support unicode et intl

Quelques autres Gotcha

  • Vous ne pouvez pas utiliser de noms de fichiers Unicode avec PHP et Windows à moins d'utiliser une extension de 3ème partie.
  • Envoyez tout en ASCII si vous utilisez exec, proc_open et d'autres appels de ligne de commande
  • Le texte brut n'est pas du texte brut, les fichiers ont des codages
  • Vous pouvez convertir des fichiers à la volée avec le filtre iconv

Je vais mettre à jour cette réponse au cas où les choses changeraient les fonctionnalités ajoutées et ainsi de suite.


19
2018-01-27 09:16



J'ai récemment découvert que l'utilisation strtolower() peut provoquer des problèmes où les données sont tronquées après un caractère spécial.

La solution était d'utiliser

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

mb_ utilise MultiByte. Il supporte plus de caractères mais en général il est un peu plus lent.


13
2018-01-13 09:37



La seule chose que je voudrais ajouter à ces réponses étonnantes est de mettre l'accent sur la sauvegarde de vos fichiers en encodage utf8, j'ai remarqué que les navigateurs acceptent cette propriété plutôt que de configurer utf8 comme encodage de code. N'importe quel éditeur de texte décent vous le montrera, par exemple Notepad ++ a une option de menu pour enconding de fichier, il vous montre l'encodage actuel et vous permet de le changer. Pour tous mes fichiers php j'utilise utf8 sans nomenclature.

Il y a quelque temps, quelqu'un me demandait d'ajouter le support utf8 pour une application php / mysql conçue par quelqu'un d'autre, j'ai remarqué que tous les fichiers étaient encodés en ANSI, donc j'ai dû utiliser ICONV pour convertir tous les fichiers, changer les tables de base de données utf8 charset et utf8_general_ci assembler, ajouter 'SET NAMES utf8' à la couche d'abstraction de base de données après la connexion (si vous utilisez 5.3.6 ou plus tôt sinon vous devez utiliser charset = utf8 dans la chaîne de connexion) et changez les fonctions de chaîne pour utiliser le php multibyte fonctions de chaîne équivalentes.


11
2017-09-10 03:39