Skip to content
Extraits de code Groupes Projets
Valider e5d06f53 rédigé par Fil's avatar Fil
Parcourir les fichiers

gestion des emoji avec MySQL

================

le charset 'utf8' de MySQL ne contient pas l'ensemble de l'UTF-8, mais seulement les caractères codés sur 1, 2, ou 3 bytes; pour contourner ce problème, on pourrait adopter le charset 'utf8mb4', mais c'est difficile à faire, et ça implique de revoir la structure de la base (notamment les VARCHAR 255 ne passent plus, car 255*4 > 1000)

la solution adoptée ici est d'échapper les caractères de 4 bytes sous leur forme unicode 💩 ; on le fait au niveau de req/mysql car ce problème touche mysql seulement

pour activer ce fonctionnement, il faut pour l'instant ajouter dans mes_options la ligne suivante :   define('_MYSQL_NOPLANES', true);

au passage mes tests sur l'emoji on révélé deux bugs dans inc/charsets, corrigés ici

références : http://seenthis.net/messages/350136
parent 4a8784da
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -654,6 +654,7 @@ function utf_32_to_unicode($source) { ...@@ -654,6 +654,7 @@ function utf_32_to_unicode($source) {
* Caractère utf8 si trouvé, '' sinon * Caractère utf8 si trouvé, '' sinon
**/ **/
function caractere_utf_8($num) { function caractere_utf_8($num) {
$num = intval($num);
if($num<128) if($num<128)
return chr($num); return chr($num);
if($num<2048) if($num<2048)
...@@ -661,7 +662,7 @@ function caractere_utf_8($num) { ...@@ -661,7 +662,7 @@ function caractere_utf_8($num) {
if($num<65536) if($num<65536)
return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128); return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
if($num<1114112) if($num<1114112)
return chr($num>>18+240).chr((($num>>12)&63)+128).chr(($num>>6)&63+128). chr($num&63+128); return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr(($num>>6)&63+128). chr($num&63+128);
return ''; return '';
} }
...@@ -1106,4 +1107,32 @@ if (!isset($GLOBALS['meta']['pcre_u']) ...@@ -1106,4 +1107,32 @@ if (!isset($GLOBALS['meta']['pcre_u'])
); );
} }
/**
* Transforme une chaîne utf-8 en utf-8 sans "planes"
* ce qui permet de la donner à MySQL "utf8", qui n'est pas un utf-8 complet
* L'alternative serait d'utiliser utf8mb4
*
* @param string $x
* La chaîne à transformer
* @return string
* La chaîne avec les caractères utf8 des hauts "planes" échappée
* en unicode : &#128169;
*/
function utf8_noplanes($x) {
$regexp_utf8_4bytes = '/(
\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)/xS';
if (preg_match_all($regexp_utf8_4bytes, $x, $z, PREG_PATTERN_ORDER)) {
foreach($z[0] as $k) {
$ku = utf_8_to_unicode($k);
$x = str_replace($k, $ku, $x);
}
}
return $x;
}
?> ?>
...@@ -207,15 +207,25 @@ function objet_modifier_champs($objet, $id_objet, $options, $c=null, $serveur='' ...@@ -207,15 +207,25 @@ function objet_modifier_champs($objet, $id_objet, $options, $c=null, $serveur=''
// si difference entre les champs, reperer les champs mal enregistres // si difference entre les champs, reperer les champs mal enregistres
if ($moof != $champs) { if ($moof != $champs) {
$liste = array(); $liste = array();
foreach($moof as $k=>$v) foreach($moof as $k=>$v) {
if ($v !== $champs[$k] if ($v !== $champs[$k]
// ne pas alerter si le champ est numerique est que les valeurs sont equivalentes // ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
AND (!is_numeric($v) OR intval($v)!=intval($champs[$k])) AND (!is_numeric($v) OR intval($v)!=intval($champs[$k]))
) { ) {
$liste[] = $k; $liste[] = $k;
$conflits[$k]['post'] = $champs[$k]; $conflits[$k]['post'] = $champs[$k];
$conflits[$k]['save'] = $v; $conflits[$k]['save'] = $v;
// cas specifique MySQL+emoji : si l'un est la
// conversion utf8_noplanes de l'autre alors c'est OK
if (defined('_MYSQL_NOPLANES') && _MYSQL_NOPLANES) {
include_spip('inc/charsets');
if ($v == utf8_noplanes($champs[$k])) {
array_pop($liste);
}
}
} }
}
// si un champ n'a pas ete correctement enregistre, loger et retourner une erreur // si un champ n'a pas ete correctement enregistre, loger et retourner une erreur
// c'est un cas exceptionnel // c'est un cas exceptionnel
if (count($liste)){ if (count($liste)){
......
...@@ -922,7 +922,7 @@ function queue_sleep_time_to_next_job($force=null) { ...@@ -922,7 +922,7 @@ function queue_sleep_time_to_next_job($force=null) {
// http://doc.spip.org/@quote_amp // http://doc.spip.org/@quote_amp
function quote_amp($u) { function quote_amp($u) {
return preg_replace( return preg_replace(
"/&(?![a-z]{0,4}\w{2,3};|#x?[0-9a-f]{2,5};)/i", "/&(?![a-z]{0,4}\w{2,3};|#x?[0-9a-f]{2,6};)/i",
"&amp;",$u); "&amp;",$u);
} }
......
...@@ -118,8 +118,9 @@ $GLOBALS['spip_mysql_functions_1'] = array( ...@@ -118,8 +118,9 @@ $GLOBALS['spip_mysql_functions_1'] = array(
//'iso-8859-6'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'), //'iso-8859-6'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
'iso-8859-9'=>array('charset'=>'latin5','collation'=>'latin5_turkish_ci'), 'iso-8859-9'=>array('charset'=>'latin5','collation'=>'latin5_turkish_ci'),
//'iso-8859-15'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'), //'iso-8859-15'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci')) 'utf-8'=>array('charset'=>'utf8','collation'=>'utf8_general_ci')
); )
);
/** /**
...@@ -488,6 +489,12 @@ function _mysql_traite_query($query, $db='', $prefixe='') { ...@@ -488,6 +489,12 @@ function _mysql_traite_query($query, $db='', $prefixe='') {
} }
$r = preg_replace(_SQL_PREFIXE_TABLE_MYSQL, '\1'.$pref, $query) . $suite; $r = preg_replace(_SQL_PREFIXE_TABLE_MYSQL, '\1'.$pref, $query) . $suite;
// en option, remplacer les emoji (que mysql ne sait pas gérer) en &#128169;
if (defined('_MYSQL_NOPLANES') && _MYSQL_NOPLANES) {
include_spip('inc/charsets');
$r = utf8_noplanes($r);
}
#spip_log("_mysql_traite_query: " . substr($r,0, 50) . ".... $db, $prefixe", _LOG_DEBUG); #spip_log("_mysql_traite_query: " . substr($r,0, 50) . ".... $db, $prefixe", _LOG_DEBUG);
return $r; return $r;
} }
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter