[RESOLU] Requête préparée qui ne fonctionne pas "Invalid parameter number"

Petit nouveau ! | 2 Messages

15 sept. 2019, 21:35

Bonjour,
J'ai un formulaire de recherche qui interroge une table contenant des interviews et plusieurs tables d'association listant les communes, les périodes et les thématiques citées dedans.
Lorsque je fais une recherche avec seulement une de ces tables, ça marche, par contre ça ne marche pas lorsque je veux interroger à la fois deux ou trois tables...
j'obtiens le message d'erreur suivant : Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number in D:\wamp64\www\interviews\resultats.php on line 136
Je ne comprends pas d'où ça vient, si quelqu'un peut m'éclairer, merci d'avance !

Code du formulaire :

Code : Tout sélectionner

<form method="post" action="resultats.php"> <fieldset> <h5>Recherche par mots-clés</h5> <p> <label for="motscles">Saisissez votre recherche</label> : <input type="text" name="motscles" id="motscles" /> </p> </fieldset> <br /> <details> <summary><strong>Recherche avancée</strong>&nbsp;<em>(cliquez pour afficher / masquer les options)</em></summary> <fieldset> <h5>Communes</h5> <em>(du territoire de l'Agglo)</em> <p style="font-size: small;"> </p> <div class="options-recherche"> <div class="flex"> <ul class="liste-recherche"> <li><label><input type="checkbox" name="communes[]" value="Champenard" />&nbsp;Champenard</label></li> <li><label><input type="checkbox" name="communes[]" value="Les-Trois-Lacs" />&nbsp;Les-Trois-Lacs</label></li> <li><label><input type="checkbox" name="communes[]" value="Saint-Didier-des-Bois" />&nbsp;Saint-Didier-des-Bois</label></li> <li><label><input type="checkbox" name="communes[]" value="Villers-sur-le-Roule" />&nbsp;Villers-sur-le-Roule</label></li> <li><label><input type="checkbox" name="communes[]" value="Vironvay" />&nbsp;Vironvay</label></li> <li><label><input type="checkbox" name="communes[]" value="Vraiville" />&nbsp;Vraiville</label></li> </ul> </div> </div> </fieldset> <fieldset> <h5>Périodes</h5> <div class="options-recherche"> <div class="flex"> <ul class="liste-recherche"> <li><label><input type="checkbox" name="periodes[]" value="1900-1914" />&nbsp;1900-1914</label></li> <li><label><input type="checkbox" name="periodes[]" value="Première Guerre mondiale" />&nbsp;Première Guerre mondiale</label></li> <li><label><input type="checkbox" name="periodes[]" value="Entre deux guerres" />&nbsp;Entre deux guerres</label></li> <li><label><input type="checkbox" name="periodes[]" value="Seconde Guerre mondiale" />&nbsp;Seconde Guerre mondiale</label></li> <li><label><input type="checkbox" name="periodes[]" value="Années 1950" />&nbsp;Années 1950</label></li> <li><label><input type="checkbox" name="periodes[]" value="Années 1960" />&nbsp;Années 1960</label></li> <li><label><input type="checkbox" name="periodes[]" value="Années 1970" />&nbsp;Années 1970</label></li> <li><label><input type="checkbox" name="periodes[]" value="1980 à nos jours" />&nbsp;1980 à nos jours</label></li> </ul> </div> </div> </fieldset> <fieldset> <h5>Thématiques</h5> <div class="options-recherche"> <div class="flex"> <ul class="liste-recherche"> <li><label><input type="checkbox" name="thematiques[]" value="Faune" />&nbsp;Faune</label></li> <li><label><input type="checkbox" name="thematiques[]" value="Flore" />&nbsp;Flore</label></li> <li><label><input type="checkbox" name="thematiques[]" value="Histoire" />&nbsp;Histoire</label></li> <li><label><input type="checkbox" name="thematiques[]" value="Légendes" />&nbsp;Légendes</label></li> <li><label><input type="checkbox" name="thematiques[]" value="Vie quotidienne" />&nbsp;Vie quotidienne</label></li> </ul> </div> </div> </fieldset> <fieldset> <h5>Options</h5> <div class="options-recherche"> <p> Tous les témoignages ont une version texte. Presque tous ont une version audio et une version vidéo, en fonction de l'accord des témoins.<br /> De nombreux témoins présentent des documents (photos, archives, etc.) dans leur témoignage. </p> Vous pouvez ici filtrer la recherche en fonction de ces critères. </p> <p class="titre-opt-rech"><strong>Vidéo</strong></p> <ul class="liste-recherche"> <li><label><input type="radio" name="avecVideo" value="-99" checked="checked" />&nbsp;Afficher tous les résultats</label></li> <li><label><input type="radio" name="avecVideo" value="1" />&nbsp;Vidéo obligatoire</label></li> <li><label><input type="radio" name="avecVideo" value="0" />&nbsp;Résultats sans vidéo</label></li> </ul> <p class="titre-opt-rech"><strong>Audio</strong></p> <ul class="liste-recherche"> <li><label><input type="radio" name="avecAudio" value="-99" checked="checked" />&nbsp;Afficher tous les résultats</label></li> <li><label><input type="radio" name="avecAudio" value="1" />&nbsp;Audio obligatoire</label></li> <li><label><input type="radio" name="avecAudio" value="0" />&nbsp;Résultats sans audio</label></li> </ul> <p class="titre-opt-rech"><strong>Documents</strong></p> <ul class="liste-recherche"> <li><label><input type="radio" name="avecDocuments" value="-99" checked="checked" />&nbsp;Afficher tous les résultats</label></li> <li><label><input type="radio" name="avecDocuments" value="1" />&nbsp;Documents présentés obligatoires</label></li> <li><label><input type="radio" name="avecDocuments" value="0" />&nbsp;Résultats sans documents présentés</label></li> </ul> </div> </fieldset> </details> <br /> <p style="text-align: center;"><input type="submit" value="Valider" id="valider" /></p>

Code de la page qui traite le formulaire :

Code : Tout sélectionner

try { $pdo = new PDO('mysql:host=localhost;dbname=interviews;charset=utf8', 'root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ]); } catch(Exception $e) { die('Erreur : '.$e->getMessage()); } $where = []; $data = []; // types de données pour PDO // construction de la clause WHERE // traitement de la section "mots-clés" if (isset($_POST['motscles'])) { $data[':motscles'] = '%'.$_POST['motscles'].'%'; $where[] = 'i.retranscription LIKE :motscles'; } // traitement des trois critères d'indexation // générateur de tag PDO $tag = function(): string { // majuscule minuscule digit return ':'.chr(mt_rand(65, 90)).chr(mt_rand(97, 122)).mt_rand(1, 1000); }; $where_in = []; // traitement de la section "Communes" if (isset($_POST['communes'])) { foreach ($_POST['communes'] as $comm) { $t = $tag(); $data[$t] = $comm; $where_in[] = $t; } $where[] = ' c.nom IN ('.implode(',', $where_in).')'; } // traitement de la section "Périodes" if (isset($_POST['periodes'])) { foreach ($_POST['periodes'] as $per) { $t = $tag(); $data[$t] = $per; $where_in[] = $t; } $where[] = ' p.nom IN ('.implode(',', $where_in).')'; } // traitement de la section "Thématiques" if (isset($_POST['thematiques'])) { foreach ($_POST['thematiques'] as $mat) { $t = $tag(); $data[$t] = $mat; $where_in[] = $t; } $where[] = ' m.nom IN ('.implode(',', $where_in).')'; } // traitement de la section "Options" $choix = [0, 1]; if (isset($_POST['avecVideo'], $choix[$_POST['avecVideo']])) { $where[] = "i.video = {$choix[$_POST['avecVideo']]}"; } if (isset($_POST['avecAudio'], $choix[$_POST['avecAudio']])) { $where[] = "i.audio = {$choix[$_POST['avecAudio']]}"; } if (isset($_POST['avecDocuments'], $choix[$_POST['avecDocuments']])) { $where[] = "i.documents = {$choix[$_POST['avecDocuments']]}"; } // écriture de la clause WHERE $where = empty($where) ? '' : ' WHERE '. implode(' AND ', $where); // préparation puis exécution de la requête $sql = <<<sql SELECT GROUP_CONCAT( DISTINCT CONCAT(t.civilite, ' ', t.prenom, ' ', t.nom, ', ', t.qualite) ORDER BY t.nom SEPARATOR ' ~~ ') AS groupe, i.id, i.nom_fichier FROM temoins t INNER JOIN asso_temoins as at ON at.temoin_id = t.id INNER JOIN temoignages i ON i.id = at.temoignage_id LEFT JOIN asso_communes ac ON ac.temoignage_id = i.id LEFT JOIN communes c ON c.id = ac.commune_id LEFT JOIN asso_periodes ap ON ap.temoignage_id = i.id LEFT JOIN periodes p ON p.id = ap.periode_id LEFT JOIN asso_matieres am ON am.temoignage_id = i.id LEFT JOIN matieres m ON m.id = am.matiere_id {$where} GROUP BY i.id ORDER BY i.nom_fichier sql; $stmt = $pdo->prepare($sql); $exec = $stmt->execute($data); $data = $stmt->fetchAll(); // affichage des résultats if (empty($data)) { echo 'Aucun résultat<br /><a href="recherche.php">Nouvelle recherche</a>'; } else { $nb = count($data); echo '<p>', $nb, ' résultat', ($nb > 1) ? 's' : '', '&nbsp;:</p>'; // échappement des caractères dangereux $hsc = function($p) { return htmlspecialchars($p, ENT_QUOTES, 'utf-8'); }; foreach ($data as $v) { echo <<<html <p><a href="temoignage.php?id={$v['id']}">Témoignage de&nbsp;{$hsc($v['groupe'])}</a></p> html; } } ?>