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

PHP & Base de données Discussion :

PHP MySQL / Requête Select/Where IN(..) [PDO]


Sujet :

PHP & Base de données

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2016
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2016
    Messages : 6
    Points : 6
    Points
    6
    Par défaut PHP MySQL / Requête Select/Where IN(..)
    Bonjour à tous,

    Ceci est mon premier Post sur le forum, excusez-moi si la question a déjà été posée, mais je ne l'ai pas trouvée.
    J'essaie de construire une requête muti-critères optionnels dont pour l'un d'eux la sélection doit s'opérer sur base d'une liste de valeurs (d'où l'utilisation de la clause IN).
    La liste des valeurs est le résultat d'une sélection précédente, et cette liste est stockée dans une variable "$DossiersSelected".
    Mon problème est que lors de l'interprétation je ne retrouve pas les valeurs de la variable dans la requête mais le terme ARRAY.
    Ma question est donc : Est-il possible, dans ce type de requête, d'utiliser une variable ou la liste des valeur relatives à la clause IN doivent-elles être fixes et codées telles quelles ?

    D'avance Merci
    Philippe

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    if(!empty($_POST)) 																														
    {
    
    // Détermination de la requête à la Data Base
    		
    		$field1 = htmlentities($_POST['Ident']);
    		$field2 = htmlentities($_POST['Label']);
    		$field3 = htmlentities($_POST['DocumentEncryption']);
    		$field4 = htmlentities($_POST['DocumentStatus']);
    		$field5 = htmlentities($_POST['DocumentType']);
    		$field6 = htmlentities($_POST['DocumentSubType']);
    		$field7 = htmlentities($_POST['DocumentOwner']);
    		$field8 = htmlentities($_POST['DocumentIdent']);
    		$field9 = htmlentities($_POST['DocumentLocation']);
    
    // Preparation de la sélection 
    $Sel = "";
    if(!empty($_POST['Ident']))																								     // on demande la liaison aux dossiers 
    {	
    		// vérification que le dossier existe et récupération du label
    			$Req = "SELECT * FROM Dossiers where Ident = :Ident";
    			$Stmt = $bdd->prepare($Req);
    			$Stmt->bindParam(':Ident', $field1);
    			$Data =$Stmt->execute();
    			$Data = $Stmt->fetch();
    		
    				if(!empty($Data)) 	$_SESSION['Dossier'][0] = $field1;																// Initialisation de la pile de recherche $_SESSION['Dossier'  	
    				else $message .= " Sorry but the input for dossier ".$field1. " is not recognized by the system ";									// $Data empty donc dossier inconnu dans le système
    }	
    echo "Child  Dossier ",$_POST['ChildDossier']	;																																							
    		if ($_POST['ChildDossier']==1)																							// la demande concerne tous les dossiers "child" ( ceux dont le dossier parent == $_POST['Ident']) 
    			{																										
    			// vérification que des dossiers "child" existent et récupération de leurs Ident 
    			$ReqChild = "SELECT Ident FROM Dossiers where DossierParent  = :Ident";	
    			$Stmt = $bdd->prepare($ReqChild);
    			$Stmt->bindParam(':Ident', $field1);
    			$DataChild =$Stmt->execute();
    			$DataChild = $Stmt->fetchall();
    			
    			if(!empty($DataChild)) 																																															// construire une array $_SESSION['Dossier'] avec tous Ident et Label des dossiers "child" de ce dossier. l'élément "0" de l'array est $_POST['Ident']
    				{	
    				foreach	 ($DataChild as $RowDossier)
    					{				
    					$_SESSION['Dossier'][] =$RowDossier['Ident'] ;		
    					$Stmt = $bdd->prepare($ReqChild);				
    					$Stmt->bindParam(':Ident', $RowDossier['Ident']);
    					$DataSubChild =$Stmt->execute();
    					$DataSubChild = $Stmt->fetchall();
    					if(!empty($DataSubChild))
    						{ 
    						foreach	 ($DataSubChild as $RowSubDossier)
    						$_SESSION['Dossier'][] = $RowSubDossier['Ident'];
    						}	
    					}
    				$DossiersSelected = array_unique($_SESSION['Dossier'])	;																										
    				$Sel .= " Ident = any ( select DocumentIdent from Dossiers_Documents where DossierIdent in ".$DossiersSelected." )" ;	
    				}	
    			else $message .= " Sorry but you request all the child dossiers but there isn't any in the system ";	
    			}	
    		
    		
    // Constitution de la requête suite
    
    
    		if(!empty($_POST['DocumentEncryption'] )) $Sel .= " AND DocumentEncryption = " ."'" . $field3."'"; 
    		if(!empty($_POST['DocumentStatus'])) $Sel .= " AND DocumentStatus = "."'" . $field4. "'";
    		if(!empty($_POST['DocumentType'])) $Sel .= " AND DocumentType = "."'" . $field5. "'";
    		if(!empty($_POST['DocumentSubType'])) $Sel .= " AND DocumentSubType >= "."'" . $field6. "'";
    		if(!empty($_POST['DocumentOwner'])) $Sel .= " AND DocumentOwner = "."'" . $field7. "'";
    		if(!empty($_POST['DocumentIdent'])) $Sel .= " AND DocumentIdent = "."'" . $field8. "'";
    		if(!empty($_POST['DocumentLocationr'])) $Sel .= " AND DocumentLocation = "."'" . $field9. "'";
    		     
    			// suppression éventuelle du premier "AND" dans la chaîne des critères de sélection cas où Ident Dossier n'est pas utilisé
    		
    			$n = strpos($Sel, "AND");
    			$n = strpos($Sel, "AND");if(!empty($n) and $n<35) $Sel = substr_replace($Sel,"",$n,3);
    
    // exécution de la requête SQL de recherche parmi les Documents sur base des critères sélectionnés
    
    if($Sel !=="")
    {
    		$Req = "Select * from Documents where ".$Sel ;
    echo $Req;		
    		$Stmt = $bdd->prepare($Req);
    		$_SESSION['Data'] =$Stmt->execute();
    		$_SESSION['Data'] = $Stmt->fetchall();																								// Documents sélectionnés 
    		$DocumentNbr = count($_SESSION['Data']);
    		if($DocumentNbr !==0)
    		{
    		lstDocument($_SESSION['Data'],$DocumentNbr);
    		}
    		
    		else  $message .= "Your selection doesn't give any results"; 
    
        	
    }
     
    else																																	// il n'y a aucune sélection alors que le bouton submit a été cliqué
    	{
    	$message .= "Please fill in at least one criteria";
    	} 
    
    }

  2. #2
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    Tu ne peux utiliser directement une variable contenant un tableau, parce que la conversion en chaine automatique d'un tableau va te renvoyer "Array" .
    Il faut que tu concatènes les éléments du tableau en une chaine, par exemple avec implode :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $DossiersSelected = implode("', '", array_unique($_SESSION['Dossier']));
    $Sel.= " Ident = any ( select DocumentIdent from Dossiers_Documents where DossierIdent in ('" . $DossiersSelected . "') )";

    Au passage, quelques remarques :
    • htmlentities n'est pas une fonction qui permet de sécuriser les requêtes en base, c'est une fonction qui gère l'affichage d'entités HTML, ça n'a rien à faire là.
    • Quand tu construis une requête dynamique, un bon truc est de commencer la partie conditionnelle par WHERE 1=1. ça te permet de construire toutes les parties dynamiques sur le modèle AND quelque chose sans prise de tête du genre "Et si le 1er paramètre n'est pas appelé, il faut que je retire le AND du 2e"
    • Tu construis une requête qui va être appelée en tant que requête préparée, mais tu injectes les données directement dans la chaine au lieu de les passer en paramètres de la requête. C'est un peu comme si tu achetais un PC high-tech avec suffisamment de RAM pour faire tourner un calculateur de la NASA et une connexion filaire encryptée et que tu t'en servais comme support pour poser ton vieux portable connecté en Wifi non sécurisé.


    (au passage, ceci est clairement un problème PHP, est-ce que quelqu'un aurait l'obligeance de me déplacer le post vers PHP & SGDB > PDO, please ? Merci au collègue qui a déplacé le thread )
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2016
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2016
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Celira

    Merci pour cette aide rapide et pour les commentaires utiles.

  4. #4
    Expert éminent sénior
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 235
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 235
    Points : 15 532
    Points
    15 532
    Par défaut
    la requête préparée peut s'utiliser comme cela par exemple :
    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
    $valeursDossierParent = ["v1", "v2", "v3"];
     
     
    // construction de la requête
     
    $tabChamps = array_fill(0, count($valeursDossierParent), "?");
    $valeursIN = implode(", ", $tabChamps);
     
    $ReqChild  = "";
    $ReqChild .= "SELECT * FROM `Dossiers` WHERE 1 = 1";
    $ReqChild .= " AND DossierParent IN ($valeursIN)"; // donnera "… DossierParent IN (?, ?, ?)"
     
     
    // connexion et exécution
     
    $Stmt = $bdd->prepare($ReqChild);
    $Stmt->execute($valeursDossierParent);
     
    var_dump($Stmt->fetchAll());

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2016
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : Belgique

    Informations professionnelles :
    Activité : Retraité
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2016
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Merci Mathieu pour cette suggestion,

    En ce qui me concerne après la réponse de Celira, j'ai simplement converti le tableau en liste

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    foreach ($DossiersSelected as $DossiersEnCours)		$DossiersSelected2 .= $DossiersEnCours.",";	// mise de l'array $DossiersSelected sous forme de liste de valeurs
     
    				$k = strrpos($DossiersSelected2, ",");
    				if(!empty($k) ) $DossiersSelected2 = substr_replace($DossiersSelected2,"",$k,1);	// suppression de la dernière virgule
     
    				$Sel .= "Ident = any ( select DocumentIdent from Dossiers_Documents where DossierIdent in (".$DossiersSelected2." ))" ;
    Y-a-il un intérêt à travailler via une requête ?

  6. #6
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    Une requête préparée est utile principalement pour deux choses :
    • exécuter la même requête plusieurs fois avec des données différentes (par exemple, une insertion appelée en boucle)
    • protéger la requête des injections SQL

    Dans ton cas, c'est la 2e option qui est intéressante. En l'état, ton code est vulnérable aux injections SQL : tu peux tester en renseignant uniquement un champ dans ton formulaire avec une valeur du type toto' OR '1'='1. Tu vas te retrouver avec la totalité des données de la table au lieu de celles sélectionnées par le filtre.

    En alternative, il y a PDO::quote. Mais la doc de PDO::quote indique ceci :
    Si vous utilisez cette fonction pour construire des requêtes SQL, vous êtes vivement invités à utiliser PDO::prepare() pour préparer les requêtes SQL avec des paramètres liés au lieu d'utiliser PDO::quote() pour interpréter les entrées utilisateur dans la requête SQL. Les requêtes préparées avec des paramètres liés sont non seulement plus portables, plus souples et plus sécuritaires, mais bien plus rapides à exécuter que d'interpréter les requêtes, étant donné que les côtés client et serveur peuvent mettre en cache une version compilée de la requête.

    Tous les pilotes PDO n'implémentent pas cette méthode (comme PDO_ODBC). Utilisez les requêtes préparées à la place.
    Bref, mieux vaut utiliser des requêtes préparées.
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

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

Discussions similaires

  1. [MySQL] Erreur sur une requête select where
    Par Goffer dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 04/01/2009, 08h45
  2. Requête select where
    Par comrad85 dans le forum SQL
    Réponses: 16
    Dernier message: 31/10/2008, 00h12
  3. PB sur requête SELECT WHERE SELECT
    Par aliochai dans le forum Requêtes
    Réponses: 2
    Dernier message: 03/03/2008, 15h59
  4. [MySQL] requête avec WHERE sur primary key
    Par newbiemac dans le forum SQL Procédural
    Réponses: 1
    Dernier message: 04/09/2007, 09h41
  5. [php-mysql] requête qui ne marche pas....
    Par sanosuke85 dans le forum Requêtes
    Réponses: 1
    Dernier message: 09/01/2006, 17h18

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