Construction requete SQL et select multiple

Résolu/Fermé
saudek - 20 sept. 2008 à 01:08
kryoportail Messages postés 222 Date d'inscription dimanche 10 août 2008 Statut Membre Dernière intervention 22 mai 2014 - 22 sept. 2008 à 14:33
Bonjour à tous,

Nouvelle question, et j'espère, la dernière. On va dire que j'abuse :)

J'ai donc une page PHP dans la quelle s'affiche une liste d'adhérents. Cette liste est obtenue par la construction, on va dire dynamique, d'une requete SQL. Cette requête est construite par concaténation à l'aide d'un formulaire.

Le soucis est que j'aimerais pouvoir utiliser, parmi les différents éléments du formulaire, ue liste déroulante à selection multiple. Seulement, à l'image des autres éléments du formulaire j'aimerais pouvoir ajouter LES différentes sélections dans ma requête SQL.
Etant donné qu'il y a 29 sélection possible, des SI sont impensables à mon avis.
J'ai donc pensé à utiliser un array, ca fonctionne mais je n'arrive pas à insérer les OR entre mes valeurs, je n'ai que des AND.
Vous allez mieux comprendre avec l'extrait de script ci-dessous.

Ma question est : Avez vous une idée comment insérer des OR à la place des AND entre chaque canton='blabla' dans le cas de selections multiples dans la liste déroulante.
D'avance merci à vous pour votre aide.

Le code :
<?php
$host="";
$user="";
$pass="";
$database="";
$canton=array();
$canton=($_POST['canton']);
$nom=($_POST['nom']);
$circonscription=($_POST['circonscription']);
$comitedepartemental=($_POST['comitedepartemental']);
$bureau=($_POST['bureau']);
$deleguedecanton=($_POST['deleguedecanton']);
$AJ=($_POST['AJ']);
$POJP=($_POST['POJP']);
$cotisation=($_POST['cotisation']);
$tri=($_GET['tri']);
$connect=mysql_connect($host,$user,$pass) or die('Base de données indisponible : ' . mysql_error());
mysql_select_db($database) or die('Base de données non trouvée');
$query="select * FROM adherents WHERE 1=1 ";
if (is_array($canton))
foreach ($canton as $valeur)
{
if ($valeur !='') {
$query .=' AND `Canton`="'.$valeur.'"';
$canton2=''.$valeur.'';
}
}
if ($nom!='') {
$query .=' AND `Nom` LIKE "'.$nom.'"';
$nom2=''.$nom.'';
}
if ($circonscription!='') {
$query .=' AND `Circonscription`="'.$circonscription.'"';
$circonscription2=''.$circonscription.'';
}
if ($comitedepartemental!='') {
$query .=' AND `Comité Départemental`="'.$comitedepartemental.'"';
$comitedepartemental2=''.$comitedepartemental.'';
}
if ($bureau!='') {
$query .=' AND `Bureau`="'.$bureau.'"';
$bureau2=''.$bureau.'';
}
if ($deleguedecanton!='') {
$query .=' AND `Délégué Canton`="'.$deleguedecanton.'"';
$deleguecanton2=''.$deleguedecanton.'';
}
if ($AJ!='') {
$query .=' AND `AJ`="'.$AJ.'"';
$AJ2=''.$AJ.'';
}
if ($POJP!='') {
$query .=' AND `POJP`="'.$POJP.'"';
$POJP2=''.$POJP.'';
}
if ($cotisation!='') {
$query .=' AND `2008`!=""';
$cotisation2=''.$cotisation.'';
}
if ($tri !='') {$query .=' ORDER BY '.$tri.'';}
$result = mysql_query($query) or die('Probleme avec les tables de données' . mysql_error());
$nb_enreg = mysql_num_rows($result);
?>

Le nom du select à selections multiple est donc "canton" dans notre cas.
Les variables $....2 et $tri n'ont pas de rapport avec le problème posé.

9 réponses

