40 votes

Suis-je correctement l'appui de l'UTF-8 dans mon PHP apps?

Je voudrais assurez-vous que tout ce que je sais à propos de l'UTF-8 est correct. J'ai essayé d'utiliser UTF-8 pour un certain temps maintenant, mais je continue de tomber sur plus et plus de bugs et d'autres choses étranges qui font qu'il semble presque impossible d'avoir un 100% UTF-8 site. Il y a toujours un piège quelque part que j'ai l'impression de passer à côté. Peut-être que quelqu'un ici peut corriger ma liste ou sur OK afin de ne pas manquer quelque chose d'important.

Base de données

Chaque site dispose d'y stocker des données quelque part. Quel que soit votre configuration PHP vous devez également configurer la DB. Si vous ne pouvez pas accéder aux fichiers de configuration puis assurez-vous de "SET NAMES 'utf8'" dès que vous vous connectez. Aussi, assurez-vous d'utiliser utf8_ unicode_ ci sur l'ensemble de vos tables. Cela suppose de MySQL pour la base de données, vous aurez à changer pour les autres.

Regex

Je fais BEAUCOUP de regex qui est plus complexe que la moyenne rechercher-remplacer. J'ai pas oublier d'utiliser le "/u" modificateur de sorte que PCRE ne pas endommager mes cordes. Pourtant, même alors, il y a encore des problèmes apparemment.

Les Fonctions De Chaîne

L'ensemble de la chaîne par défaut des fonctions (strlen(), strpos(), etc.) doit être remplacé par Chaîne multi-octets Fonctions que regarde le personnage au lieu de l'octet.

