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 :

Pourquoi cette requête préparée ne fonctionne-t'elle pas ?


Sujet :

PHP & Base de données

  1. #1
    Inactif
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 37
    Points : 13
    Points
    13
    Par défaut Pourquoi cette requête préparée ne fonctionne-t'elle pas ?
    Bonjour,

    Je m'essaie aux requêtes préparées, mon but est simplement d'afficher une liste d'article qui commencent par une même lettre, ici la lettre G. Dans un premier temps, je fais fi des histoires de sécurisation, etc...

    Néanmoins ça ne fonctionne pas pour autant.

    Car avec ceci :
    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
    $pdo = new PDO('mysql:host=localhost;dbname=article7_dico1','article7_jeromec', 'SI~nq,[nX,');   
     
    $lettre = 'g';
     
     
    /** on définit la requete sql */
    $sql = "SELECT field_9 FROM cms_custom_database_2
    WHERE field_12 LIKE CONCAT(:A, '%')
    ";
     
    /* On prépare la requête */
    $stmt = $dbh->prepare ($sql);
     
    /** On prépare les paramètres */
    $params = array('A' => $lettre);
     
    /** On execute la requete */
    $stmt->execute($params);
     
    while($lettre=$params = $stmt->fetch(PDO::FETCH_OBJ))
    {
     
    echo "<b>".$lettre->field_9."</b>";
     
    }
    J'obtiens cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Fatal error: Call to a member function prepare() on a non-object in /home1/article7/public_html/applications/cms/sources/Blocks/Block.php(195) : eval()'d code on line 12
    Si vous voulez bien me guider un peu pour débuter, merci d'avance

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    le % fait partie de la variable :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $sql = "SELECT field_9 FROM cms_custom_database_2
    WHERE field_12 LIKE :A
    ";
    $stmt = $dbh->prepare ($sql); /* On prépare la requête */
    $params = array('A' => $lettre.'%'); /* On prépare les paramètres */
    $stmt->execute($params); /* On execute la requete */
     
    while($row = $stmt->fetch(PDO::FETCH_OBJ))
    {
       echo "<b>".$row->field_9."</b><br />";
    }

    Citation Envoyé par Alorslaçaprogramme Voir le message
    ...Dans un premier temps, je fais fi des histoires de sécurisation, etc...
    Utiliser une requête préparée te met en sécurité.

  3. #3
    Inactif
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 37
    Points : 13
    Points
    13
    Par défaut
    Bonjour, cher jreaux62.

    Je ne comprends pas quel est au juste le problème avec le %, ceci dit la requête fonctionne tout de même : j'avais simplement omis de remplacer $pdo par $dbh.

    Cela étant, lorsque tu dis que la requête préparée se suffit à elle-même en terme de sécurité, il me faut préciser que le script ci-dessus n'est pas définitif. La lettre à retourner en paramètre de recherche dans la requête préparée doit en fait être récupérée par l'URL. Il y a donc un risque, si quelqu'un me balance un code dans l'url, n'est-ce pas ?
    C'est la première fois que je travaille avec les requêtes préparées et/ou PDO (je sais, je retarde).
    Avant, je faisais un truc comme cela pour exécuter ou non le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if ($_GET['lettre']==a OR $_GET['lettre']==b, etc...) { 
    $dbh = new PDO('mysql:host=localhost;dbname=dicocom7_dico1','dicocom7_jeromec', 'SD_I~nq,[nX,');   
    on exécute le code;}
    ElSE {echo 'Va jouer ailleurs, vil pirate !';}
    Ce genre de condition d'affichage est-il toujours valable avec les récentes versions de PHP ? Et qu'en est-il des mysql_real_escape_string (celui-là plante désormais je crois), htmlentities et autre regexp ?

  4. #4
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Pour commencer, active les erreurs PDO quand tu developpes :
    http://php.net/manual/fr/pdo.error-handling.php

    Le principe d'un paramètre dans une requête préparée est de remplacer une valeur (dans ton cas "A%") par un identifiant (:A)
    La structure de la requête étant traitée incidemment (étape de préparation), il n'est pas possible d'injecter un code en passant pas la valeur.

    Tu peux donc écrire sans crainte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $sql = "SELECT field_9 FROM cms_custom_database_2
    WHERE field_12 LIKE :lettre
    ";
    $stmt = $dbh->prepare ($sql); /* On prépare la requête */
    $params = array(':lettre' => $_GET['lettre'].'%');
    mysql_real_escape_string() ne plante pas mais elle fonctionne avec l'ancienne extension mysql, pas avec PDO.
    htmlentities sert à afficher du contenu.
    une expression régulière peut servir à contrôler le contenu de la valeur pour des aspects fonctionnels.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  5. #5
    Inactif
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 37
    Points : 13
    Points
    13
    Par défaut
    Salut sabotage,

    Je viens d'essayer ton code, ça fonctionne, mais j'avoue que je recopie un peu sans piger.

    Le principe d'un paramètre dans une requête préparée est de remplacer une valeur (dans ton cas "A%") par un identifiant (:A)
    Dans mon premier code ci-dessus, j'utilisais donc une valeur plutôt qu'un identifiant, comme dans ton bout de code. Mais quelle est la différence ? Dans quel cas utiliser l'un plutôt que l'autre ? Ma requête avec identifiant était-elle une fausse requête préparée, un reliquat de requête ancienne mode ? Une erreur ?

    La structure de la requête étant traitée incidemment (étape de préparation), il n'est pas possible d'injecter un code en passant pas la valeur.
    J'ai du mal à voir dans ton bout de code ce qui garantit la sécurité de la requête. Rien est filtré, si le pirate envoie ça, qu'est-ce qui l'empêche d'agir sur la base ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //url bidouillée par le pirate :
    http://www.monsite.com/article.php?lettre=la_super_injection_sql_super_fignolée
    //Ce que je récupère dans mon script
    $params = array(':lettre' => $_GET['lettre'].'%');
    Pourquoi ici $_GET['lettre'] ne serait-il pas infecté, puisque nulle part cette variable retournée par l'url n'a été filtrée ?

  6. #6
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Dans ton premier code, la requête est bonne mais L'utilisation de CONCAT alourdi la requête pour rien.
    De plus l'idée d'une requête préparée est qu'elle peut être rejouée sans modification avec d'autres valeurs. Il est donc plus logique d'avoir le % dans la valeur plutôt que en dur dans la requête.

    L'erreur obtenue vient du fait que tu as mis $pdo pour la connexion et $dbh pour la préparation.

    Concernant la sécurité, comme je t'ai dis, la valeurs sont séparées de la requête. Donc si la valeur contient du code SQL, il ne sera pas interprété.
    Après si tu ne veux pas que l'utilisateur ne puisse que rechercher une lettre seule et pas 'toto' par exemple, cela demande des contrôles supplémentaires.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  7. #7
    Inactif
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 37
    Points : 13
    Points
    13
    Par défaut
    Bonjour !

    Alors reprenons si vous le voulez bien, après ce week-end salvateur.
    Concernant la sécurité, comme je t'ai dis, la valeurs sont séparées de la requête. Donc si la valeur contient du code SQL, il ne sera pas interprété.
    Eh mais justement, pourquoi ce code SQL n'est-il pas interprété s'il constitue la valeur ? Qu'est-ce qui empêche automatiquement cela ?

  8. #8
    Invité
    Invité(e)
    Par défaut
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    $stmt = $dbh->prepare ($sql); /* On prépare la requête */



    PDO::prepare — Prépare une requête à l'exécution et retourne un objet.

    Prépare une requête SQL à être exécutée par la méthode PDOStatement::execute().
    La requête SQL peut contenir zéro ou plusieurs noms (:nom) ou marqueurs (?) pour lesquels les valeurs réelles seront substituées lorsque la requête sera exécutée.

  9. #9
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Les valeurs ne sont pas interprétées puisque ce sont des valeurs.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

Discussions similaires

  1. Pourquoi cette requête n'utilise pas d'index ?
    Par seal3 dans le forum Requêtes
    Réponses: 2
    Dernier message: 31/08/2009, 18h03
  2. Réponses: 12
    Dernier message: 24/07/2007, 11h09
  3. Pourquoi cette requête SQL ne marche pas toujours
    Par Platon93 dans le forum Requêtes et SQL.
    Réponses: 17
    Dernier message: 14/12/2006, 17h29
  4. [ADO.Net][OleDb] Pourquoi ma requête access ne fonctionne pas?
    Par Bapt.ice dans le forum Accès aux données
    Réponses: 6
    Dernier message: 05/05/2006, 17h19
  5. Pourquoi cette requête est lente ?
    Par zenzo dans le forum Langage SQL
    Réponses: 7
    Dernier message: 06/01/2006, 15h15

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