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 :

BindValue() : Paramètre data_type sans effet ?


Sujet :

PHP & Base de données

  1. #1
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut BindValue() : Paramètre data_type sans effet ?
    Salut à tous

    Je me pose la question de l'utilité du 3ème paramètre qu'attend la méthode BindValue() (et BindParam() aussi) qui est une constante définissant le type de donnée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    bool PDOStatement::bindValue ( mixed $parameter , mixed $value [, int $data_type = PDO::PARAM_STR ] )
    Cependant, j'ai beau faire des essai en indiquant explicitement le "type", j'ai l'impression que cela n'a strictement aucun effet

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    $sStmt = $db->prepare('UPDATE table SET une_chaine = :chaine');
    $sStmt->bindValue(':chaine', 'Une chaine', PDO::PARAM_INT);
    $sStmt->execute();
    Je m'attendais à une sorte de typage, que PDO transtyperait cette donnée, et comme c'est une chaine, 0 serait retournée, enregistrée.
    Où alors, un retour d'erreur, une exception serait déclenchée du faite d'une donnée non conforme au type.
    Mais non ... rien.

    Du coup, que je mette PARAM_INT, PARAM_NULL, PARAM_LOB, PARAM_BOOL ... les modifs ont lieu, comme si de rien était.

    Pourquoi donc il y a rien qui se passe ?
    Est ce lié à la base de donnée ? (J'ai fait cet essai que sur MySQL)
    Au moteur MySQL ? (des essais que sur MyISAM)
    Ou alors c'est juste là pour qu'on l'exploite soit même ?


    Merci pour toutes explications
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

  2. #2
    Expert éminent sénior

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    6 152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 6 152
    Points : 17 778
    Points
    17 778
    Par défaut
    Comment ça il ne se passe rien ? Il y a bien une gestion d'erreur ? Parce que table est un mot-clé réservé normalement.

    Mais PDO effectue bel et bien les conversions demandées (un import depuis SimpleXML en est un bon exemple). Après c'est éventuellement dépendant du comportement du SGBD (conversions implicites) et du mapping des types SGBD/PHP (réalisé au niveau du pilote PDO).

  3. #3
    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
    Si tu passes un chiffre, par défaut il est passé comme un chaine et donc PDO lui ajoute des guillemets.
    Si tu le passes en tant que PARAM_INT, PDO ne lui ajoute pas de guillemets.

    Alors dans le cas d'une chaine, il est possible que PDO sur-corrige.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  4. #4
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut
    Je ne suis pas certain qu'on s'est compris

    J'avais mis un exemple bidon, c'est peut être pour ça.
    Donc prenons un exemple concret, et fonctionnel, de plus, en utilisant PDO tel quel (sans avoir fait de classe dérivée).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    $objPdo = new PDO('... bla bla bla ...');
    $objPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $objPdo->exec('SET NAMES utf8');
    //
    $objSt = $objPdo->prepare('UPDATE articles SET article_ref = :article_ref WHERE article_id = 20');
    $objSt->bindValue(':article_ref', 'ART-00001034', PDO::PARAM_INT);
    $execute = $objSt->execute();
    echo ($execute === true) ? 'true': 'false';
    Ici, l'enregistrement à bien lieu, que je mettre :
    1/ 'ART-00001034'
    ou
    2/ 'truc muche'
    Dans ces 2 cas c'est une chaine de caractère, on est d'accord

    Ce qui m'interpelle, c'est ce 3ème paramètre de bindValue -> PARAM_INT (mis volontairement)

    Il y a quand même un truc pas logique, non ?
    -> Soit il devrait avoir un retour d'erreur, une exception (le ERROR_MODE est actif) parce que la valeur n'est pas un INTERGER.
    -> Soit rien du tout, pas de mise à jour.
    Mais non, le truc passe comme une lettre à la poste

    Je dis que c'est pas normal.

    Ceci dit, le type de donnée est un VARCHAR coté MySQL.
    Si je fais le même test en changeant de champ (comme quantity) qui est un INT (toujours coté MySQL), vu que je tente d'enregistrer une chaine, c'est 0 qui sera enregistré.

    Mais là encore, pas l'ombre d'une erreur de retournée.
    Pourtant, cette fois le paramètre précise un type INT (integer) ET le type de donné du champ est aussi un INT.
    La valeur est une chaine, ça DOIT planter ... nom d'une pipe ...
    Du moins, je m'attend(ais) à ce que PDO me lance une exception, le ERROR_MODE est actif de plus je suis au max (STRICT) coté error_reporting Php.

    Mais dans tous les cas, c'est exactement la même chose qui se passe quelque soit le type que passe en argument, et même ne rien mettre du tout.

    Tous mes essais reviennent exactement à faire comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $objSt->bindValue(':article_ref', 'ART-00001034');
    Mes essais me démontre que ça à rien de le mettre.
    Je remarque aucune action venant de ce paramètre, c'est MySQL qui transtype quand cela est nécessaire, pas PDO.


    Ma question est : A quoi il sert alors ce 3ème paramètre de bindValue ?


    Mais PDO effectue bel et bien les conversions demandées (un import depuis SimpleXML en est un bon exemple). Après c'est éventuellement dépendant du comportement du SGBD (conversions implicites) et du mapping des types SGBD/PHP (réalisé au niveau du pilote PDO).
    La faut dire les choses comme elles sont : j'suis largué
    Il y a peut être un cas de figure où ça se remarque et qu'il y ai un intérêt, mais je ne parvient pas à le voir.
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

  5. #5
    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
    Il n'est pas dit que le paramètre applique une restriction.
    Ca change plutot la facon dont sont traités les données, voir l'exemple que j'ai donné.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  6. #6
    Expert éminent sénior

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    6 152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 6 152
    Points : 17 778
    Points
    17 778
    Par défaut
    C'est, a priori, dépendant du SGBD, puisque dans les cas où cela semble nécessaire PHP, par l'intermédiaire de cette indication de type, pourra effectuer les conversions nécessaires. (le même cas de figure sous SQLite implique une conversion via un processus interne similaire à intval)

    PDO n'émet pas d'erreur à ce niveau et ne vérifie les types que pour appeler la sous-routine appropriée (API SGBD) car dépendante du type SGBD et effectuer cette conversion (PHP => SGBD) quand nécessaire.

    On peut voir ces conversions en "détournant" volontairement la méthode bindParam puisque pour une donnée de type inapproprié par rapport à la valeur de ce troisième paramètre, on pourra voir, après l'appel à execute, que la variable a été modifiée pour être transtypée.

  7. #7
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut
    Citation Envoyé par sabotage
    Il n'est pas dit que le paramètre applique une restriction.
    Ca change plutot la facon dont sont traités les données, voir l'exemple que j'ai donné.
    Effectivement, j'ai rien lu de tel.
    Pour ton exemple, ceci s'arrêterait à quoter ou ne pas quoter, donc 2 cas.
    Du coup, à quoi bon proposer autant de types, quelle différence il y aurait entre un PARAM_INT et PARAM_BOOL, ou PARAM_STR et PARAM_LOB par exemple ?

    Je me dis que s'il y a autant de type, c'est que ça doit offrir plus que ça.


    Citation Envoyé par julp
    On peut voir ces conversions en "détournant" volontairement la méthode bindParam puisque pour une donnée de type inapproprié par rapport à la valeur de ce troisième paramètre, on pourra voir, après l'appel à execute, que la variable a été modifiée pour être transtypée.
    Ca serait vachement bien
    Le gros biiiiiinds c'est que je le remarque pas du tout ... rien ... à mon grand regret.

    Si je fais comme ceci (avec bindParam au lieu de bindValue) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    $ref = 'PRD-00001034';
    $id = 20;
    $objSt->bindParam(':article_ref', $ref, PDO::PARAM_INT);
    $objSt->bindParam(':article_id', $id, PDO::PARAM_INT);
    echo '1/ ref : '.$ref.'<br />';
    $execute = $objSt->execute();
    echo '2/ ref : '.$ref.'<br />';
    La mise à jour s'effectue avec PRD-00001034, et non un transtypage qui devrait donner un 0 ou 1034.
    De même que les 2 echo affichent la même valeur, toujours pas de transtypage, que ce soit avant ou après le execute().


    La conclusion que j'en tire, c'est que renseigner le data_type ne sert à rien, du moins, dans ce cas là, et dans ce contexte là (MySQL - MyISAM).

    J'ai vraiment l'impression que ceci serait lié au SGDB comme tu le dit Julp.
    Cependant, je n'est pas effectué d'essai sur d'autres SGBD.

    Je trouve ça fort dommage, car Php/MySQL c'est tout de même le tandem qui a le plus d'affinité, ne serait ce qu'historiquement.
    Là où devrait avoir "un plus", je me dis que c'est ici. M'enfin, une conclusion un peu simpliste, surement.


    Ceci dit, rien n'est perdu ...
    Je me dis qu'il me reste plus qu'à le faire moi même, suffirait de "surcharger" les méthodes binValue / binParam et transtyper explicitement.
    Un truc dans le genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    public function bindValue($param, $value, $type = PDO::PARAM_STR) {
    	switch (true) {
    		case (PDO::PARAM_BOOL) : $value = (bool)$value;
    		break;
    		case (PDO::PARAM_NULL) : $value = NULL;
    		break;
    		case (PDO::PARAM_INT) : $value = (int)$value;
    		break;
    	}
    	return parent::bindValue($param, $value, $type);
    }
    Ou alors, un truc "à la dur" ... chaud les marrons :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    public function bindValue($param, $value, $type = PDO::PARAM_STR) {
    	switch (true) {
    		case (PDO::PARAM_BOOL) : if (is_bool($value) == false)  throw new PdoException('Bouuuuhhh : Pas un booleen !!!');
    		break;
    		case (PDO::PARAM_NULL) : if (is_null($value) == false)  throw new PdoException('Bouuuuhhh : Pas Nulle !!!');
    		break;
    		case (PDO::PARAM_INT) : if (is_int($value) == false)  throw new PdoException('Bouuuuhhh : Pas un Integer !!!');
    		break;
    	}
    	return parent::bindValue($param, $value, $type);
    }
    Croyez vous qu'il est bon de faire ainsi ?


    Petit truc que je vient de découvrir ... j'suis passé complètement à coté d'ailleurs, c'est la méthode PDOStatement::debugDumpParams().
    C'est pas mal, ça fournie des détails sur la requête, et paramètres liés aux bindValue/bindParam.
    Petit bémol, c'est qu'à aucun moment les valeurs des données de binValue et bindParam n'est fourni, il n'y que le nom, et le type.
    Dommage, on aurait pu l'exploiter pour reconstituer la requête (pour un mode debug par exemple).


    Merci pour vos explications en tout cas.
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

  8. #8
    Expert éminent sénior

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    6 152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 6 152
    Points : 17 778
    Points
    17 778
    Par défaut
    C'est géré au niveau du pilote de chacun. Ainsi pour MySQL, c'est principalement le type de la variable PHP qui fait fois (3e paramètre "ignoré") : pour une variable PHP de type chaîne, elle est bindée comme telle via l'API sous-jacente (peu importe le PDO::PARAM_*). Ce qui n'induit pas de problème de sécurité, ça reste cohérent.

    SQLite, c'est l'inverse, il se base sur le troisième paramètre et effectue les conversions avant.

    PostgreSQL, quasi tout finit converti en chaîne (3e paramètre "ignoré").

    Le faire soi-même est possible (via une surcharge notamment) mais n'est donc pas nécessaire (surtout quand PHP en refait une derrière qui peut être toute autre).

  9. #9
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut
    C'est géré au niveau du pilote de chacun
    En gros, faut que je me fasse une raison, me dire que c'est ainsi.

    Le faire soi-même est possible (via une surcharge notamment) mais n'est donc pas nécessaire (surtout quand PHP en refait une derrière qui peut être toute autre).
    Pour le bindParam dont la valeur passe par référence, ça peut être une surcharge inutile effectivement, ça dépend quand même.
    Mais pour le bindValue, ça devrait le faire. Enfin, je pense.

    Tout ceci est fort dommage quand même.
    Ce phénomène je l'ai remarqué à partir du moment où je souhaitais faire un truc pour reconstituer la requête, pour un mode débug, de remplacer les :parametre par leur valeur qui eux se trouvent dans le bindValue/bindParam.


    J'ai l'impression d'avoir fait du bruit pour pas grand chose.
    Merci pour les explications éclairés tout de même
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

Discussions similaires

  1. [forms 6i]execute_query sans effet
    Par pjcejbpojo dans le forum Forms
    Réponses: 11
    Dernier message: 28/04/2006, 17h08
  2. [AJAX] Fontion JS sans effet
    Par LoK dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 31/03/2006, 14h43
  3. Combo sans effet
    Par GBW067 dans le forum Sécurité
    Réponses: 5
    Dernier message: 29/01/2006, 07h48
  4. Requête UPDATE sans effet
    Par Death83 dans le forum Requêtes
    Réponses: 4
    Dernier message: 15/01/2006, 01h23
  5. Sans effet: StringGrid1->Cells[1][1][2] = c ?
    Par Xavier dans le forum C++Builder
    Réponses: 3
    Dernier message: 27/11/2002, 10h32

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