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 :

Passage à PDO


Sujet :

PHP & Base de données

  1. #1
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut Passage à PDO
    Salut à tous.

    Voilà, je suis en train de passer à PDO sur mon dernier projet. J'ai une classe MySQL à l'origine que j'aimerais passer à 100% en PDO.

    Voici ma classe remaniée :
    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
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
     
    <?php
     
    class MySQL extends PDO {
     
    	private $logins = array(
    		'host'	=> 'host',
    		'user'	=> 'rpgamer',
    		'pass'	=> '1234',
    		'bdd'	=> 'database'
    	);
     
    	// constructeur 
    	public function __construct() {
     
    		parent::__construct(
    			"mysql:host=".$this->logins['host'].";dbname=".$this->logins['bdd'],
    			$this->logins['user'], $this->logins['pass']
    		);
    	}
     
    	// exécution de la requête
    	public function query($query) {
     
    		try {
     
    			$result = $this->query($query);
    			return $result;
    		}
     
    		catch (Exception $e) {
     
    			error_log(SharedParking::$actual_page.' - '.$query.' : '.$e->getMessage(), 0);
    			return FALSE;
    		}
    	}
     
    	// exécution de la requête
    	public function exec($query) {
     
    		try {
     
    			$result = $this->exec($query);
    			return $result;
    		}
     
    		catch (Exception $e) {
     
    			error_log(SharedParking::$actual_page.' - '.$query.' : '.$e->getMessage(), 0);
    			return FALSE;
    		}
    	}
     
    	// insertion de données dans MySQL
    	public function insert($table, $values) {
     
    		$values = array_map(array($this, 'quote'), (array)$values);	
    		return $this->exec("INSERT INTO ".$this->quote($table)." VALUES('".implode("', '", $values)."')");
    	}
     
    	// sélection de données depuis MySQL
    	public function select($table, $small_size = FALSE, $fields, $where = '', $order = '') {
     
    		$result_size = !empty($small_size) ? 'SQL_SMALL_RESULT' : '';
    		$where = !empty($where) ? ' WHERE '.$where : '';
     
    		return $this->query("SELECT ".$result_size." ".implode(", ", (array)$fields)." FROM ".
    		$this->quote($table).$where.$order);
    	}
     
    	// tri des résultat d'une requête SELECT
    	public function order($fields, $order = 'ASC') {
     
    		$order = array_map(array($this, 'quote'), (array)$order);
    		if (count($fields) == count($order)) {
     
    			$set = array();
    			$fields = (array)$fields;
    			for ($i = 0; $i < count($fields); $i++) {
     
    				$set[] = $fields[$i].' '.$order[$i];
    			}
     
    			return " ORDER BY ".implode(", ", $set);
    		}
     
    		else {
     
    			return FALSE;
    		}
    	}
     
    	// limitation des résultats d'une requête SELECT
    	public function limit($offset, $number) {
     
    		if (is_numeric($offset) && is_numeric($number)) {
     
    			return " LIMIT ".intval($offset).", ".intval($number);
    		}
     
    		else {
     
    			return FALSE;
    		}
    	}
     
    	// mis à jour de données de MySQL
    	public function update($table, $values, $where = FALSE) {
     
    		$set = array();
    		foreach ((array)$values as $field => $value) {
     
    			$set[] = $field." = ".$value;
    		}
     
    		return $this->exec("UPDATE ".$this->quote($table)." SET ".implode(", ", $set).(!empty($where) ? " WHERE ".$where : ''));
    	}
     
    	// suppression de données de MySQL
    	public function delete($table, $where) {
     
    		return $this->exec("DELETE FROM ".$this->quote($table)." WHERE ".$where);
    	}
    }
     
    ?>
    Actuellement toutes les erreurs PHP sont journalisées dans un fichier. Si une erreur MySQL survient, je la capture et la journalise également.

    En modifiant ma classe, j'ai bien sûr dû modifier la totalité de mon code, ce qui fait des milliers de lignes à corriger, je suis sûr de rencontrer au moins 1 erreur de syntaxe.

    Mais je m'attendais pas à avoir chaque de mes pages totalement blanches et un fichier de journalisation totalement vide.

    J'ai pensé à retirer le code capturant les erreurs retournées par les méthodes query() et exec() de la classe PDO, mais j'obtiens une erreur m'indiquant que la méthode fetch() n'est pas appelée sur un objet. Erreur correspondant à la première utilisation de l'instance.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <?php
     
    $mysql = new MySQL();
    $result = $mysql->select('configuration', TRUE, '*', "conf_country = '".$sp->country."' && conf_lang = '".$sp->lang."'");
    $conf = $result->fetch(PDO::FETCH_ASSOC);
     
    ?>
    Je pense que le problème vient de la classe MySQL.
    Merci d'avance de m'éclairer sur le sujet ^^

  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
    La gestion des erreurs par PDO, par défaut, est silencieuse : il faut que vous testiez les retours de méthode puisqu'elles renvoient FALSE en cas d'erreur au lieu d'un objet PDOStatement. Et dans ces cas-là, si on ne le fait pas et que l'on fait poursuivre l'exécution du script on en vient à chercher à appeler une méthode sur FALSE donc forcément, PHP ne va pas aimer.

    Il faut donc que vous testiez vos valeurs de retour ou que vous basculiez PDO en gestion des erreurs par exception via :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $this/$mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    Mais il faut éventuellement gérer (ou empêcher) une possible redéfinition de ce paramètre.

    C'est un peu dommage d'écrire une classe pour effectuer les requêtes quand on a les requêtes préparées à disposition et l'usage de la méthode quote, surtout sur les "noms" SQL (tables par exemple), ne fonctionnera pas - puisque ce ne sont pas des chaînes.

  3. #3
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    OK, je ne savais pas que ce comportement était défini par défaut.

    Seulement modifier le paramétrage n'a pas l'air de faire bouger les choses.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    <?php
     
    $mysql = new MySQL();
    $mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $result = $mysql->select('configuration', TRUE, '*', "conf_country = '".$sp->country."' && conf_lang = '".$sp->lang."'");
    $conf = $result->fetch(PDO::FETCH_ASSOC);
     
    ?>
    J'ai donc fait sauter la déclaration de méthodes query() et exec() maison et j'obtiens l'erreur suivante :
    [10-Apr-2010 16:07:47] PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''utilisateurs' SET user_lang = 'fr' WHERE user_id='9'' at line 1' in /home/www/4bb65782f4ecb4ef3c3607e4738e1e40/web/dev/scripts/php/mysql.class.php:95
    #0 /home/www/4bb65782f4ecb4ef3c3607e4738e1e40/web/dev/scripts/php/mysql.class.php(95): PDO->exec('UPDATE 'utilisa...')
    #2 /home/www/4bb65782f4ecb4ef3c3607e4738e1e40/web/dev/index.php(14): require('/home/www/4bb65...')
    thrown in /home/www/4bb65782f4ecb4ef3c3607e4738e1e40/web/dev/scripts/php/mysql.class.php on line 95
    Stack trace:
    #1 /home/www/4bb65782f4ecb4ef3c3607e4738e1e40/web/dev/start.inc.php(119): MySQL->update('utilisateurs', Array, 'user_id='9'')
    #3 {main}
    Normalement ça correspond à la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <?php
     
    $mysql->update('utilisateurs', array('user_lang' => "'".$sp->lang."'"), "user_id='".$_SESSION['user_id']."'");
     
    ?>
    J'ai l'impression que je n'ai pas les droits pour écrire ou modifier. Est-ce que par défaut PDO empêche ce type de requête ? J'utilise pourtant bien la méthode PDO::exec() dans ma méthode MySQL::update().

  4. #4
    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
    Non, aucun lien.

    Pour l'exception c'est normal, vous demandez une gestion des erreurs par exception mais ayant retiré vos méthodes (qui devaient boucler), il n'y a alors plus rien pour gérer une éventuelle exception (bloc try/catch). Donc PHP en fait une erreur fatale.

    Concernant l'erreur même, comme dit plus haut, vous ne devez pas quoter vos noms de table (ce que vous réalisez en leur appliquant la méthode quote) : ce ne sont pas des chaînes ! ($objetPDO->quote('x') donnant 'x' en SQL)

  5. #5
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Je ne connaissais pas cette particularité de PDO::quote(), elle ajoute automatiquement les apostrophes. Quelques heures supplémentaires à supprimer les apostrophes de mes clause WHERE en perspectives. Quelle bonne idée cette méthode...

    Apparemment c'est là que devait se poser le problème puisque ça semble marcher la plupart du temps.

    J'ai quand même un problème pour trouver un équivalent dans la documentation à mysql_result pour obtenir la valeur d'une cellule bien précise dans un jeu de résultat. Existe-t-il un équivalent.

    Enfin, comment définir des priorité sur les éléments présents dans la clause WHERE ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM table WHERE user = 10 || user = 25
    Dans cet exemple j'aimerais que le résultat qui correspond à l'utilisateur 10 aie la priorité sur celui qui correspond à l'utilisateur 25.

    Merci beaucoup pour votre aide précieuse

  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
    Citation Envoyé par RPGamer Voir le message
    J'ai quand même un problème pour trouver un équivalent dans la documentation à mysql_result pour obtenir la valeur d'une cellule bien précise dans un jeu de résultat. Existe-t-il un équivalent.
    Vous ne trouverez pas d'équivalent à cette fonction en PDO. Il faut que vous trouviez autre chose : rapatriement de tous les résultats avec fetchAll (avec un mode adapté) ?

    Citation Envoyé par RPGamer Voir le message
    Enfin, comment définir des priorité sur les éléments présents dans la clause WHERE ?
    WHERE n'ordonne pas les résultats, avec une clause ORDER.

  7. #7
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    OK... je vais m'arranger avec PDOStatement::fetch().

    Je connais ORDER BY pour ordonner les résultats. Mais ici c'est la priorité qui m'intéresserait. Par exemple dans une messagerie pour obtenir l'entrée de l'envoyeur et celle du receveur, qui se trouvent dans la même table. Je n'aurais plus qu'à me servir des 2 résultats retournés en sachant que le premier sera toujours l'envoyeur et le 2ème toujours le receveur. Je ne crois pas qu'ORDER BY puisse faire ça, malgré que ce soit très simple. Je me trompe peut-être.

    Ensuite avec cette histoire de PDO::quote(), je me rend compte qu'il m'est impossible de l'utiliser avec LIKE. Je crois que cette méthode est tellement bien conçue qu'il toujours faut utiliser des requêtes préparées.

    Ca va alourdir la mise à jour et le code, mais je crois qu'on y gagne en temps d'exécution ?

  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
    Je maintiens ORDER, ça ne peut être fait à un autre niveau et étant donné que l'usage des fonctions MySQL y est permis, il est possible de "bricoler un critère dynamique".

    Les requêtes préparées ont plusieurs avantages : elles seront bien plus performantes s'il y a plusieurs appels, des requêtes plus claires dans un sens et bien sûr elles permettent de tirer profit de toutes les fonctionnalités de PDO (citons bindParam par exemple). Par contre, elles ont des "inconvénients" : elles sont difficiles à utiliser lorsque la requête est dynamique (ce qui est normal puisque ce n'est pas vraiment leur but) et il existe des particularités SQL où elles ne peuvent être réellement utilisées (par exemple avec une liste de valeurs - (NOT) IN).

  9. #9
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Pour l'heure j'utilise UNION avec 2 requêtes SELECT identiques qui m'assurent l'ordre des résultats.

    Pour les marqueurs et une requête INSERT préparée, est-ce qu'il est possible de faire ce genre de syntaxe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?php
     
    $mysql = new PDO(...);
    $query = $mysql->prepare("INSERT INTO table VALUES(?, ?, ?, ?)");
    $query->execute(array(
        'Jean',
        'Durant', 
        'test@test.com',
        'Sod5D6dfd3xGad'
    ));
     
    ?>
    Est-ce que PDO::quote() détecte si il est utilisé avec LIKE ?

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <?php
     
    $mysql->select('table', '*', "user LIKE '%".$mysql->quote($var)."%'");
     
    ?>

  10. #10
    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
    Citation Envoyé par RPGamer Voir le message
    Pour les marqueurs et une requête INSERT préparée, est-ce qu'il est possible de faire ce genre de syntaxe
    Oui mais à long terme, des paramètres nommés (syntaxe :nom) seraient peut être plus faciles à (re)lire/maintenir.

    Citation Envoyé par RPGamer Voir le message
    Est-ce que PDO::quote() détecte si il est utilisé avec LIKE ?
    Non, il n'y a aucune vérification. Et de toute manière, ce n'est pas la requête ou une partie de celle-ci qui est fournie à la méthode quote mais uniquement la valeur à quoter.

Discussions similaires

  1. [PDO] menu déroulant construit par (passage de) MySql au (lieu de) PDO
    Par tonton.odilon dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 09/06/2015, 22h32
  2. passage à mysql pdo
    Par laloupiote dans le forum Langage
    Réponses: 13
    Dernier message: 06/04/2013, 18h10
  3. [MySQL] PDO pb de passage de parametre
    Par altair8080 dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 05/04/2012, 20h33
  4. Réponses: 4
    Dernier message: 16/08/2011, 13h19
  5. Passage de parametre a une anim Flash 5
    Par debug dans le forum Intégration
    Réponses: 4
    Dernier message: 03/06/2002, 17h59

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