kryoportail Messages postés 222 Date d'inscription dimanche 10 août 2008 Statut Membre Dernière intervention 22 mai 2014 125
20 sept. 2008 à 21:35
Re !

Sans vouloir être lourd... (tu fais ce que tu veux !)
Comme l'a précisé Olivier, certes c'est un gros problème de sécurité, mais aussi de fonctionnement....
Si l'utilisateur met une apostrophe dans un de tes champs, ton script se plantera inévitablement, puisque MySql ne pourra pas interprété ta requête...

Si ton problème et d'avoir des AND sauf pour le canton, tu peux modifier la première solution que j'ai énoncé en y ajoutant la tienne...

// On récupère les données
$aCantons = $_POST['canton'];
$sName=$_POST['nom'];
...
...

// On remplie le tableau en utilisant les données fournies
$aWheres = array();
if( is_array($aCantons) && count($aCantons) > 0 )
{
// Cette boucle est là pour 'protéger' les valeurs de champs dans la requête...
$aWhereCantons = array();
foreach( $aCantons as $sCanton )
{
$aWhereCantons[] = "`Canton`='" . mysql_real_escape_string($sCanton) . "'";
}
// On sélectionne tous les enregistrements pour lesquels le canton est dans la liste (plus lisible et peu être plus rapide que liste de 'OR' )...
$aWheres[] = '`Canton` IN (' . implode( ', ', $aWhereCantons) . ')';
}
if( strlen($sName) > 0 ) { $aWheres[] = "`Nom`='" . mysql_real_escape_string($sName) . "'"; }
...
...

// On génère la clause 'Where'
if( count($aWheres) > 0 ) { $sWheres = ' WHERE ' . implode( ' AND ', $aWheres ); } else { $sWheres = ''; }

// Et on forme la requête...
$SQL = 'select * FROM adherents' . $sWheres;

V'la cette fois çà devrait aller, si ta liste de canton renvoi bien un tableau !

Amicalement,
S@M...
http://kryoportail.ath.cx
2
Quel est le principe du formulaire svp ?
1
kryoportail Messages postés 222 Date d'inscription dimanche 10 août 2008 Statut Membre Dernière intervention 22 mai 2014 125
22 sept. 2008 à 14:33
Re,

Argh ! Oui c'est exacte... Bien joué !

Amicalement,
S@M...
http://kryoportail.ath.cx
1
Si j'ai bien compris tu voudrais que le contenu d'un select dépende du remplissement d'un des champs du formulaire ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
et bien le formulaire sert de filtre à l'affichage des adhérents. En méthode $_POST, le formulaire va donner des valeurs aux variables déclarées en haut du script ci dessus. Si, dans le formulaire, un champs n'est pas selectionné, il ne renvoie rien. S'il ne renvoie rien, on ne complète pas la requete de base, dans le cas contraire on complète la requete ($query). La ligne ci dessous illustre cette explication.

if ($POJP!='') {
$query .=' AND `POJP`="'.$POJP.'"'; }

La ou il faut se concentrer, c'est sur cette ligne :

