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)
<?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','',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 😒 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 ''.dechex(substr(mb_convert_encoding($m[0], 'HTML-ENTITIES', 'UTF-8'), 2)).';';}, $body);
echo 'after: ',$body,'<br />'; # Output: lol😒a☺
?>
EDIT: Désolé, je ne peux pas utiliser la coloration syntaxique car, n'ayant pas encore implémenté cette solution, j'ai activé l'HTML pour ce message (creator only) mais la balise code me l'échappe si je tente de faire ça.
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.