[RESOLU] Eviter l'insertion de plusieur entrée identique en bdd

Eléphant du PHP | 372 Messages

23 juin 2015, 15:04

Salut à tous.
J'ai un code fonctionnel et je souhaite juste améliorer un petit truc.
Je récupère dans mon XML mes infos mails il arrive que dans ce fichier XML il existe plusieurs fois la même entrée j'aimerais donc éviter de l'injection une deuxième fois si elle à était déjà injectée.

J'aimerais faire un truc du genre: Si le loisir posséde le même titre, même ville, même code postal, même date alors ne pas insérée en bdd.

Merci à vous :wink:

Mon code:
<?php

    //connection a la base de donnee
    $dbhost = "localhost";
    $dbuser = "root";      // mysql user
    $dbpass = "";       // mysql password
    $dbname = "mabase";     // mysql database
    $conn=mysql_connect($dbhost,$dbuser,$dbpass) or die(erreurServeurMySQL());
    mysql_select_db($dbname,$conn) or die('Erreur de selection '.mysql_error()); // problème sur la bdd
      
    $flux = simplexml_load_file('http://localhost/csv/zxpd_201506220436_3467_31592008.xml'); // Source du flux.xml
	
	
                           
    foreach ($flux->product as $item) {
		
	set_time_limit(0);
  
    $titre = addslashes($item->name);
    $price = $item->price;
    $url_fnac = $item->deepLink;
    $date_debut_sortie = $item->validFrom;
    $date_fin_sortie = $item->validTo;
    $street = addslashes($item->terms);
    $photo = $item->largeImage;
    $genre = $item->merchantCategoryPath;
	$description = 'blablabla !!!';
	
     
    // $aLoisirs = array (1 => 'Restaurant', 2 => 'Discothèque', 3 => 'Bar/Pub', 4 => 'Videgrenier/Brocante', 5 => 'Marché', 6 => 'Sport', 7 => 'Loto', 13 => 'Exposition', 10 => 'Divers', 10 => 'Concert', 11 => 'Spectacle', 12 => 'Rencontre', 13 => 'Excursion/Visite', 14 => 'Bal/Festival', 15 => 'Théatre', 16 => 'Classique', 17 => 'Salons et foires',  18 => 'Cinéma', 20 => 'Coffrets cadeau'  );
     
    $type  = array(  
            // Coffret cadeau
                         'CCA|Carte cadeau' => 20, 'COB|Coffrets Bien-être' => 20, 'COS|Coffrets Séjours' => 20, 'COG|Coffrets Gastronomie' => 20, 'COA|Coffrets Activités' => 20,
                         'COE|Coffrets Enfants' => 20, 'CHM|Coffrets Homme' => 20, 'COS|Coffrets Femme' => 20, ' CPS|Coffrets Sport/Pilotage' => 20, ' CAO|Coffrets Originaux/Atypiques' => 20,
                         'CMT|Coffrets Multithématiques' => 20, 'CLU|Coffrets luxe' => 20, 'CDI|Coffrets divers' => 20,
                          
                         // Cinéma
                         'FIL|Film' => 18, 'ACI|Abonnement/Pass cinéma' => 18, 'ACT|Action' => 18, 'ANI|Animation' => 18, 'ARM|Arts martiaux' => 18, 'AVE|Aventure' => 18, 'AVP|Avant-première' => 18, 'BIO|Biopic' => 18, 'BOL|Bollywood' => 18, 'CIC|Ciné-concert' => 18,
                         'CIE|Cinéma jeune public' => 18, 'CLA|Classique' => 18, 'COD|Comédie dramatique' => 18, 'COM|Comédie' => 18, 'DEA|Dessin animé' => 18, 'DIV|Divers' => 18, 'DOC|Documentaire' => 18, 'DRA|Drame' => 18, 'EPO|Epouvante-horreur' => 18, 'ERO|Erotique' => 18,
                         'ESP|Espionnage' => 18, 'FAN|Fantastique ' => 18, 'FCE|Comédie érotique' => 18, 'FFA|Famille' => 18, 'GUE|Guerre' => 18, 'HIS|Historique' => 18, 'JUD|Judiciaire' => 18, 'MED|Médical' => 18, 'MOB|Mobisode' => 18, 'MUS|Musical' => 18,
                         'NUI|Nuit à thème (cinéma)' => 18, 'PEP|Péplum' => 18,  'POL|Policier' => 18, 'ROM|Romance' => 18, 'SCF|Science fiction' => 18, 'SOA|Soap' => 18, 'THR|Thriller' => 18,
                         'WEB|Web série' => 18, 'WES|Western' => 18, '131F|Cinéma' => 18, 18, '13CI|Cinéma' => 18, 'ROC|Retransmission Opéra/Concert ;' => 18,
                        );
 
   
 
    // On fait un explode afin de récupérer ce qu'il nous interesse
    $postcode  = $item->extra2;
    $pieces = explode(" ", $postcode);
 
    // On attribut le département en fonction des 2 premiers chiffre du code postal
    $departement = substr($postcode, 0, 2);
     
    $region = regionIdByDepartement($departement);
     
    // Attribution de la valeur id 1010 pour la fnac
    $id_simply_user = '1010';
     
    // On valide la sortie par default
    $valide = '1';
	
	
	 foreach (explode(' ; ', /*(string)*/ $item->merchantCategoryPath) as $subtype) {
    $id_type_loisirs = $type[$subtype];
    
	
	 $sql = "INSERT INTO `matable` (id_simply_user,titre,price,photo,url_fnac,date_debut_sortie,date_fin_sortie,description,street,postcode,city,id_region,id_departements,id_type_loisirs,valide) VALUES ('$id_simply_user','$titre','$price','$photo','$url_fnac','$date_debut_sortie','$date_fin_sortie','$description','$street','$pieces[0]','$pieces[2]','$region','$departement','$id_type_loisirs','$valide')";
    $req = mysql_query($sql) or die('Erreur SQL !'.$sql.'<br>'.mysql_error());
    echo 'données inserées en base';
	} 
 
}
  
?>

Avatar du membre
Mammouth du PHP | 1609 Messages

23 juin 2015, 15:08

Salut Blinz, il suffit dans ta boucle, après avoir extrait titre, ville et code postal, de faire un SELECT pour voir si une ligne existe avec ces informations.
Si une ligne est trouvée alors tu peux utiliser l'instruction continue pour passer à l'itération suivante de la boucle, sinon tu peux faire l'insert.
Développeur web depuis + de 20 ans

Eléphant du PHP | 372 Messages

23 juin 2015, 15:13

Avez vous un exemple concret svp ?

Avatar du membre
Mammouth du PHP | 1609 Messages

23 juin 2015, 15:29

Un petit coup de pouce. Il faut que tu places ça au bon endroit en complétant la requête comme nécessaire.
$result = mysql_query('SELECT ... FROM ... WHERE ....');
if(mysql_num_rows($result) > 0)
  continue ;
EDIT
lol désolé Ryle ;)
Au moins ton exemple de requête est plus parlant, Blinz a tout ce qu'il faut pour y arriver.
Modifié en dernier par Saian le 23 juin 2015, 15:40, modifié 2 fois.
Développeur web depuis + de 20 ans

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

23 juin 2015, 15:36

Bonjour,

Comme indiqué par Saian, il te faut une requête pour vérifier la présence d'un enregistrement identique en base ou non. Un truc du genre :
" SELECT count(*) AS nb FROM ta_table_de_loisir WHERE titre = ton_titre, ville = ta_ville, cp = ton_cp, dte = ta_date "
Si cette requête te retourne 0, c'est qu'il n'y a aucun enregistrement identique dans ta table, si elle te retourne une autre valeur (1 ou plus), c'est qu'il y a déjà un enregistrement similaire en base.

En fonction de ce résultat, tu pourras donc utiliser un if/else pour savoir s'il te faut enregistrer les donnes en bdd ou non.

Et puisque tu es dans une boucle, tu peux effectivement utiliser l'instruction "continue" comme le suggère Saian pour passer directement à l'itération suivante et optimiser un peu les performances (ça se sentira pas plus que ça dans ton cas, mais c'est une bonne habitude à prendre :))

EDIT : grillé -_-
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphant du PHP | 372 Messages

23 juin 2015, 16:22

quelque chose comme ça ?
/// le code ....
 
    // On fait un explode afin de récupérer ce qu'il nous interesse
    $postcode  = $item->extra2;
    $pieces = explode(" ", $postcode);
 
    // On attribut le département en fonction des 2 premiers chiffre du code postal
    $departement = substr($postcode, 0, 2);
     
    $region = regionIdByDepartement($departement);
     
    // Attribution de la valeur id 1010 pour la fnac
    $id_simply_user = '999';
     
    // On valide la sortie par default
    $valide = '1';
	
	
	foreach (explode(' ; ', /*(string)*/ $item->merchantCategoryPath) as $subtype) {
    $id_type_loisirs = $type[$subtype];
    
	$result = mysql_query('SELECT count(*) AS nb FROM loisirs WHERE titre = $titre, city = $pieces[2], postcode = $pieces[0], date_debut_sortie = $date_debut_sortie, date_fin_sortie = $date_fin_sortie');
	if(mysql_num_rows($result) > 0)

	{
		echo'pas posté';
	}
	else {
	
		$sql = "INSERT INTO `loisirs` (id_simply_user,titre,price,photo,url_fnac,date_debut_sortie,date_fin_sortie,description,street,postcode,city,id_region,id_departements,id_type_loisirs,valide) VALUES ('$id_simply_user','$titre','$price','$photo','$url_fnac','$date_debut_sortie','$date_fin_sortie','$description','$street','$pieces[0]','$pieces[2]','$region','$departement','$id_type_loisirs','$valide')";
		$req = mysql_query($sql) or die('Erreur SQL !'.$sql.'<br>'.mysql_error());
		echo 'données inserées en base';
		} 
	}
}
  
?>

Avatar du membre
Mammouth du PHP | 1609 Messages

23 juin 2015, 16:27

Oui, sauf que $id_type_loisirs ne faisant pas partie des critères du WHERE, tu peux mettre le test avant le foreach et mettre un continue si mysql_num_rows($result) > 0 n'ayant pas besoin d'exécuter le code en dessous (ça réduira le nombre de requêtes et le script n'en sera que plus performant).

A priori ta requête va aussi faire des erreurs car pour les colonnes de type chaine de caractères, les valeurs doivent être délimitées avec ' ou " (penser à traiter les cas où la chaine contiendrait des ' ou ").

PS : de la même manière, tu devrais mettre le tableau $type et le set_time_limit(0); en dehors du foreach principal car il n'est pas nécessaire de re-déclarer le tableau $type et de remettre la limite de temps à 0 à chaque itération de la boucle.

PPS : et en fait le mysql_num_rows ne convient pas avec un SELECT count(*), car tu auras toujours un résultat contenant le nombre de lignes correspondantes (normalement 0 ou 1).
Pour que le mysql_num_rows puisse fonctionner comme voulu dans ma proposition il faut plutôt faire un SELECT id (en remplaçant évidement id par le nom de la colonne d'id de la table). Ainsi aucune ligne ne sera retournée s'il n'y a pas de correspondance avec le WHERE et mysql_num_rows retournera bien 0.
Développeur web depuis + de 20 ans

Eléphant du PHP | 372 Messages

23 juin 2015, 18:42

Du coup tout plante.
Je remet le code des foiq que ds; et merci encore:
<?php
     
    include("include/variables.php");
     
    //connection a la base de donnee
    $dbhost = "localhost";
    $dbuser = "root";      // mysql user
    $dbpass = "";       // mysql password
    $dbname = "mabase";     // mysql database
    $conn=mysql_connect($dbhost,$dbuser,$dbpass) or die(erreurServeurMySQL());
    mysql_select_db($dbname,$conn) or die('Erreur de selection '.mysql_error()); // problème sur la bdd
      
    $flux = simplexml_load_file('http://localhost/csv/zxpd_201506220436_3467_31592008.xml'); // Source du flux.xml
	
	//set_time_limit(20);
	
	// $aLoisirs = array (1 => 'Restaurant', 2 => 'Discothèque', 3 => 'Bar/Pub', 4 => 'Videgrenier/Brocante', 5 => 'Marché', 6 => 'Sport', 7 => 'Loto', 13 => 'Exposition', 10 => 'Divers', 10 => 'Concert', 11 => 'Spectacle', 12 => 'Rencontre', 13 => 'Excursion/Visite', 14 => 'Bal/Festival', 15 => 'Théatre', 16 => 'Classique', 17 => 'Salons et foires',  18 => 'Cinéma', 20 => 'Coffrets cadeau'  );
     
	 
	
	 
    $type  = array(     // Concert  
                        'POP|Pop-rock/Folk' => 10, '11P|Pop-Rock/Musique électronique' => 10, '1MC|Musique/Concerts' => 10, 'VAI|Variété internationale' => 10, 'VAI|Variété internationale ' => 10, 'VAF|Variété et chanson françaises' => 10,
                        'CMU|Comédie Musicale' => 10, 'HAR|Hard-rock/Métal' => 10,  'MEL|Musique électronique' => 10,  'CLU|Clubbing & Soirées' => 10, 'SOI|Galas/Soirées étudiante' => 10,
                        'REV|Réveillon' => 10, 'RAP|Rap/Hip-hop/Slam' => 10, 'REG|Reggae' => 10, 'SOU|R\'n\'B/Soul/Funk' => 10, 'CMU|Comédie Musicale' => 10, 'BLU|Blues/Country' => 10, 'CIC|Ciné-concert' => 10,
                        'GOS|Gospel' => 10, 'JAZ|Jazz' => 10, 'MAC|Musiques des Caraïbes & Amérique latine' => 10, 'MTF|Musiques de France & Europe' => 10, 'RAI|Musiques d\'Orient & Maghreb' => 10,
                        'MAI|Musiques d\'Asie, Inde & Océanie' => 10, 'MAF Musiques d\'Afrique' => 10, 'CHO|Chant choral' => 10, 'CIC|Ciné-concert' => 10, 'LYR|Lyrique' => 10, 'MBA|Musique baroque' => 10,
                        'MCL|Musique classique' => 10, 'MCO|Musique contemporaine' => 10, 'MSA|Musique sacrée' => 10, 'MBA|Musique baroque' => 10, 'OPE|Opéra' => 10, 'OPT|Opérette' => 10, 
						'11V|Variété/Comédie' => 10, '13R|Rap/Reggae/Soul-Funk' => 10, '3DA|Musique Classique & Danse' => 10, '3DA|Musique Classique & Danse' => 10, '16C|Musique classique et Opéra' => 10,
						'12P|Pop-Rock/Musique électronique' => 10, '15M|Musiques du monde' => 10, 'MAF|Musiques d\'Afrique' => 10, '14J|Jazz/Blues/Gospel' => 10, 'VAI|Variété internationale' => 10,
						'15M|Musiques du monde' => 10, 'VAI|Variété internationale' => 10, '11V|Variété/Comédie musicale' => 10, 'MAC|Musique Caraïbes/Amérique latine' => 10, '11V|Variété/Comédie musicale ' => 10,
						'12P|Pop-Rock/Musique électronique ' => 10, '15M|Musiques du monde ' => 10, '; VAI|Variété internationale' => 10, '15M|Musiques du monde ;' => 10, '12P|Pop-Rock/Musique électronique ;' => 10,
						'14J|Jazz/Blues/Gospel ;' => 10, '; JAZ|Jazz' => 10, '; MEL|Musique électronique' => 10, '13R|Rap/Reggae/Soul-Funk ;' => 10, ' ;VAF|Variété et chanson françaises' => 10,
						' ; VAF|Variété et chanson françaises' => 10, '13R|Rap/Reggae/Soul-Funk ; ' => 10, ' ; SOU|R\'n\'B/Soul/Funk' => 10, '13R|Rap/Reggae/Soul-Funk ; ' => 10, '; RAP|Rap/Hip-hop/Slam' => 10,
						'; VAF|Variété et chanson françaises' => 10, 'POP|Pop-rock/Folk ;' => 10, 'MCL|Musique classique ;' => 10, 'CHO|Chant choral ;' => 10, 'ROC|Retransmission Opéra/Concert' => 10,
                         
           
                          
                         // Cinéma
                         'FIL|Film' => 18, 'ACI|Abonnement/Pass cinéma' => 18, 'ACT|Action' => 18, 'ANI|Animation' => 18, 'ARM|Arts martiaux' => 18, 'AVE|Aventure' => 18, 'AVP|Avant-première' => 18, 'BIO|Biopic' => 18, 'BOL|Bollywood' => 18, 'CIC|Ciné-concert' => 18,
                         'CIE|Cinéma jeune public' => 18, 'CLA|Classique' => 18, 'COD|Comédie dramatique' => 18, 'COM|Comédie' => 18, 'DEA|Dessin animé' => 18, 'DIV|Divers' => 18, 'DOC|Documentaire' => 18, 'DRA|Drame' => 18, 'EPO|Epouvante-horreur' => 18, 'ERO|Erotique' => 18,
                         'ESP|Espionnage' => 18, 'FAN|Fantastique ' => 18, 'FCE|Comédie érotique' => 18, 'FFA|Famille' => 18, 'GUE|Guerre' => 18, 'HIS|Historique' => 18, 'JUD|Judiciaire' => 18, 'MED|Médical' => 18, 'MOB|Mobisode' => 18, 'MUS|Musical' => 18,
                         'NUI|Nuit à thème (cinéma)' => 18, 'PEP|Péplum' => 18,  'POL|Policier' => 18, 'ROM|Romance' => 18, 'SCF|Science fiction' => 18, 'SOA|Soap' => 18, 'THR|Thriller' => 18,
                         'WEB|Web série' => 18, 'WES|Western' => 18, '131F|Cinéma' => 18, 18, '13CI|Cinéma' => 18, 'ROC|Retransmission Opéra/Concert ;' => 18,
                        );
 
     // suite array
	
	                       
    foreach ($flux->product as $item) {
		

  
    $titre = addslashes($item->name);
    $price = $item->price;
    $url_fnac = $item->deepLink;
    $date_debut_sortie = $item->validFrom;
    $date_fin_sortie = $item->validTo;
    $street = addslashes($item->terms);
    $photo = $item->largeImage;
    $genre = $item->merchantCategoryPath;
	$description = 'Une sortie proposé par notre parnetaire Fnac, trouvez la sortie du moment qui vous correspond';
	
     
   
   
 
    // On fait un explode afin de récupérer ce qu'il nous interesse
    $postcode  = $item->extra2;
    $pieces = explode(" ", $postcode);
 
    // On attribut le département en fonction des 2 premiers chiffre du code postal
    $departement = substr($postcode, 0, 2);
     
    $region = regionIdByDepartement($departement);
     
    // Attribution de la valeur id 1010 pour la fnac
    $id_simply_user = '999';
     
    // On valide la sortie par default
    $valide = '1';
	
	
	foreach (explode(' ; ', /*(string)*/ $item->merchantCategoryPath) as $subtype) {
    $id_type_loisirs = $type[$subtype];
    
	$result = mysql_query('SELECT id_loisirs FROM loisirs WHERE titre = $titre, city = $pieces[2], postcode = $pieces[0], date_debut_sortie = $date_debut_sortie, date_fin_sortie = $date_fin_sortie');
	if(mysql_num_rows($result) > 0)
	{ 
	
	$sql = "INSERT INTO `matable` (id_simply_user,titre,price,photo,url_fnac,date_debut_sortie,date_fin_sortie,description,street,postcode,city,id_region,id_departements,id_type_loisirs,valide) VALUES ('$id_simply_user','$titre','$price','$photo','$url_fnac','$date_debut_sortie','$date_fin_sortie','$description','$street','$pieces[0]','$pieces[2]','$region','$departement','$id_type_loisirs','$valide')";
    $req = mysql_query($sql) or die('Erreur SQL !'.$sql.'<br>'.mysql_error());
    echo 'données inserées en base';
	} 
}
	
}
  
?>

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

23 juin 2015, 19:10

Tu y es presque, il te faut simplement combiner ça
$result = mysql_query('SELECT id_loisirs FROM loisirs WHERE titre = $titre, city = $pieces[2], postcode = $pieces[0], date_debut_sortie = $date_debut_sortie, date_fin_sortie = $date_fin_sortie');
et ça :
A priori ta requête va aussi faire des erreurs car pour les colonnes de type chaine de caractères, les valeurs doivent être délimitées avec ' ou "
(penser à traiter les cas où la chaine contiendrait des ' ou ").
;)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphant du PHP | 372 Messages

23 juin 2015, 20:36

Alors j'ai mis des " comme vous me l'avez recommandé, l'insertion se fait bien en bdd mais pour vérifier si l'annonce existe djà ca ne marche pas, des doublons sont toujours présent .....
Une erreur encore ?

J'ai le massage suivant :
Warning: mysql_num_rows() expects parameter 1 to be resource, boolean given in C:\wamp\www\csv\index.php on line 142

Cette ligne correspond à :
$result = mysql_query("SELECT id_loisirs FROM loisirs WHERE titre = ".$titre.", city = ".$pieces[2].", postcode = ".$pieces[0].", date_debut_sortie = ".$date_debut_sortie.", date_fin_sortie = ".$date_fin_sortie."");
	if(mysql_num_rows($result) == 1){
Le code :
<?php
     
    include("include/variables.php");
     
    //connection a la base de donnee
    $dbhost = "localhost";
    $dbuser = "root";      // mysql user
    $dbpass = "";       // mysql password
    $dbname = "mabase";     // mysql database
    $conn=mysql_connect($dbhost,$dbuser,$dbpass) or die(erreurServeurMySQL());
    mysql_select_db($dbname,$conn) or die('Erreur de selection '.mysql_error()); // problème sur la bdd
      
    $flux = simplexml_load_file('http://localhost/csv/zxpd_201506220436_3467_31592008.xml'); // Source du flux.xml
	
	//set_time_limit(20);
	
	// $aLoisirs = array (1 => 'Restaurant', 2 => 'Discothèque', 3 => 'Bar/Pub', 4 => 'Videgrenier/Brocante', 5 => 'Marché', 6 => 'Sport', 7 => 'Loto', 13 => 'Exposition', 10 => 'Divers', 10 => 'Concert', 11 => 'Spectacle', 12 => 'Rencontre', 13 => 'Excursion/Visite', 14 => 'Bal/Festival', 15 => 'Théatre', 16 => 'Classique', 17 => 'Salons et foires',  18 => 'Cinéma', 20 => 'Coffrets cadeau'  );
     
	 
	
	 
    $type  = array(     
                          
            			 // Coffret cadeau
                         'CCA|Carte cadeau' => 20, 'COB|Coffrets Bien-être' => 20, 'COS|Coffrets Séjours' => 20, 'COG|Coffrets Gastronomie' => 20, 'COA|Coffrets Activités' => 20,
                         'COE|Coffrets Enfants' => 20, 'CHM|Coffrets Homme' => 20, 'COS|Coffrets Femme' => 20, ' CPS|Coffrets Sport/Pilotage' => 20, ' CAO|Coffrets Originaux/Atypiques' => 20,
                         'CMT|Coffrets Multithématiques' => 20, 'CLU|Coffrets luxe' => 20, 'CDI|Coffrets divers' => 20,
                          
                         // Cinéma
                         'FIL|Film' => 18, 'ACI|Abonnement/Pass cinéma' => 18, 'ACT|Action' => 18, 'ANI|Animation' => 18, 'ARM|Arts martiaux' => 18, 'AVE|Aventure' => 18, 'AVP|Avant-première' => 18, 'BIO|Biopic' => 18, 'BOL|Bollywood' => 18, 'CIC|Ciné-concert' => 18,
                         'CIE|Cinéma jeune public' => 18, 'CLA|Classique' => 18, 'COD|Comédie dramatique' => 18, 'COM|Comédie' => 18, 'DEA|Dessin animé' => 18, 'DIV|Divers' => 18, 'DOC|Documentaire' => 18, 'DRA|Drame' => 18, 'EPO|Epouvante-horreur' => 18, 'ERO|Erotique' => 18,
                         'ESP|Espionnage' => 18, 'FAN|Fantastique ' => 18, 'FCE|Comédie érotique' => 18, 'FFA|Famille' => 18, 'GUE|Guerre' => 18, 'HIS|Historique' => 18, 'JUD|Judiciaire' => 18, 'MED|Médical' => 18, 'MOB|Mobisode' => 18, 'MUS|Musical' => 18,
                         'NUI|Nuit à thème (cinéma)' => 18, 'PEP|Péplum' => 18,  'POL|Policier' => 18, 'ROM|Romance' => 18, 'SCF|Science fiction' => 18, 'SOA|Soap' => 18, 'THR|Thriller' => 18,
                         'WEB|Web série' => 18, 'WES|Western' => 18, '131F|Cinéma' => 18, 18, '13CI|Cinéma' => 18, 'ROC|Retransmission Opéra/Concert ;' => 18,
                        );
 
     
	
	                       
   foreach ($flux->product as $item) {
		

  
    $titre = addslashes($item->name);
    $price = $item->price;
    $url_fnac = $item->deepLink;
    $date_debut_sortie = $item->validFrom;
    $date_fin_sortie = $item->validTo;
    $street = addslashes($item->terms);
    $photo = $item->largeImage;
    $genre = $item->merchantCategoryPath;
	$description = 'Une sortie proposé par notre parnetaire Fnac, trouvez la sortie du moment qui vous correspond';
	
    // On fait un explode afin de récupérer ce qu'il nous interesse
    $postcode  = $item->extra2;
    $pieces = explode(" ", $postcode);
 
    // On attribut le département en fonction des 2 premiers chiffre du code postal
    $departement = substr($postcode, 0, 2);
     
    $region = regionIdByDepartement($departement);
     
    // Attribution de la valeur id 1010 pour la fnac
    $id_simply_user = '999';
     
    // On valide la sortie par default
    $valide = '1';
	
	
	foreach (explode(' ; ', /*(string)*/ $item->merchantCategoryPath) as $subtype) {
	$id_type_loisirs = $type[$subtype];
  
 
	$result = mysql_query("SELECT id_loisirs FROM loisirs WHERE titre = ".$titre.", city = ".$pieces[2].", postcode = ".$pieces[0].", date_debut_sortie = ".$date_debut_sortie.", date_fin_sortie = ".$date_fin_sortie."");
	if(mysql_num_rows($result) == 1){
		
	// déjà existant
	echo 'Cette entrée existe déjà';
	
	}else{
		
	// Pseudo libre
	$sql = "INSERT INTO `matable` (id_simply_user,titre,price,photo,url_fnac,date_debut_sortie,date_fin_sortie,description,street,postcode,city,id_region,id_departements,id_type_loisirs,valide) VALUES ('$id_simply_user','$titre','$price','$photo','$url_fnac','$date_debut_sortie','$date_fin_sortie','$description','$street','$pieces[0]','$pieces[2]','$region','$departement','$id_type_loisirs','$valide')";
	$req = mysql_query($sql) or die('Erreur SQL !'.$sql.'<br>'.mysql_error());
	echo 'Insertion en bdd';
	} 
	  
	
	  }  
	}
?>
Merci à vous

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

24 juin 2015, 09:04

Ce message d'erreur indique que le résultat retourné par ta requête n'est pas valide. Cela signifie dans la majorité des cas que ta requête a généré une erreur (le code SQL n'a pas pu être correctement interprété). Il faut donc chercher dans la requête qui est exécuté, le "pourquoi du qu'est-ce qui lui plait pas" (si si, c'est le terme officiel :p)

En l’occurrence, tu as toujours un problème de délimitation des chaines de caractères. En SQL, une chaine de caractère (type : char, varchar, text, date, ...) doit impérativement être délimité par des apostrophes (pour que le moteur de base de données puisse savoir où elle commence et où elle finie :)). Seuls les nombres (type : int, float, double, number, ...) n'ont pas besoin (et ne doivent pas) être délimité avec des apostrophes :
SELECT ... FROM ... WHERE ma_chaine = 'mon texte' AND mon_nombre = 42
L'autre problème, c'est la séparation des conditions dans la clause WHERE pour laquelle il faut utiliser des opérateurs AND, OR, ... et non pas des virgules :)

A partir de là, le mieux pour construire ta requête SQL en php et éviter ce genre d'erreur, c'est de partir du résultat que tu veux obtenir :
SELECT id_loisirs FROM loisirs WHERE titre = 'mon_titre' AND city = 'ma_ville' AND postcode = 'mon_cp' AND date_debut_sortie = 'ma_date' AND  date_fin_sortie = 'mon_autre_date'
Tu mets tout ça dans une variable php (ça te permet de faire un echo pour vérifier la requête qui sera envoyé)
$sql = "SELECT id_loisirs FROM loisirs WHERE titre = 'mon_titre' AND city = 'ma_ville' AND postcode = 'mon_cp' AND date_debut_sortie = 'ma_date' AND  date_fin_sortie = 'mon_autre_date' ";
Tu remplaces avec tes variables
$sql = "SELECT id_loisirs FROM loisirs WHERE titre = '" . $titre . "' AND city = '" . $pieces[2] . "' AND postcode = '" . $pieces[0] . "' AND date_debut_sortie = '" . $date_debut_sortie . "' AND  date_fin_sortie = '" . $date_fin_sortie . "' ";
Et tu peux ensuite exécuter et tester le résultat de la requête :
// echo $sql; // si tu veux vérifier à quoi ressemble la requête générée
$result = mysql_query($sql);
if (mysql_num_rows($result) > 0) { // au cas où il y en aurait 2 identiques en base, le test == 1 serait faux, alors que > 0 sera vrai :)
...
}
Et pour être vraiment complet, il faudrait t'assurer que les variables que tu utilises dans ta requête ne contiennent pas de caractères susceptibles de la faire planter () :
SELECT ... FROM ... WHERE ma_chaine = 'l'apostrophe dans une chaine doit être protégée, sinon le moteur de bdd considère que la chaine s'arrête à la première apostrophe qu'elle trouve'
Il faut en général doubler l'apostrophe ou l'antislasher (oui, ça aussi c'est un terme technique officiel - antislasher, verbe du premier groupe ;))
SELECT ... FROM ... WHERE ma_chaine = 'l\'apostrophe dans une chaine doit être protégée, sinon le moteur de bdd considère que la chaine s\'arrête à la première apostrophe qu\'elle trouve'
La différence entre ces deux requêtes apparait en couleur :)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

24 juin 2015, 09:24

salut,

vu que ryle m'a coupé l'herbe sous le pieds je ne laisse que la partie 'amélioration du script' ;)

Pour la "fin" du script il est possible que cela soit du au temps que le parse du fichier prend. Par défaut limité à 30s.
Pour optimiser ton code tu peux regarder ce message pour avoir un parse xml plus "rapide" post436657.html#p436657

Ensuite je t'invite à utiliser mysqli ou PDO afin de profiter des requêtes préparées.
Pourquoi ?
Parce que dans la requête le plus long c'est la "compilation" de la requête (terme mal choisis mais le principe est la). Avec une requête préparée cette phase n'est faite qu'une fois et tu ne fournis que les valeurs ;)

Le select dans la boucle c'est moyen et vu que le but c'est de savoir si le la chose est déjà en base un count() (par exemple select count(1) as nb from laTable ) c'est pas plus mal et évite de retourner des données inutile.
Pour l'insert mêle combat la préparation avant la boucle devrait aider en un peu en perf.

oublie addslashes pour la sécurisation des données utilise mysql_real_escape_string (ou mysqli_real_escape_string ou PDO::qote suivant l'extension) ;)

voici un exemple avec ton code.
<?php

include("include/variables.php");

//connection a la base de donnee
$dbhost = "localhost";
$dbuser = "root";      // mysql user
$dbpass = "";       // mysql password
$dbname = "mabase";     // mysql database
$cnx = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);

$flux = simplexml_load_file('http://localhost/csv/zxpd_201506220436_3467_31592008.xml'); // Source du flux.xml

// $aLoisirs = array (1 => 'Restaurant', 2 => 'Discothèque', 3 => 'Bar/Pub', 4 => 'Videgrenier/Brocante', 5 => 'Marché', 6 => 'Sport', 7 => 'Loto', 13 => 'Exposition', 10 => 'Divers', 10 => 'Concert', 11 => 'Spectacle', 12 => 'Rencontre', 13 => 'Excursion/Visite', 14 => 'Bal/Festival', 15 => 'Théatre', 16 => 'Classique', 17 => 'Salons et foires',  18 => 'Cinéma', 20 => 'Coffrets cadeau'  );


$type = array(

    // Coffret cadeau
    'CCA|Carte cadeau' => 20, 'COB|Coffrets Bien-être' => 20, 'COS|Coffrets Séjours' => 20, 'COG|Coffrets Gastronomie' => 20, 'COA|Coffrets Activités' => 20,
    'COE|Coffrets Enfants' => 20, 'CHM|Coffrets Homme' => 20, 'COS|Coffrets Femme' => 20, ' CPS|Coffrets Sport/Pilotage' => 20, ' CAO|Coffrets Originaux/Atypiques' => 20,
    'CMT|Coffrets Multithématiques' => 20, 'CLU|Coffrets luxe' => 20, 'CDI|Coffrets divers' => 20,

    // Cinéma
    'FIL|Film' => 18, 'ACI|Abonnement/Pass cinéma' => 18, 'ACT|Action' => 18, 'ANI|Animation' => 18, 'ARM|Arts martiaux' => 18, 'AVE|Aventure' => 18, 'AVP|Avant-première' => 18, 'BIO|Biopic' => 18, 'BOL|Bollywood' => 18, 'CIC|Ciné-concert' => 18,
    'CIE|Cinéma jeune public' => 18, 'CLA|Classique' => 18, 'COD|Comédie dramatique' => 18, 'COM|Comédie' => 18, 'DEA|Dessin animé' => 18, 'DIV|Divers' => 18, 'DOC|Documentaire' => 18, 'DRA|Drame' => 18, 'EPO|Epouvante-horreur' => 18, 'ERO|Erotique' => 18,
    'ESP|Espionnage' => 18, 'FAN|Fantastique ' => 18, 'FCE|Comédie érotique' => 18, 'FFA|Famille' => 18, 'GUE|Guerre' => 18, 'HIS|Historique' => 18, 'JUD|Judiciaire' => 18, 'MED|Médical' => 18, 'MOB|Mobisode' => 18, 'MUS|Musical' => 18,
    'NUI|Nuit à thème (cinéma)' => 18, 'PEP|Péplum' => 18, 'POL|Policier' => 18, 'ROM|Romance' => 18, 'SCF|Science fiction' => 18, 'SOA|Soap' => 18, 'THR|Thriller' => 18,
    'WEB|Web série' => 18, 'WES|Western' => 18, '131F|Cinéma' => 18, 18, '13CI|Cinéma' => 18, 'ROC|Retransmission Opéra/Concert ;' => 18,
);

$stmtCount = mysqli_prepare($cnx, 'SELECT id_loisirs FROM loisirs WHERE titre = ?, city = ?, postcode =?, date_debut_sortie = ?, date_fin_sortie =?')
$stmtInsert = mysqli_prepare($cnx, 'INSERT INTO `matable` (id_simply_user,titre,price,photo,url_fnac,date_debut_sortie,date_fin_sortie,description,street,postcode,city,id_region,id_departements,id_type_loisirs,valide) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
foreach ($flux->product as $item) {

    $titre = $item->name;
    $price = $item->price;
    $url_fnac = $item->deepLink;
    $date_debut_sortie = $item->validFrom;
    $date_fin_sortie = $item->validTo;
    $street = $item->terms;
    $photo = $item->largeImage;
    $genre = $item->merchantCategoryPath;
    $description = 'Une sortie proposé par notre parnetaire Fnac, trouvez la sortie du moment qui vous correspond';


    // On fait un explode afin de récupérer ce qu'il nous interesse
    $postcode = $item->extra2;
    $pieces = explode(" ", $postcode);

    // On attribut le département en fonction des 2 premiers chiffre du code postal
    $departement = substr($postcode, 0, 2);

    $region = regionIdByDepartement($departement);

    // Attribution de la valeur id 1010 pour la fnac
    $id_simply_user = '999';

    // On valide la sortie par default
    $valide = '1';


    foreach (explode(' ; ', /*(string)*/
        $item->merchantCategoryPath) as $subtype) {
        $id_type_loisirs = $type[$subtype];

        mysqli_stmt_bind_param($stmtCount, 'sssss', $titre, $pieces[2], $pieces[0], $date_debut_sortie, $date_fin_sortie);
        mysqli_stmt_execute($stmtCount);
        mysqli_stmt_bind_result($stmtCount, $result);
        mysqli_stmt_fetch($stmtCount);
        if ($result == 0) {
            mysqli_stmt_bind_param($stmtInsert, 'dssssssssssddds', $id_simply_user, $titre, $price, $photo, $url_fnac, $date_debut_sortie, $date_fin_sortie, $description, $street, $pieces[0], $pieces[2], $region, $departement, $id_type_loisirs, $valide);
            mysqli_stmt_execute($stmtInsert);
            echo 'données inserées en base<br />', PHP_EOL;
        } else {
            echo 'Données ddéjà existante<br />', PHP_EOL;
        }
    }
}
mysqli_stmt_close($stmtCount);
mysqli_stmt_close($stmtInsert);
mysqli_close($cnx);
L'indentation de ton code le rend plus facilement lisible et compréhensible pour les autres ;)

ce code te permet de "sécuriser" (plus ou moins) simplement test données vu que le mécanisme de préparation le fait pour toi.
La version POO de mysqli est plus "lisible", ou mieux PDO cela permet d'avoir un code plus clair.

@+
Il en faut peu pour être heureux ......