logo

NPDS : Gestion de contenu et de communauté


Content & Community Management System (CCMS) robuste, sécurisé, complet, performant, parlant vraiment français, libre (Open-Source) et gratuit.
180 visiteur(s) et 0 membre(s) en ligne.
Activité du Site

Pages vues depuis 25/05/2001 : 116 171 333

  • Nb. de membres 8 707
  • Nb. d'articles 1 703
  • Nb. de forums 26
  • Nb. de sujets 8
  • Nb. de critiques 92

Top 10  Statistiques

Index du forum »»  Le coin des codeurs »» [Résolu] - Bug du captcha en chinois

[Résolu] - Bug du captcha en chinois#27112

2Contributeur(s)
Visiteurjpb
3 Modérateur(s)
developpeurjpbJireck
Visiteur Visiteuricon_post
Concernant le commentaire mort dans Q_spambot() :

##################################################################
/* infernal ....
après de nombreux essai ... avec ISO-8859-1 ou UTF-8
$aff=str_replace($tab[$al1],html_entity_decode(translate($tab[$al1]), ENT_QUOTES | ENT_HTML401, 'ISO-8859-1'),$aff);

encrypt puis decrypt renvoient un résultats corrects stable
mais parfois la fonction encrypt peut renvoyer une chaine
- se terminant par == ou /
- contenant de + des /
dans ces cas là le résultat de rawurldecode(decrypt()) est corrompu !

dans les autres cas le résultat de rawurldecode(decrypt()) traité dans cette page est correct
MAIS PAS quand ça repasse par le serveur et traité dans getfile.php (et je ne comprends pas pourquoi)

donc pour l'instant on garde UTF-8 et on redécode dans getfile.php
mais dans tout les cas le captcha en chinois est faux
//je pense qu' il faut plutôt utiliser imagettftext dans le captcha (adapté à utf-8) !
*/
##################################################################

En fait le vrai coupable est ailleurs, dans getfile.php. Dans Q_spambot(), l'URL est construite comme ça :

php
rawurlencode(encrypt($aff." = "))

Donc encrypt() fait son base_64, et rawurlencode() rend ça propre pour l'URL. Sauf que PHP url-decode automatiquement les paramètres de $_GET/$_POST en parsant la query string — donc quand $att_id arrive dans getfile.php, il est déjà revenu à sa forme d'origine (base_64 brut, avec ses +, /, =). Ce boulot-là, PHP l'a déjà fait tout seul avant même que le code s'exécute.

Le bug, il est là :

php
$mot = decrypt($att_id); // OK, $att_id est déjà "propre"
$mot = rawurldecode($mot); // ça décode le texte déjà décrypté, pas la donnée encodée !

Ce rawurldecode() s'applique sur le texte en clair (genre "4 - (3 / 1) = ", ou une traduction en chinois) au lieu de la donnée encodée — inutile la plupart du temps, et carrément dangereux si le texte contient par hasard une séquence qui ressemble à un %XX ou des octets UTF-8 multi-bytes. Ça colle pile avec ce que notait l'auteur : "le captcha en chinois est faux".

La correction, c'est simplement de virer ce rawurldecode() en trop, vu que $att_id est déjà décodé par PHP à l'entrée :

dans getfile.php



case 'captcha':
$mot = decrypt($att_id);
$mot = mb_convert_encoding($mot, 'ISO-8859-1', 'UTF-8'); ////utf-8 >> iso
$font = 16;
$width = imagefontwidth($font)* strlen($mot);
$height = imagefontheight($font);
$img = imagecreate($width+4, $height+4);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagecolortransparent($img, $blanc);
imagestring($img, $font, 1 , 1, $mot, $noir);
imagepng($img);
imagedestroy($img);
break;


Ce qui devrait corriger ton bug sur le captcha en chinois. Si tu veux être sûr à 100 % avant de pousser en prod, le plus simple reste de tester le captcha avec une question traduite en chinois après la modif, pour confirmer visuellement que le texte s'affiche correctement dans l'image.

À Jpb, comme d'hab, à toi de voir ce qui te convient le mieux.
jpb jpbicon_post
merci nico de t'être penché sur ce problème teigneux... je testerai ta soluce dès que je me remet au fourneaux !!!
L'eau goutte à goutte finit toujours par percer la pierre.
Visiteur Visiteuricon_post
DejaVuSans.ttf https://www.fontsquirrel.com/fonts/dejavu-sans
DejaVuSans.ttf (direct) https://github.com/senotrusov/dejavu-fonts-ttf/blob/master/ttf/DejaVuSans.ttf

https://raw.githubusercontent.com/deepin-community/fonts-wqy-zenhei/master/wqy-zenhei.ttc



case 'captcha':
$mot = decrypt($att_id); // gardez en UTF-8

// Choix de la police selon la langue
if (isset($language) && $language === 'chinese') {
$fontFile = 'fonts/wqy-zenhei.ttc';
} else {
$fontFile = 'fonts/DejaVuSans.ttf';
}

// Utilisation directe de imagettftext
$fontSize = 16;
$angle = 0;
$bbox = imagettfbbox($fontSize, $angle, $fontFile, $mot);
$width = $bbox[2] - $bbox[0] + 4;
$height = $bbox[1] - $bbox[5] + 4;
$img = imagecreate($width, $height);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagecolortransparent($img, $blanc);
$x = -$bbox[0] + 2;
$y = -$bbox[5] + 2;
imagettftext($img, $fontSize, $angle, $x, $y, $noir, $fontFile, $mot);
imagepng($img);
imagedestroy($img);
break;

 Message édité par : nicolas2 / 21/07/2026 23:30