Les en-têtes Vous devriez assurez-vous que votre serveur est de retour le bon en-tête du navigateur pour savoir quel jeu de caractères que vous souhaitez utiliser (tout comme vous devez l'indiquer à MySQL).

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

Il est également une bonne idée de mettre la bonne balise < meta > dans la page de la tête. Si l'en-tête de remplacer ce devrait ils diffèrent.

<meta http-equiv="Content-Type" content="text/html;charset=utf-8">

Questions

Ai-je besoin pour convertir tout ce que je reçois de l'agent utilisateur (au format HTML et URI) de l'UTF-8 lorsque le chargement de la page, ou si je peux laisser juste les cordes/valeurs telles qu'elles sont et encore exécuter par le biais de ces fonctions sans problème?

Si j'ai besoin de tout convertir en UTF-8 alors quelles mesures dois-je prendre? mb_detect_encoding semble être construit pour cela, mais je continue à voir des gens se plaignent que ça ne fonctionne pas toujours. mb_check_encoding semble aussi avoir un problème de raconter une chaîne UTF-8 à partir d'un mal formé un.

N'PHP stocker des chaînes dans la mémoire différemment selon ce que le codage qu'il utilise (comme les types de fichiers) ou est-il encore dans la mémoire comme un aiguillon avec quelques-uns des caractères interprétés différemment (comme & amp; vs & en HTML). chazomaticus répond à cette question:

En PHP (jusqu'à PHP5, de toute façon), cordes sont juste des séquences d'octets. Il est aucune implicite ou explicite d'un jeu de caractères associé avec eux; c'est quelque chose le programmeur doit garder la trace de.

Si l'un donne une non-chaîne UTF-8 pour une mb_* fonction il toujours causer un problème?

Si une chaîne UTF est mal codés sera quelque chose de mal se passer (comme une erreur d'analyse dans les regex?) ou est-ce juste l'occasion d'une entité comme mauvais (html)? Est-il jamais une chance que mal codés chaînes de résultats en fonction renvoyant FALSE car la chaîne est mauvais?

J'ai entendu dire que vous devez vous marque les formes en UTF-8 aussi (accept-charset="UTF-8"), mais je ne suis pas sûr de ce que la prestation est..?

A l'UTF-16 écrite à l'adresse d'une limite en UTF-8? Comme n'UTF-8 a plus de place pour les personnages? (Y2(UTF)k?)

Fonctions

Ici sont un couple de la coutume des fonctions PHP que j'ai trouvé mais je n'ai pas moyen de vérifier qu'ils fonctionnent réellement. Peut-être quelqu'un a un exemple que je peux utiliser. La première est convertToUTF8() et puis seems_utf8 à partir de wordpress.

function seems_utf8($str) {
    $length = strlen($str);
    for ($i=0; $i < $length; $i++) {
        $c = ord($str[$i]);
        if ($c < 0x80) $n = 0; # 0bbbbbbb
        elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
        elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
        elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
        elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
        elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
        else return false; # Does not match any model
        for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
            if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
                return false;
        }
    }
    return true;
}

function is_utf8($str) {
    $c=0; $b=0;
    $bits=0;
    $len=strlen($str);
    for($i=0; $i<$len; $i++){
        $c=ord($str[$i]);
        if($c > 128){
            if(($c >= 254)) return false;
            elseif($c >= 252) $bits=6;
            elseif($c >= 248) $bits=5;
            elseif($c >= 240) $bits=4;
            elseif($c >= 224) $bits=3;
            elseif($c >= 192) $bits=2;
            else return false;
            if(($i+$bits) > $len) return false;
            while($bits > 1){
                $i++;
                $b=ord($str[$i]);
                if($b < 128 || $b > 191) return false;
                $bits--;
            }
        }
    }
    return true;
}

Si quelqu'un est intéressé, j'ai trouvé un excellent exemple de la page à utiliser lors de l'essai de l'UTf-8.

20voto

bobince Points 270740

Ai-je besoin pour convertir tout ce que je reçois de l'agent utilisateur (au format HTML et URI) de l'UTF-8 lorsque le chargement de la page

Pas de. L'agent utilisateur devrait être de la soumission des données au format UTF-8, sinon vous perdez le bénéfice de l'Unicode.

Le moyen de garantir un agent utilisateur soumet au format UTF-8 est de servir la page contenant le formulaire, c'est la soumission dans l'encodage UTF-8. Utiliser le header Content-Type (et meta http-equiv trop si vous avez l'intention de la forme pour être sauvé et travail autonome).

J'ai entendu dire que vous devez vous marque les formes en UTF-8 aussi (accept-charset="UTF-8")

Ne le faites pas. C'était une belle idée dans le standard HTML, mais IE n'a jamais eu droit. Il était censé état d'une liste exclusive de admissibles de jeux de caractères, mais IE traite comme une liste de jeux de caractères pour essayer, sur un champ par champ. Donc, si vous avez un ISO-8859-1 page et un "accept-charset="UTF-8"", c'est à dire va d'abord essayer de coder un domaine que l'ISO-8859-1, et si il y a un non-8859-1 personnage-il, puis il va recourir à l'UTF-8.

Mais depuis IE ne vous dit pas s'il a utilisé l'ISO-8859-1 ou UTF-8, c'est d'absolument aucune utilité pour vous. Vous devez deviner, séparément pour chaque champ, dont l'encodage est en cours d'utilisation! Pas utile. Omettre l'attribut et de servir vos pages en UTF-8; c'est le meilleur que vous pouvez faire à l'heure actuelle.

Si une chaîne UTF est mal codés sera quelque chose de mal se passer

Si vous laissez une telle séquence de passer à travers le navigateur que vous pourriez être en difficulté. Il y a " trop de séquences, qui codent pour une faible numérotés codepoint dans une longue séquence d'octets que ce qui est nécessaire. Cela signifie que si vous êtes filtrage ‘<' par la recherche pour que les caractères ASCII en une séquence d'octets, vous risquez de rater l'un, et un élément de script dans ce que vous avez pensé était sûr de texte.

Trop séquences ont été interdits de retour dans les premiers jours de l'Unicode, mais il a fallu à Microsoft un temps très long pour obtenir leur merde ensemble: c'est à dire les interpréter la séquence d'octets ‘\xC0\xBC' comme un ‘<' jusqu'à IE6 Service Pack 1. L'opéra a également eu tort jusqu'à (je pense) de la version 7. Heureusement, ces navigateurs plus anciens sont en train de disparaître, mais il est toujours intéressant de filtrage trop séquences dans le cas où ces navigateurs sont encore aujourd'hui (ou de nouvelles idiot navigateurs de faire la même erreur à l'avenir). Vous pouvez faire cela, et de fixer d'autres mauvaises séquences, avec une regex qui permet seulement une bonne UTF-8, comme ce l'un de W3.

Si vous utilisez des fonctions mb_ en PHP, vous pourriez être isolé à partir de ces questions. Je ne peux pas dire pour sûr que mb_* était inutilisable fragile quand j'étais encore écrit en PHP.

En tout cas, c'est aussi un bon moment pour supprimer les caractères de contrôle, qui sont d'une grande et généralement apprécié source de bugs. Je voudrais supprimer des caractères 9 et 13 de soumis chaîne en plus des autres le W3 regex sort; il est également intéressant de retrait de la plaine des retours à la ligne pour les chaînes que vous connaissez ne sont pas censés être des zones de texte multiligne.

A l'UTF-16 écrite à l'adresse d'une limite en UTF-8?

Non, UTF-16 est un deux-octet-par-codepoint codage qui est utilisé pour faire de l'indexation des chaînes Unicode plus facile dans la mémoire (de l'époque où toutes Unicode rentre dans deux octets; les systèmes comme Windows et Java encore le faire de cette façon). À la différence de l'UTF-8, il n'est pas compatible avec l'ASCII, et est de peu-à-peu l'utiliser sur le Web. Mais il vous arrive parfois de rencontrer dans les fichiers enregistrés, généralement ceux enregistrés par les utilisateurs de Windows qui ont été induits en erreur par les Fenêtres de la description de l'UTF-16LE "Unicode" dans Enregistrer sous menus.

seems_utf8

C'est très inefficace par rapport à la regex!

Aussi, assurez-vous d'utiliser utf8_unicode_ci sur toutes vos tables.

Vous pouvez réellement sortir sans cela, le traitement de MySQL comme un magasin pour rien, mais octets et seulement les interpréter comme de l'UTF-8 dans votre script. L'avantage de l'utilisation de utf8_unicode_ci c'est qu'il va assembler (tri et de faire de la casse compare) avec des connaissances sur les caractères non-ASCII, afin par exemple. ‘à' et ‘À' sont le même personnage. Si vous utilisez un non-UTF8 classement vous devez vous en tenir à binaire (sensible à la casse) correspondant.

Quel que soit votre choix, le faire de manière cohérente: utiliser le même jeu de caractères pour vos tables comme vous le faites pour votre connexion. Ce que vous voulez éviter, c'est une perte de conversion de jeu de caractères entre vos scripts et de la base de données.

11voto

djn Points 3015

La plupart de ce que vous faites aujourd'hui se doit d'être correcte.

Quelques remarques: tout utf_* classement dans MySQL serait de stocker correctement vos données en UTF-8, la seule différence entre eux est le classement (par ordre alphabétique) appliquée lors du tri.

Vous pouvez indiquer à Apache et PHP pour délivrer le bon charset les en-têtes de réglage AddDefaultCharset utf-8 dans httpd.conf/.htaccess et default_charset = "utf-8" en php.ini respectivement.

Vous pouvez dire à l'extension mbstring pour prendre soin de la chaîne de fonctions. Cela fonctionne pour moi:

mbstring.internal_encoding=utf-8
mbstring.http_output=UTF-8
mbstring.encoding_translation=On
mbstring.func_overload=6

(ce qui laisse l' mail() de la fonction intact - j'ai trouvé un réglage à 7 a fait des ravages dans mon en-têtes de courriel)

Pour la conversion de jeux de caractères prendre un coup d'oeil à https://sourceforge.net/projects/phputf8/.

PHP ne se préoccupe pas de ce qui est dans la variable, c'est juste stocke et récupère aveuglément son contenu.

Vous aurez des résultats inattendus si vous déclarez un mbstring.internal_encoding et d'alimentation à une mb_* fonction de chaînes de caractères dans un autre encodage. Vous pouvez quand même envoyer en toute sécurité ASCII, utf-8 fonctions.

Si vous êtes inquiet au sujet de quelqu'un affichage incorrecte codé des trucs sur le but je crois que vous devriez considérer HTML Purifier pour filtre GET/POST données avant de les traiter.

Accept-charset a été dans les specs depuis toujours, mais le monde réel support dans les navigateurs est plus ou moins zéro. Le navigateur typiquement à utiliser l'encodage af la page contenant le formulaire.

UTF-16 n'est pas le grand frère de l'UTF-8, il sert juste à un objectif différent.

3voto

VolkerK Points 54118

base de données/mysql: Si vous utilisez SET NAMES et, par exemple, php/mysql , vous êtes en laissant mysql_real_escape_string() dans l'obscurité au sujet de la modification de l'encodage des caractères. Cela peut conduire à des résultats faux. Donc, si vous êtes en s'appuyant sur une fonction d'échappement comme mysql_real_escape_string (parce que vous n'êtes pas en utilisant des requêtes préparées) SET NAMES est une solution sous-optimale. C'est pourquoi mysql_set_charset() a été mis en place ou pourquoi gentoo applique un patch qui ajoute la config paramètre mysql.connect_charset pour php/mysql et php/mysqli.

Le client n'a généralement pas d'indiquer l'encodage des paramètres qu'il envoie. Si vous vous attendez codé en utf-8 les données et les traiter en tant que tel il peut y avoir des erreurs de codage (les séquences d'octets qui sont invalides en utf-8). Ainsi, les données peuvent ne pas s'afficher comme prévu ou un analyseur pouvez interrompre l'analyse. Mais au moins, l'entrée de l'utilisateur ne peut pas "s'échapper" et de faire plus de mal par exemple dans une ligne de l'instruction sql ou de la sortie html. E. g. prendre le script (enregistré en tant que iso-8859-1 ou utf-8, n'a pas d'importance)

<?php
$s = 'abcxyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));
// adding the byte sequence for äöü in iso-8859-1
$s = 'abc'. chr(0xE4) . chr(0xF6) . chr(0xFC). 'xyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));

imprime

string(6) "abcxyz"
string(0) ""

E4F6FC n'est pas utf-8 valide séquence d'octets, donc htmlspecialchars retourne une chaîne vide. D'autres fonctions peuvent renvoyer ? ou un autre caractère spécial. Mais au moins, ils ne "erreur" un caractère malveillant caractère de contrôle - tant que tous en tenir à la "bonne" encoding (utf-8 dans ce cas).

accept-charset ne garantit pas que vous recevrez uniquement les données avec cet encodage. Pour tous vous le savez, le client peut même pas a "utilisé"/analysé votre document html contenant l'élément de formulaire. Il peut aider et il n'ya aucune raison pourquoi vous ne devriez pas définir cet attribut. Mais ce n'est pas "fiable".

0voto

Adrián Navarro Points 337

UTF-8 est très bien, et n'ont pas des limites que l'UTF-16 en résout. PHP se complique pas les changements de son chemin pour stocker des chaînes de caractères dans la mémoire (contrairement à Python). Si l'ensemble du flux de données est l'utilisation de l'UTF-8 (formulaires web recevoir des données UTF-8, les tables d'utiliser l'encodage utf8 et que vous utilisez l' SET NAMES utf8, et les données sont stockées sans être altéré (pas de conversion de jeux de caractères), qui doit être fine.

0voto

p4bl0 Points 2583

Pour les entrées de l'utilisateur de la forme-je ajouter cet attribut pour ma forms tags : accept-charset="utf-8". De cette façon, les données que vous recevez doit toujours être codé en utf-8.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X