utilisation de rand

Eléphanteau du PHP | 31 Messages

14 mars 2022, 11:14

bonjour,
J'ai un quiz que j'ai fait.
Mon problème est que les questions reviennent plusieurs fois or je souhaiterais que la question ne revienne qu'une seule fois.

Code : Tout sélectionner

include("configu.php"); $sql = 'SELECT * from equation WHERE ecoleq= "'.$_SESSION['ecoles'].'" AND classeq= "'.$_SESSION['classe'].'" AND matiereq= "'.$matiere.'" AND activationq= "'.$yes.'" ORDER BY RAND() LIMIT 0,1 '; foreach ($bdd->query($sql) as $data) { echo ' <input type="hidden" name="titre" size=70 value="'.stripslashes ($data['titreq']).'" ><br> <big style="font-weight: bold;"><span style="color: rgb(204, 0, 0);"> '.stripslashes ($data['question']).'</span></big> <input type="hidden" name="question" size=70 value="'.stripslashes (trim($data['question'])).'" ><br> <input type="radio" name="reponse" value="'.stripslashes ($data['rep1']).'" > '.stripslashes (trim($data['rep1'])).'<br> <input type="radio" name="reponse" value="'.stripslashes ($data['rep2']).'" >'.stripslashes (trim($data['rep2'])).'<br> <input type="radio" name="reponse" value="'.stripslashes ($data['rep3']).'" >'.stripslashes (trim($data['rep3'])).'<br> <input type="hidden" name="vraie" size=70 value="'.stripslashes (trim($data['repvraie'])).'" > <hr> '; //fin de foreach }

ynx
Mammouth du PHP | 586 Messages

14 mars 2022, 20:02

Bonjour,

Difficile de donner une réponse précise par rapport à ton code car on a qu'un extrait sans aucun contexte.
Il n'y a qu'une seule question à chaque chargement de la page ?
Tu enregistres les réponses via un formulaire qui est traité en PHP ? Ou tu affiches les réponses directement en javascript (d'où le input hidden) ?

En PHP, Une solution possible serait d'enregistrer (en session ou en bdd) les questions qui sont déjà passées afin de les exclure dans la requête sql (via une condition NOT IN par exemple).

Eléphanteau du PHP | 31 Messages

14 mars 2022, 23:19

Ta solution est une bonne idée mais je souhaiterais l'enregistrer en session pour ne pas bourrer ma base de données.
Alors Je souhaiterais faire quelque chose comme ceci selon ta proposition:
$disable_equations = [15,23,50];

$sql = 'SELECT * from equation WHERE activationq= "'.$yes.'" AND id NOT IN ("'.explode(',',$disable_equations).'") ORDER BY RAND() LIMIT 0,1';
Mais je ne sais pas comment enregistrer plusieurs variables dans une session et l'utiliser après.

ynx
Mammouth du PHP | 586 Messages

16 mars 2022, 20:05

Pour utiliser la session, il faut donc enregistrer le tableau des equations à exlure dans une variable de session ($_SESSION).
Par exemple dans ton script, commence par initialiser ce tableau si il n'existe pas :
if (!isset($_SESSION['disable_equations'])) {
    $_SESSION['disable_equations'] = [];
}

Pour utiliser ce tableau dans une condition sql NOT IN, il faut plutôt utiliser la fonction implode pour transformer le tableau en une chaine de caractère (l'inverse de la fonction explode).
Il ne faut pas de guillemet autour de la liste : id NOT IN (1,2,3) au lieu de id NOT IN ("1,2,3")
$sql = 'SELECT * from equation WHERE activationq= "'.$yes.'" AND id NOT IN ('.implode(',', $_SESSION['disable_equations']).') ORDER BY RAND() LIMIT 0,1';

Il faut aussi penser à vérifier si le tableau contient au moins un élément pour ajouter la condition sql NOT IN, puisque si le tableau est vide, la condition sera alors sous la forme id NOT IN () ce qui va surement déclencher une erreur sql.
$sql = 'SELECT * from equation WHERE activationq= "'.$yes.'" ';

if (count($_SESSION['disable_equations']) > 0) {
    $sql .= 'AND id NOT IN ('.implode(',', $_SESSION['disable_equations']).') ';
}

$sql .= 'ORDER BY RAND() LIMIT 0,1';

Concernant la sécurité : tu devrais utiliser une requête préparée avec des paramètres au lieu de concaténer directement les variables PHP $_SESSION['ecoles'], $matiere, $yes, etc.
Tu risques en effet une injection sql. Outre les éventuelles erreurs que ceci pourrait causer, si les variables PHP sont modifiables par l'utilisateur, un internaute malintentionné pourrait facilement extraire toutes les données ou supprimer ta base.

Sauf erreur de ma part, il n'est pas possible d'utiliser simplement un paramètre d'une requête préparée pour réaliser la condition sql NOT IN avec la fonction implode, car il faudrait un paramètre par identifiant (mais j'insiste, tu devrais utiliser une requête préparée avec des paramètres pour les autres conditions sql).
Puisque le tableau ne doit contenir que des nombres entiers (id), une manière simple pour éviter les injections sql dans ce cas est d'appliquer la fonction intval sur chaque élément du tableau. Pour appliquer cette fonction sur chaque élément, on peut utiliser la fonction array_map.
$sql = 'SELECT * from equation WHERE activationq= "'.$yes.'" ';

if (count($_SESSION['disable_equations']) > 0) {
    $sql .= 'AND id NOT IN ('.implode(',', array_map('intval', $_SESSION['disable_equations'])).') ';
}

$sql .= 'ORDER BY RAND() LIMIT 0,1';

Autre remarque au passage; Pour afficher une variable PHP dans du code HTML, tu devrais plutôt utiliser la fonction htmlspecialchars (ou htmlentities) à la place de stripslashes.
Attention, si tu as déjà appliqué htmlspecialchars/htmlentities sur les données avant de les insérer en bdd, il ne faut alors pas réutiliser ces fonctions à l'affichage.

Enfin, pour enregistrer les id à exclure dans le tableau, à partir de ton extrait de code, on peut éventuellement ajouter l'id de l'équation dans le tableau lors de l'affichage de l'équation :
foreach ($bdd->query($sql) as $data) {
    $_SESSION['disable_equations'][] = $data['id'];

    echo '<input...';
}
A voir si cela convient : avec cette solution, si l'utilisateur recharge la page sans répondre à l'équation, celle-ci sera tout de même exclue.
Si tu traites les réponses en PHP (via un formulaire par exemple), il serait p-e mieux d'ajouter l'id de l'équation à exclure dans le tableau lorsque l'utilisateur donne la bonne réponse.

Eléphanteau du PHP | 31 Messages

18 mars 2022, 13:28

Merci pour ce précieux temps que tu m'as accordé! Je te reviens.