IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[PHP 8.3] La fonction mb_strlen donne un résultat différent en PHP 8.2 et 8.3


Sujet :

Langage PHP

  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut [PHP 8.3] La fonction mb_strlen donne un résultat différent en PHP 8.2 et 8.3
    Bonjour,

    Pour un code source et des entrants identiques, j'observe une différence de résultat avec la fonction mb_strlen entre PHP 8.2 et PHP 8.3.

    En PHP 8.2.14, j'ai loggé les éléments suivants :
    mb_internal_encoding() = UTF-8
    mb_strlen(c•,¼D•KK“Z`2=iĉÁ¹óM£) = 20

    En PHP 8.3.2 :
    mb_internal_encoding() = UTF-8
    mb_strlen(c•,¼D•KK“Z`2=iĉÁ¹óM£) = 24

    Dans les deux cas, l'encodage pris en compte est UTF-8. La chaîne est visiblement la même (et de plus, elle est issue de la même donnée entrante et passée par le même code source). Mais, dans un cas, la longueur calculée par mb_strlen est 20 et, dans l'autre, 24.

    Je n'arrive pas à déterminer ce qui expliquerait cette différence. Je n'observe pas d'écart de configuration (même version d'Apache 2.4.58.1 dans les deux cas). Rien d'évident non plus dans le changelog des versions PHP.

    Le problème se pose dans le cadre d'une vérification de mot de passe qui, par conséquent, ne fonctionne plus en PHP 8.3.2.

    Quelqu'un aurait-il une idée sur ce qui peut poser cette situation ? Ou sur les points à vérifier pour identifier cet écart de fonctionnement ?


    Merci d'avance.

  2. #2
    Membre éclairé
    Homme Profil pro
    Urbaniste
    Inscrit en
    Août 2023
    Messages
    386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Août 2023
    Messages : 386
    Points : 788
    Points
    788
    Par défaut
    https://github.com/php/php-src/issues/12556 ?

    ceci n'est pas vraiment en rapport, mais j'ai trouvé intéressant la partie sur le scrub, et je me suis demandé si ça ne pourrait pas aider, aucune certitude.

    https://github.com/php/php-src/issues/13198

    Here's another tip: If your application expects to receive UTF-8 text as input, it may be a good idea to check input strings with mb_check_encoding($str, 'UTF-8') before operating on them. If mb_check_encoding shows that the input is not UTF-8, the safest thing to do is to reject it. However, if you want to be more tolerant of unexpected inputs, you could use mb_scrub to sanitize the invalid string. Before calling mb_scrub, you may want to set mb_substitute_character to control what will happen with invalid byte sequences... for example, if you set mb_substitute_character("none"), then the invalid bytes will be deleted from the string, rather than being replaced with "?".

  3. #3
    Membre confirmé
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 321
    Points : 642
    Points
    642
    Par défaut
    Bonjour,

    A priori le résultat est identique (24) en PHP 8.2.14 et PHP 8.3.1 : https://onlinephp.io/c/b00b4

  4. #4
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Merci pour vos réponses.

    @unanonyme : Merci pour les liens. C'est intéressant et peut-être pas sans rapport. Notamment, cette phrase m'interpelle :
    UTF-8 text handling now obeys the W3C specification, and this may result in different output for invalid UTF-8 strings.
    Je vais creuser ça.

    @Pytet : Oui, j'avais vu sur des sandboxes en ligne que le résultat ne différait pas entre les deux versions. Donc je ne mets pas en cause PHP.
    Mais le fait est que j'observe cet écart sur mon projet et que j'aimerais le comprendre. Soit cela vient spécifiquement du fait que je travaille sous OS Windows, soit il y a un paramètre quelque part qui diffère, peut-être lié à l'encodage.

  5. #5
    Membre confirmé
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 321
    Points : 642
    Points
    642
    Par défaut
    Tu peux procéder par élimination. Passe ton environnement 8.3.2 en 8.2.14 et refait ton test : tu verras si le problème vient de la version de PHP ou de ton environnement.

    Si le problème ne viens pas du changement de version PHP, il semble alors que les chaines comparées via mb_strlen ne soient visiblement pas les mêmes
    Difficile de deviner sans plus de détails (tu évoques une vérification de mot de passe, la chaine est récupérée depuis une base de données ? Les 2 environnements PHP se connectent à la même bdd ou 2 SGBD distincts ?)

  6. #6
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Alors, pour préciser le contexte, je travaille sur un environnement construit avec le logiciel WAMP. Le test est effectivement fait en passant d'une version 8.2.14 à une version 8.3.2 avec les outils de WAMP. Le reste de l'environnement ne change pas : même serveur Apache, même base de données.

    Sur le traitement, il s'agit du processus d'authentification. L'utilisateur saisit son mot de passe et le problème se pose pendant la comparaison des hash (hashage de la saisie, comparé avec le hash stocké dans la base de données).

    Je saisis le même mot de passe, il passe par le même code source.

    La différence de mb_strlen apparaît sur le hash enregistré dans la base de données (si cela peut jouer, celui-ci passe au préalable par un base64_decode). Il s'agit donc de la même chaîne de caractères initiale.

    Cette différence est bloquante, car le résultat est utilisé pour le hashage du mot de passe saisi.


    Note : Je découvre le processus d'authentification de l'application concernée avec ce problème, car il s'agit d'un aspect historique qui n'a jamais posé de problème jusqu'ici et auquel je n'avais pas encore touché.

  7. #7
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Pour information, le problème est résolu.

    Il était dû à l'utilisation de la fonction mb_strlen dans l'algorithme de hashage, alors qu'il fallait utiliser strlen (pour compter la longueur en bytes, et non en caractères).

    Il n'en reste pas moins qu'il y a un réel écart dans mon environnement sur les résultats fournis par mb_strlen sur une même chaîne issu d'un décodage base 64 d'une même valeur dans une même base de données. La correction permet de contourner les effets de cette différence, mais finalement, le point étonnant est que cela fonctionnait en l'état jusqu'en PHP 8.2.

  8. #8
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    À ma connaissance, mb_strlen avec mb_internal_encoding réglé sur UTF-8 a des problèmes de consistance dés lors que la chaîne qu'on lui fournit contient des séquences d'octets invalides pour toutes les versions de PHP inférieures à 8.3. Cela semble avoir été corrigé avec la version 8.3, maintenant une séquence invalide dans une chaîne est comptée comme un caractère (non identifié mais un caractère quand même) et le comptage continu dés le prochain début de séquence (valide ou pas), et ce, quelque soit sa position dans la chaîne. Ce n'était pas le cas avec les versions précédentes.

    Tu peux apprécier l'ampleur du désastre avec ce petit test à essayer sur 8.3 et une version précédente:

    demo

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    echo mb_internal_encoding(), "\n\n\n";
     
    /* premier test: on convertit en ISO-8859-1 pour produire des séquences UTF-8 invalides.
       Bien entendu, comme mb_internal_encoding est UTF-8, c'est dans cette encodage que
       mb_strlen va tenter de les lire.
       On remarque l'incohérence des résultats pour PHP < 8.3, résultats qui dépendent de la
       localisation du caractère  dans la chaîne.
    */
     
    $test1 = [ 'mAm', 'mÂ', 'mÂm', 'mÂÂm' ];
     
    echo "test 1:\n\n";
     
    foreach ($test1 as $s) {
        printf(
            "%s:\n    UTF-8: %d    ISO-8859-1: %d\n",
            $s,
            mb_strlen($s),
            mb_strlen(mb_convert_encoding($s, 'ISO-8859-1', 'UTF-8'))
        );
    }
     
    echo "\n\n\n";
     
    /* ici on teste  le caractère U+2030 ‰ e2 80 b0 PER MILLE SIGN, on interrompt sa séquence et
       on essaie différents cas de figure pour la suite.
    */
    $test2 = ["\xe2\x80\xb0", "\xe2\x80", "\xe2\x80L", "\xe2\x80\xe2\x80", "\xe2\x80LL"];
     
    echo "test 2:\n\n";
     
    foreach ($test2 as $s) {
        printf(
            "%s:    UTF-8: %d\n",
            $s,
            mb_strlen($s)
        );
    }
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #9
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Merci pour la précision.

    Effectivement, cela doit être l'explication.

  10. #10
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Mais ça veut aussi dire que tes chaînes que tu crois être en UTF-8 ne le sont pas. Pour en avoir le cœur net, affiche leurs octets:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for ($i=0; $i < strlen($str); $i++) {
        echo dechex(ord($str[$i])), ' ';
    }
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  11. #11
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Voici ce que cela donne sur la chaîne de caractères de mon cas de test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ae 1c 85 8a 53 30 77 81 35 7f fb e3 29 99 29 ea 57 12 18 f5 ad 2e cf 82
    On est sur le hash d'un mot de passe, donc cela ne m'étonnerait pas que cela ne soit pas spécifiquement de l'UTF-8.

  12. #12
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    On est sur le hash d'un mot de passe, donc cela ne m'étonnerait pas que cela ne soit pas spécifiquement de l'UTF-8.
    Oui ça a du sens, et tu as fait ce qu'il fallait en comptant les octets avec strlen plutôt qu'en tentant de compter les caractères.


    Code txt : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    ae     octet de continuation orphelin
    1c     U+001C  <control> FS (File Separator)
    85     octet de continuation orphelin
    8a     octet de continuation orphelin
    53     U+0053  LATIN CAPITAL LETTER S
     
    30     U+0030  DIGIT ZERO
    77     U+0077  LATIN SMALL LETTER W
    81     octet de continuation orphelin
    35     U+0035  DIGIT FIVE
    7f     U+007F  <control> DEL
     
    fb     octet invalide
    e3     séquence interrompue
    29     U+0029  RIGHT PARENTHESIS
    99     octet de continuation orphelin
    29     U+0029  RIGHT PARENTHESIS
     
    ea     séquence interrompue
    57     U+0057  LATIN CAPITAL LETTER W
    12     U+0012  <control> DC2 (Device Control 2)
    18     U+0018  <control> CAN (Cancel)
    f5     octet invalide
     
    ad     octet de continuation orphelin
    2e     U+002E  FULL STOP
    cf 82  U+03C2  GREEK SMALL LETTER FINAL SIGMA

    mb_strlen renvoie 23 avec PHP 8.3 et 19 pour les versions précédentes du fait des deux séquences interrompues qui sont mal gérées.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  13. #13
    Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2019
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2019
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Un grand merci pour les explications.

    Au moins, maintenant, tout est clair.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 29/06/2009, 14h50
  2. [VBA] fonction qui donne la valeur présente dans une table
    Par zanou666 dans le forum VBA Access
    Réponses: 7
    Dernier message: 25/09/2007, 17h33
  3. fonction qui donne le nom de la racine
    Par muad'dib dans le forum Windows
    Réponses: 4
    Dernier message: 24/05/2007, 11h40
  4. Réponses: 1
    Dernier message: 06/03/2007, 10h55
  5. Réponses: 4
    Dernier message: 28/10/2005, 16h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo