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 :

MySQL contrainte unique [MySQL]


Sujet :

PHP & Base de données

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2006
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juillet 2006
    Messages : 985
    Points : 460
    Points
    460
    Par défaut MySQL contrainte unique
    Bonjour à tous,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    CREATE TABLE table (
      adresse_email    varchar(128) NOT NULL,
      UNIQUE KEY adresse_email (adresse_email)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
    Comment gérer en PHP l'erreur retournée par la contrainte unique sur le champ adresse_email lorsqu'un utilisateur essaie d'entrer une email qui existe déjà dans la table table.

    Merci d'avance...

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2006
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juillet 2006
    Messages : 985
    Points : 460
    Points
    460
    Par défaut
    J'ai essayé ceci pour gérer correctement l'erreur
    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
     
    define('DB_USER', 'root');
    define('DB_PASSWORD', '');
    define('DB_CONNECTION_STRING', 'mysql:host=localhost;dbname=test');
     
    function insertdb($email) {
    	global $db;
    	$sql = 'INSERT INTO duplicate (email) VALUES (:email)';
    	$statement = $db->prepare($sql);
    	$statement->bindValue(':email',   $email);
    	if ( $statement->execute() ) return $db->lastInsertId();
    	else return $statement->errorInfo();
    }
     
    $db = new PDO(DB_CONNECTION_STRING, DB_USER, DB_PASSWORD);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->query('SET NAMES utf8');
     
    $email = 'bmw@yahoo.fr';
    $user = insertdb($email);
    $erreur =& $user;
    Message d'erreur affiché par le navigateur pour doublon rencontré
    Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'bmw@yahoo.fr' for key 'email'' in C:\wamp\www\test\duplicate.php on line 11

    PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'bmw@yahoo.fr' for key 'email' in C:\wamp\www\test\duplicate.php on line 11
    Pourtant ce que je souhaite c'est que l'erreur soit stocké dans la varibale $erreur (pour traitement avec une expression régulière) et non affiché par le navigateur.

    Que faire ?

    Merci d'avance...

  3. #3
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Tu devais pourtant t'y attendre vu que tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


    Solution: soit tu mets ton execute() dans un bloc try/catch (recommandé) soit mets l'error mode à PDO::ERRMODE_SILENT (déconseillé).

    Avant que tu ne pose la question, voici comment utiliser un bloc try/catch: http://php.net/manual/en/language.exceptions.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
    Salut

    Une autre technique, moins optimisée, mais simple, consiste à faire une 1ère requête SELECT pour vérifier si l'adresse mail existe déjà ou pas.

    Un simple :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT COUNT(*)
    FROM duplicate
    WHERE email = :email

    Une autre encore, vu que tu utilise InnDB, c'est de faire un trigger coté SQL (MySQL) qui sera déclenché lors d'un INSERT, ce trigger fera une requête SQL (comme un peu ci-dessus), et l'insertion ne se fera que SI l'email n'existe pas.
    C'est pas loin d'être la même chose mais en plus optimisé.

    Peut être même plus optimisé qu'une gestion des exceptions Php, car l'erreur de duplication sera obtenue que lorsque MySQL aura renvoyée l'erreur à Php.

    Ceci dit, je dit bien "peut être" car je suis loin d'être expert pour affirmer ce genre de chose.
    Disons que vu que le tout (trigger / l'insertion) se passe coté MySQL, la théorie veut que cela soit assez performant.


    Pure suggestions.
    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
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2006
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juillet 2006
    Messages : 985
    Points : 460
    Points
    460
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    soit mets l'error mode à PDO::ERRMODE_SILENT (déconseillé).
    Ça marche.

    Citation Envoyé par Benjamin Delespierre Voir le message
    soit tu mets ton execute() dans un bloc try/catch (recommandé).
    http://php.net/manual/en/language.exceptions.php
    Je suis interressé par cette solution mais je n'y arrive pas. J'ai regardé le lien. De l'aide SVP !

    Merci d'avance...

  6. #6
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2006
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juillet 2006
    Messages : 985
    Points : 460
    Points
    460
    Par défaut
    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
     
    function insertdb($email) {
    	global $db;
     
    	$sql = 'INSERT INTO duplicate (email) VALUES (:email)';
    	$statement = $db->prepare($sql);
    	$statement->bindValue(':email',   $email);
    	try {
    		$statement->execute();
    		$return = $db->lastInsertId();
    	} catch (Exception $e) {
    		$return = $statement->errorInfo();
    	}
    	return $return;
    }
    Ça marche. Avant de basculer en résolu, j'attends vos remarques et améliorations possibles.

    Merci d'avance...

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2006
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juillet 2006
    Messages : 985
    Points : 460
    Points
    460
    Par défaut
    Merci à vous tous pour votre précieuse aide.

  8. #8
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    mis à part le global $db qui me répugne, c'est acceptable niveau sécurité.

    Remarque: pour éviter d'avoir recours à une variable globale (ou à un Singleton, ce qui revient exactement au même), tu devrais considérer la possibilité d'injecter l'instance PDO dans les fonctions/méthodes qui en ont besoin.

    Dans ton cas ça nous donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function insertdb(PDO $db, $email) {
    	$sql = 'INSERT INTO duplicate (email) VALUES (:email)';
    	$statement = $db->prepare($sql);
    	$statement->bindValue(':email',   $email);
    	try {
    		$statement->execute();
    		$return = $db->lastInsertId();
    	} catch (Exception $e) {
    		$return = $statement->errorInfo();
    	}
    	return $return;
    }
    De cette façon, tu es certain que $db sera toujours une instance de PDO, c'est d'ailleurs beaucoup plus flexible car tu peux passer l'instance qui t'intéresse si par exemple tu utilise 2 serveur MySQL (ok c'est rare mais ça arrive).

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 13/02/2006, 11h13
  2. Nested table et contrainte UNIQUE
    Par evlad dans le forum Oracle
    Réponses: 7
    Dernier message: 05/01/2006, 10h13
  3. [Hibernate] Surrogate key et contraintes unique
    Par mauvais_karma dans le forum Hibernate
    Réponses: 2
    Dernier message: 22/11/2005, 16h41
  4. mysql et Unique étendu
    Par Stef784ever dans le forum Administration
    Réponses: 3
    Dernier message: 29/08/2005, 15h14
  5. Suppression de la contrainte unique
    Par mika dans le forum SQL
    Réponses: 3
    Dernier message: 20/02/2003, 17h56

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