if (is_array($canton))
foreach ($canton as $valeur)
{
if ($valeur !='') {
$query .=' AND `Canton`="'.$valeur.'"';
$canton2=''.$valeur.'';
}

Le problème avec le code ci dessus, c'est que dans mon select multiple, lorsque plusieurs champs sont selectionnés, la requete est complétée comme cela par exemple :
$query="select * FROM adherents WHERE 1=1 AND `canton`="blabla" AND `canton`="bloublou"";

Or moi je veux pas des AND entre les différentes valeurs de $canton, je veux des OR, mais tout en gardant les AND à la suite venant des autres champs (s'ils sont renseignés dans le form)
0
Quelques remarques :
Tu ne devrais pas avoir une suite de AND canton car seul le choix réalisé dans le select passe en valeur lors de la validation du formulaire.
Pour le nettoyage des cariables potées, comme décrit plus haut, il est impératif, au delà même d'une utilisation détournée, une faute de frappe de l'utilisateur peut entraîner un beug gênant.

Donc je dirais, à moins de n'avoir pas bien saisi le principe, qu'il faut réalisée une requête si le formulaire contient au moins un champs renseigné (le count du post précédent) executer la requête en complilant une suite de AND pour avoir les enregistrement répondant à tout les critères à la fois, ou une suite de or pour avoir les enregistrements contenant au moins un des critères. Pour ton cas il semble que tu recherches une suite de AND.
Il faudrait un message d'erreur élégant formulé en cas ou l'union des critères soit un ensemble vide.

Cordialement.
0
Merci ça fonctionne comme je veux!!
Permettez moi, cependant de modifier ceci :

$aWhereCantons[] = "`Canton`='" . mysql_real_escape_string($sCanton) . "'";

En

$aWhereCantons[] = "'" . mysql_real_escape_string($sCanton) . "'";

Sinon j'avais `canton`="quelque chose" dans la parenthèse du IN.



Merci beaucoup.
0
kryoportail Messages postés 222 Date d'inscription dimanche 10 août 2008 Statut Membre Dernière intervention 22 mai 2014 125
20 sept. 2008 à 05:06
Bonjour,

J'ai pas tout lu, mais ce que je peux dire, dans le cas qui est le tien, c'est que j'utilise cette méthode peut être effectivement plus propre ! :

// On récupère les données
$sCanton = $_POST['canton'];
$sName=$_POST['nom'];
...
...

// On remplie le tableau en utilisant les données fournies
$aWheres = array();
if( strlen($sCanton) > 0 ) { $aWheres[] = "`Canton`='" . mysql_real_escape_string($sCanton) . "'"; }
if( strlen($sName) > 0 ) { $aWheres[] = "`Nom`='" . mysql_real_escape_string($sName) . "'"; }
...
...

// On génère la clause 'Where'
if( count($aWheres) > 0 ) { $sWheres = ' WHERE ' . implode( ' OR ', $aWheres ); } else { $sWheres = ''; }

// Et on forme la requête...
$SQL = 'select * FROM adherents' . $sWheres;


Note : Ne pas oublier ques $_POST vient de l'utilisateur donc :

- Il est mieux de filtrer les données avant utilisation (par exemple en utilisant l'extension 'Filter' disponible à partir de PHP 5.2). Cf : https://www.php.net/manual/fr/intro.filter.php
- Il est primordial d'échapper les données afin d'éviter les injections SQL !!! via mysql_real_escape_string... Cf : https://www.php.net/manual/fr/function.mysql-real-escape-string.php
Image qu'un petit malin vienne rajouter dans la variable 'canton' qui est postée, des apostrophes.... Ta requête ne voudras plus rien dire, mais pire, si la variable 'canton' est bien choisie, elle peut permettre d'exécuter du code malicieux, genre un DELETE `adherents` ou un TRUNCATE `adherents`, voir un DROP `madatabase`... Bref, oui..., c'est dangereux !

Amicalement,
S@M...
http://kryoportail.ath.cx
-1
Alors je reprécise,

Le formulaire est une suite de select (6) à part 1 input text pour chercher un nom en générant la close LIKE dans la requete.
Pour les problèmes de sécurité, pas de soucis le dossier est en accès restreint, protégé par htaccess. Donc je vais pas me compléter la vie avec ça. Mias ls conseils à ce sujet sont les bienvenue merci.

Ce que je recherche, c'est insérer des OR entre les différentes valeurs de cantons tirées du array PUIS des AND pour tous les autres champs renseignés.
C'est là la difficulté, pouvoir insérer des AND et des OR dans la même requête. Donc le script gentillement donné par kryoportail ne correspond pas à ce que je veux.
Est ce que je peux utiliser la fonction implode JUSTE pour la variabe canton?
Parce que j'ai essayé de mettre OR avant canton, mais 1=1 OR quelque chose...

Je vous précise que TOUT marche, que tous les champs du formulaires s'ajoutent bien dans la requete avec des AND sauf que le select multiple génère des AND aussi avec le script que j'ai, et moi je veux des OR entre les cantons.
-1