Récemment, j'ai découvert un bogue dans BlogoText. La ligne incriminée est :

$token = (isset($_POST['token'])) ? $_POST['token'] : (isset($_GET['token'])) ? $_GET['token'] : 'false';

Soit :

$token =
    isset($_POST['token']) ?
        $_POST['token'] :
        isset($_GET['token']) ?
            $_GET['token'] :
            'false';

Il s'agit d'une imbrication de conditions ternaires. Comme le dit la documentation, l'expression (expr1) ? (expr2) : (expr3) est évaluée à expr2 si expr1 est évaluée à TRUE, et expr3 si expr1 est évaluée à FALSE.

operateur-ternaire.png

Ici l'auteur désire récupérer le token envoyé par la méthode POST, ou sinon GET.
En situation réelle, $_POST contient bien une entrée token, donc nous devrions avoir $_POST['token']. Hors, l'expression ci-dessus retournera NULL... Voyons pourquoi.


L'expression ternaire est évaluée de gauche à droite, pour que ça soit plus clair :

$token =
    isset($_POST['token']) ?
        'a' :
        isset($_GET['token']) ?
            'b' :
            isset($_SESSION['token']) ?
                'c' :
                isset($je_suis_un_crack) ?
                    'd':
                    FALSE;

Que vaut $token dans cet l'exemple ?
En théorie 'a', puisque $_POST['token'] existe. Au lieu de ça, $token vaut 'd'. Si je remplace isset($_POST['token']) par !isset($_POST['token']), $token faudra FALSE.

Pour simplifier, les expressions du milieu sont ignorées. On aura le résultat de la dernière expression :

$token =
    isset($_POST['token']) ?
        //'a' :
        //isset($_GET['token']) ?
            //'b' :
            //isset($_SESSION['token']) ?
                //'c' :
                //isset($je_suis_un_crack) ?
                    'd':
                    FALSE;

Revenons-en à nos moutons, pourquoi NULL est renvoyé ? Car $_POST['token'] existe bel et bien, donc d'après la suite de l'expression, on retourne $_GET['token'], qui n'existe pas, donc NULL. D'ailleurs, en activant l'affichage des erreurs, on a bien un averto :
Notice: Undefined index: token in inc/veri.php on line 160

Pour corriger le problème, il suffit d'ajouter des parenthèses, comme en maths :

$token = isset($_POST['token']) ? $_POST['token'] : (isset($_GET['token']) ? $_GET['token'] : 'false');

Soit :

$token =
    isset($_POST['token']) ?
        $_POST['token'] :
        (isset($_GET['token']) ?
            $_GET['token'] :
            'false');