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
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+30 −1
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -654,6 +654,7 @@ function utf_32_to_unicode($source) {
 *    Caractère utf8 si trouvé, '' sinon
**/
function caractere_utf_8($num) {
	$num = intval($num);
	if($num<128)
		return chr($num);
	if($num<2048)
@@ -661,7 +662,7 @@ function caractere_utf_8($num) {
	if($num<65536)
		return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
	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 '';
}

@@ -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;
}


?>
+14 −4
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -207,7 +207,7 @@ function objet_modifier_champs($objet, $id_objet, $options, $c=null, $serveur=''
		// si difference entre les champs, reperer les champs mal enregistres
		if ($moof != $champs) {
			$liste = array();
			foreach($moof as $k=>$v)
			foreach($moof as $k=>$v) {
				if ($v !== $champs[$k]
				// ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
				AND (!is_numeric($v) OR intval($v)!=intval($champs[$k]))
@@ -215,6 +215,16 @@ function objet_modifier_champs($objet, $id_objet, $options, $c=null, $serveur=''
					$liste[] = $k;
					$conflits[$k]['post'] = $champs[$k];
					$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
			// c'est un cas exceptionnel
+1 −1
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -922,7 +922,7 @@ function queue_sleep_time_to_next_job($force=null) {
// http://doc.spip.org/@quote_amp
function quote_amp($u) {
	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);
}

+9 −2
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -118,7 +118,8 @@ $GLOBALS['spip_mysql_functions_1'] = array(
//'iso-8859-6'=>array('charset'=>'latin1','collation'=>'latin1_swedish_ci'),
'iso-8859-9'=>array('charset'=>'latin5','collation'=>'latin5_turkish_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='') {
	}
	$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);
	return $r;
}