Je configure un nouveau serveur et souhaite prendre en charge UTF-8 dans mon application Web. J'ai déjà essayé cela sur des serveurs existants et semble toujours devoir me rabattre sur ISO-8859-1.
Où dois-je exactement définir l'encodage/les jeux de caractères? Je suis conscient de la nécessité de configurer Apache, MySQL et PHP pour ce faire. Existe-t-il une liste de contrôle standard que je peux suivre, ou peut-être que l'on puisse résoudre le problème d'incompatibilités?
Ceci concerne un nouveau serveur Linux, exécutant MySQL 5, PHP, 5 et Apache 2.
Stockage de données :
Spécifiez le jeu de caractères _utf8mb4
_ sur toutes les tables et toutes les colonnes de texte de votre base de données. Cela permet à MySQL de stocker et de récupérer physiquement les valeurs encodées de manière native en UTF-8. Notez que MySQL utilisera implicitement le codage _utf8mb4
_ si un classement _utf8mb4_*
_ 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 prend en charge qu'un sous-ensemble de caractères Unicode. Je voudrais plaisanter.
Accès aux données :
Dans votre code d'application (PHP, par exemple), quelle que soit la méthode d'accès à la base de données utilisée, vous devez définir le jeu de caractères de connexion sur _utf8mb4
_. De cette façon, MySQL n'effectue aucune conversion de son UTF-8 natif lorsqu'il transmet des données à votre application, et inversement.
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 du codage à utiliser sur la connexion (il s'agit généralement de l'approche préférée. En PHP:
Si vous utilisez la couche d'abstraction PDO avec PHP ≥ 5.3.6, vous pouvez spécifier charset
dans DSN :
_$dbh = new PDO('mysql:charset=utf8mb4');
_
Si vous utilisez mysqli , vous pouvez appeler set_charset()
:
_$mysqli->set_charset('utf8mb4'); // object oriented style
mysqli_set_charset($link, 'utf8mb4'); // procedural style
_
Si vous êtes coincé avec plain mysql mais que vous utilisez PHP ≥ 5.2.3, vous pouvez appeler mysql_set_charset
.
Si le pilote ne fournit pas son propre mécanisme pour définir le jeu de caractères de la connexion, vous devrez peut-être lancer 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'
.
Les mêmes considérations concernant _utf8mb4
_/_utf8
_ s'appliquent comme ci-dessus.
Sortie :
Si votre application transmet du texte à d'autres systèmes, ceux-ci devront également être informés du codage 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 l'option default_charset
php.ini ou attribuer manuellement l'en-tête _Content-Type
_ MIME vous-même, ce qui représente davantage de travail mais a le même effet.
Lors du codage de la sortie à l'aide de json_encode()
, ajoutez _JSON_UNESCAPED_UNICODE
_ en tant que deuxième paramètre.
Entrée :
Malheureusement, vous devez vérifier chaque chaîne reçue comme étant en UTF-8 valide avant d'essayer de la stocker ou de l'utiliser n'importe où. Le PHP mb_check_encoding()
fait l'affaire, mais vous devez l'utiliser religieusement. Il n’ya vraiment aucun moyen de contourner ce problème, car les clients malveillants peuvent soumettre des données dans l’encodage qu’ils souhaitent, et je n’ai pas trouvé l’astuce pour que PHP le fasse pour vous de manière fiable.
D'après ma lecture du HTML spec actuel, les sous-puces suivantes ne sont plus nécessaires ni même plus valables pour le HTML moderne. D'après ce que j'ai compris, les navigateurs travailleront avec les données et les soumettront dans le jeu de caractères spécifié pour le document. Cependant, si vous ciblez d'anciennes versions de HTML (XHTML, HTML4, etc.), ces points peuvent toujours être utiles:
accept-charset
_ à toutes vos balises _<form>
_: _<form ... accept-charset="UTF-8">
_.<form>
_.Autres considérations sur le code :
Bien évidemment, tous les fichiers que vous allez servir (PHP, HTML, JavaScript, etc.) doivent être encodés en UTF-8 valide.
Vous devez vous assurer que chaque fois que vous traitez une chaîne UTF-8, vous le faites en toute sécurité. C'est malheureusement la partie la plus difficile. Vous voudrez probablement faire un usage intensif de l'extension mbstring
de PHP.
Les opérations de chaîne intégrées à PHP sont et non par défaut avec la sécurité UTF-8. peut le faire en toute sécurité avec les opérations de chaîne PHP normales (comme la concaténation), mais pour la plupart des choses, vous devez utiliser la fonction équivalente mbstring
.
Pour savoir ce que vous faites (lisez: ne le gâchez pas), vous devez vraiment connaître le format UTF-8 et son fonctionnement au niveau le plus bas possible. Découvrez l'un des liens de tf8.com pour trouver de bonnes ressources pour apprendre tout ce que vous devez savoir.
J'aimerais ajouter une chose à excellente réponse de chazomaticus :
N'oubliez pas la balise META soit (comme ceci, ou la version HTML4 ou XHTML de celle-ci ):
<meta charset="utf-8">
Cela semble anodin, mais IE7 m’a déjà posé problème auparavant.
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 réglés sur UTF-8 et fonctionnaient correctement sur tous les autres navigateurs, mais Internet Explorer insistait toujours pour utiliser le codage "Europe occidentale".
Il s'est avéré que la page manquait l'étiquette META. Ajouter cela a résolu le problème.
Modifier:
Le W3C a en fait un assez grand section dédiée à I18N . Ils ont plusieurs articles sur ce problème, décrivant les aspects HTTP, (X) HTML et CSS:
Ils recommandent d'utiliser à la fois l'en-tête HTTP et la balise méta HTML (ou la déclaration XML dans le cas où XHTML est utilisé en tant que XML).
En plus de définir default_charset
dans php.ini, vous pouvez envoyer le jeu de caractères correct à l'aide de header()
à partir de votre code, avant toute sortie:
header('Content-Type: text/html; charset=utf-8');
Travailler avec Unicode dans PHP est simple, tant que vous vous rendez compte que la plupart des fonctions de chaîne ne fonctionnent pas avec Unicode et que certaines peuvent modifier complètement les chaînes . PHP considère que les "caractères" ont une longueur de 1 octet. Parfois, c'est correct (par exemple, explode()
ne recherche qu'une séquence d'octets et l'utilise comme séparateur - le type de caractère recherché n'a donc pas d'importance.). Mais d'autres fois, lorsque la fonction est conçue pour fonctionner sur caractères , PHP n'a aucune idée que votre texte comporte des caractères multi-octets trouvés avec Unicode. .
Une bonne bibliothèque à vérifier est phputf8 . Ceci réécrit toutes les "mauvaises" fonctions afin que vous puissiez travailler en toute sécurité sur les chaînes UTF8. Il existe des extensions telles que l'extension mbstring qui essaient de le faire pour vous aussi, mais je préfère utiliser la bibliothèque car elle est plus portable (mais j'écris des produits grand public, donc c'est important pour moi). Mais phputf8 peut utiliser mbstring dans les coulisses pour augmenter ses performances.
J'ai trouvé un problème avec une personne utilisant PDO et la réponse a été de l'utiliser 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 sur lequel j'ai pris cette information est en panne, mais heureusement, j'ai pu l'obtenir à l'aide du cache de Google.
Dans mon cas, j'utilisais mb_split
, qui utilise regex. Par conséquent, je devais aussi m'assurer manuellement que le codage regex était utf-8 en faisant mb_regex_encoding('UTF-8');
En remarque, j'ai aussi découvert en exécutant mb_internal_encoding()
que l'encodage interne n'était pas utf-8, et j'ai changé cela en exécutant mb_internal_encoding("UTF-8");
.
Tout d’abord si vous êtes dans <5.3PHP, alors non. Vous avez une tonne de problèmes à résoudre.
Je suis surpris qu’aucune d’entre elles n’ait mentionné la bibliothèque intl , celle qui supporte bien unicode , graphèmes , opérations sur les chaînes , localisation et beaucoup d'autres, voir ci-dessous.
Je citerai quelques informations sur le support unicode dans PHP de par Elizabeth Smith slides à PHPBenelux'14
Bien:
Mauvais:
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
Je mettrai à jour cette réponse au cas où des modifications seraient apportées aux fonctionnalités, etc.
J'ai récemment découvert que l'utilisation de strtolower()
peut entraîner des problèmes de données 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 est en général un peu plus lent.
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 acceptaient cette propriété plutôt que de définir utf8 comme encodage de code. Tout éditeur de texte correct vous le montrera. Par exemple, Notepad ++ a une option de menu pour l’encodage de fichier, il vous montre l’encodage actuel et vous permet de le changer. Pour tous mes fichiers php, j'utilise utf8 sans nomenclature.
Quelque temps auparavant, quelqu'un m'a demandé 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. Je devais donc utiliser ICONV pour convertir tous les fichiers, modifier les tables de la base de données utf8 charset et utf8_general_ci s'assemblent, ajoutez 'SET NAMES utf8' à la couche d'abstraction de la base de données après la connexion (si vous utilisez 5.3.6 ou une version antérieure, vous devez utiliser charset = utf8 dans la chaîne de connexion) et modifiez les fonctions de chaîne pour utiliser le multibyte php. fonctions de chaîne équivalentes.
Je viens de parcourir le même problème et j'ai trouvé une bonne solution dans PHP manuals.
J'ai changé tout mon encodage de fichier en UTF8 puis l'encodage par défaut de ma connexion. Cela a résolu tous les problèmes.
if (!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
printf("Current character set: %s\n", $mysqli->character_set_name());
}
En PHP, vous devez soit utiliser fonctions multi-octets , soit activer mbstring.func_overload . De cette façon, des choses comme strlen fonctionneront si vous avez des caractères qui prennent plus d’un octet.
Vous devrez également identifier le jeu de caractères de vos réponses. Vous pouvez soit utiliser AddDefaultCharset, comme ci-dessus, ou écrire PHP code qui retourne l'en-tête. (Vous pouvez également ajouter une balise META à vos documents HTML.)
Le support Unicode dans PHP est toujours un désastre énorme. Bien qu’il soit capable de convertir une chaîne ISO8859 (qu’il utilise en interne) en utf8, il n’a pas la capacité de travailler avec des chaînes unicode de manière native, ce qui signifie que toutes les fonctions de traitement de chaîne modifieront et corrompront vos chaînes. Vous devez donc utiliser une bibliothèque distincte pour la prise en charge appropriée d'utf8 ou réécrire vous-même toutes les fonctions de gestion des chaînes.
La partie facile consiste simplement à spécifier le jeu de caractères dans les en-têtes HTTP et dans la base de données, mais cela n’a aucune importance si votre code PHP ne génère pas de code UTF8 valide. C'est la partie difficile, et PHP ne vous aide pratiquement pas. (Je pense que PHP6 est supposé résoudre le pire, mais c'est encore loin)
Si vous voulez que le serveur MySQL décide du jeu de caractères et non de PHP en tant que client (ancien comportement; préféré, à mon avis), essayez d'ajouter skip-character-set-client-handshake
à votre my.cnf
, sous [mysqld]
et redémarrez mysql
.
Cela peut causer des problèmes si vous utilisez autre chose que UTF8.
La réponse est excellente. Voici ce que je devais faire sur une installation standard de debian/php/mysql:
// storage
// debian. apparently already utf-8
// retrieval
// the mysql database was stored in utf-8,
// but apparently php was requesting iso. this worked:
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');
// delivery
// php.ini did not have a default charset,
// (it was commented out, shared Host) and
// no http encoding was specified in the Apache headers.
// this made Apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');
// submission
// this worked in all major browsers once Apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.
// processing
// changed a few commands in php, like substr,
// to mb_substr
c'était tout !
Juste une note:
Vous êtes confronté au problème de vos caractères non-latins qui se présentent comme ?????????
, vous avez posé une question, et il s'est fermé avec une référence à cette question canonique, vous avez tout essayé et peu importe ce que vous obtenez, vous obtenez toujours ??????????
de MySQL
.
C’est principalement parce que vous testez vos anciennes données qui a été inséré dans la base de données à l’aide du mauvais jeu de caractères, puis converti et stocké sous les caractères de point d’interrogation ?
. Ce qui signifie que vous avez perdu votre texte original pour toujours et peu importe ce que vous essayez, vous obtiendrez ???????
.
en appliquant ce que vous avez appris des réponses de cette question sur de nouvelles données, cela pourrait résoudre votre problème.
si vous voulez une solution mysql, j'ai eu des problèmes similaires avec 2 de mes projets, après une migration de serveur. Après avoir cherché et essayé beaucoup de solutions, je suis tombé sur celui-ci/rien avant que celui-ci ne fonctionne):
mysqli_set_charset($con,"utf8");
Après avoir ajouté cette ligne à mon fichier de configuration, tout fonctionne correctement!
J'ai trouvé cette solution https://www.w3schools.com/PHP/func_mysqli_set_charset.asp alors que je cherchais à résoudre une requête d'insertion à partir de HTML
bonne chance!