Visiteur Visiteuricon_post
DejaVuSans.ttf couvre le latin étendu, cyrillique, grec, etc. — mais pas les idéogrammes chinois.
wqy-zenhei.ttc ("WenQuanYi Zen Hei") est spécifiquement une police chinoise — elle contient les glyphes des milliers de caractères CJK.



case 'captcha':
$mot = decrypt($att_id); // on garde en UTF-8, pas besoin de conversion ISO avec imagettftext

// Détection des caractères chinois (CJK) dans le texte, plutôt que de dépendre
// d'une variable de langue du site qui peut ne pas correspondre au texte du captcha
$fontsDir = 'fonts/'; // adapter au chemin réel du dossier fonts sur ton serveur
$fontFile = preg_match('/[\x{4e00}-\x{9fff}]/u', $mot)
? $fontsDir . 'wqy-zenhei.ttc'
: $fontsDir . 'DejaVuSans.ttf';

$fontSize = 16;
$angle = 0;
$bbox = imagettfbbox($fontSize, $angle, $fontFile, $mot);
$width = abs($bbox[2] - $bbox[0]) + 8;
$height = abs($bbox[1] - $bbox[7]) + 8;

$img = imagecreatetruecolor($width, $height);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $blanc);
imagecolortransparent($img, $blanc);

$x = -$bbox[0] + 4;
$y = -$bbox[7] + 4;
imagettftext($img, $fontSize, $angle, $x, $y, $noir, $fontFile, $mot);

imagepng($img);
imagedestroy($img);
break;
Visiteur Visiteuricon_post
Mets les deux polices dans le dossier fonts/ et teste.



<?php

Mets les deux polices dans le dossier fonts/ et teste.

header('!content-type:! image/png');

if ($_GET['page'] == 'chinois') {
$mot = "四 + 3 = "; // texte chinois codé en dur pour le test
$fontsDir = 'fonts/';

$fontFile = preg_match('/[\x{4e00}-\x{9fff}]/u', $mot)
? $fontsDir . 'wqy-zenhei.ttc'
: $fontsDir . 'DejaVuSans.ttf';

$fontSize = 16;
$angle = 0;
$bbox = imagettfbbox($fontSize, $angle, $fontFile, $mot);
$width = abs($bbox[2] - $bbox[0]) + 8;
$height = abs($bbox[1] - $bbox[7]) + 8;

$img = imagecreatetruecolor($width, $height);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $blanc);
imagecolortransparent($img, $blanc);

$x = -$bbox[0] + 4;
$y = -$bbox[7] + 4;
imagettftext($img, $fontSize, $angle, $x, $y, $noir, $fontFile, $mot);

imagepng($img);
imagedestroy($img); // depuis PHP 8.0, imagedestroy() n'a plus aucun effet — depuis PHP 8.0, l'extension GD utilise des objets au lieu de ressources, et les objets ne peuvent pas être fermés explicitement. Et cette fonction a été officiellement dépréciée à partir de PHP 8.5, ce qui déclenche maintenant un warning si tu es sur PHP 8.5+
if (PHP_VERSION_ID < 80000) {
imagedestroy($img);
}
} else {
$mot = "四 + 3 = "; // même texte chinois codé en dur, pour comparaison directe

$font = 16;
$width = imagefontwidth($font) * strlen($mot);
$height = imagefontheight($font);

$img = imagecreate($width + 4, $height + 4);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagecolortransparent($img, $blanc);

imagestring($img, $font, 1, 1, $mot, $noir);

imagepng($img);
if (PHP_VERSION_ID < 80000) {
imagedestroy($img);
}
}


Normalement, après ça, ton captcha chinois devrait être ok et opérationnel.
Visiteur Visiteuricon_post
Visiteur Visiteuricon_post
donc dans ton getfile.php



case 'captcha':
$mot = decrypt($att_id); // on garde en UTF-8, pas besoin de conversion ISO avec imagettftext

// Détection des caractères chinois (CJK) dans le texte, plutôt que de dépendre
// d'une variable de langue du site qui peut ne pas correspondre au texte du captcha
$fontsDir = 'fonts/'; // adapter au chemin réel du dossier fonts sur ton serveur

$fontFile = preg_match('/[\x{4e00}-\x{9fff}]/u', $mot)
? $fontsDir . 'wqy-zenhei.ttc'
: $fontsDir . 'DejaVuSans.ttf';

$fontSize = 16;
$angle = 0;
$bbox = imagettfbbox($fontSize, $angle, $fontFile, $mot);
$width = abs($bbox[2] - $bbox[0]) + 8;
$height = abs($bbox[1] - $bbox[7]) + 8;

$img = imagecreatetruecolor($width, $height);
$blanc = imagecolorallocate($img, 255, 255, 255);
$noir = imagecolorallocate($img, 0, 0, 0);
imagefill($img, 0, 0, $blanc);
imagecolortransparent($img, $blanc);

$x = -$bbox[0] + 4;
$y = -$bbox[7] + 4;
imagettftext($img, $fontSize, $angle, $x, $y, $noir, $fontFile, $mot);

imagepng($img);

// depuis PHP 8.0, imagedestroy() n'a plus aucun effet —
// depuis PHP 8.0, l'extension GD utilise des objets au lieu de ressources,
// et les objets ne peuvent pas être fermés explicitement.
// Et cette fonction a été officiellement dépréciée à partir de PHP 8.5,
// ce qui déclenche maintenant un warning si tu es sur PHP 8.5+
imagedestroy($img);
if (PHP_VERSION_ID < 80000) {
imagedestroy($img);
}
break;
 Message édité par : nicolas2 / 21/07/2026 23:32