Daily Shaarli

All links of one day in a single page.

May 4, 2014

(SOLUTION) [PHP] [MySQL] Stocker UTF-8 avant MySQL 5.5 (sans utf8mb4) ? - Forums - Olissea.com

Lien précédent : http://www.olissea.com/mb/links/1/?ibR8_g

EDIT: J'ai trouvé ce problème ceci dit: https://bugs.php.net/bug.php?id=65045
Mais j'ignore si je suis vraiment concerné : ça dépend en effet si mon script capture ces séquences à problèmes mais il me semble qu'il ne capture que les séquences valides de 4 bytes, donc pas de problème normalement.

Également, j'ai pas trop compris comment ça se fait, mais lorsque j'applique htmlspecialchars sur les séquences données sur la page, l'output n'est pas vide. Ne devrait-il pas l'être (vu que htmlspecialchars renvoie stupidement une chaîne vide lorsqu'il reçoit de l'UTF-8 invalide normalement ?).

Mmmmmh.
</EDIT>

"Plop.

Après mainte péripéties et échecs, je pense avoir trouver quelque chose de "potable".

Voir le code avec coloration syntaxique (un peu différent, manque une source) : http://sebsauvage.net/paste/?e249576d75ee9946#jBpv2UCufTQ4UC2WnTtM11gfolfGkQi61brf11pFORU=

<?php

"😒" est codé sur 4 bytes

$body = 'lol😒a☺';

echo 'before: ',$body,'<br />'; # Output: lol😒a☺
echo 'length: ',strlen($body),'<br />'; # Output: 11 (😒 = 4, ☺ = 3)

Le but est de remplacer uniquement les caractères de plus de 3 bytes par leur entité HTML.

Afin d'obtenir ce code dans le cas de notre exemple

echo '😒','<br />'; # Fourni par https://duckduckgo.com/?q=html+%F0%9F%98%92

Récupération des caractères de plus de 3 bytes uniquement

Source: http://stackoverflow.com/a/1401716/1524913

$body = preg_replace('/[\xF0-\xF7][\x80-\xBF]{3}/', '�', $body); # Yeah! It works!

Ne fonctionne pas. htmlentities ne connaît pas tous les caractères unicode ( http://stackoverflow.com/a/13942507/1524913 )

$body = preg_replace_callback('/[\xF0-\xF7][\x80-\xBF]{3}/', function($m){return htmlentities($m[0], ENT_COMPAT, 'UTF-8');}, $body); # Ignore complètement 😒

La solution proposée au lien précédemment cité : Ne fonctionne pas non plus

$body = preg_replace_callback('/[\xF0-\xF7][\x80-\xBF]{3}/', function($m){return str_replace('\u','&#x',trim(json_encode($m[0]),'"')).';';}, $body);

Output: lol��a☺ car json_encode considère ça comme deux caractères de deux bytes et renvoie "\ud83d\ude12"

Ne fonctionne pas ( http://php.net/manual/en/function.htmlentities.php#107985 )

$body = preg_replace_callback('/[\xF0-\xF7][\x80-\xBF]{3}/', function($m){return mb_encode_numericentity($m[0], array(0x0, 0xffff, 0, 0xffff), 'UTF-8');}, $body); # Ignore complètement 😒

Fonctionne !!! Mais renvoie &#128530 au lieu de 😒 (Pas vraiment un problème en soit)

$body = preg_replace_callback('/[\xF0-\xF7][\x80-\xBF]{3}/', function($m){return mb_convert_encoding($m[0], 'HTML-ENTITIES', 'UTF-8');}, $body);

Si on veut vraiment la version hexadécimal

$body = preg_replace_callback('/[\xF0-\xF7][\x80-\xBF]{3}/', function($m){return '&#x'.dechex(substr(mb_convert_encoding($m[0], 'HTML-ENTITIES', 'UTF-8'), 2)).';';}, $body);

echo 'after: ',$body,'<br />'; # Output: lol😒a☺

?> "