8721 sujets

Développement web côté serveur, CMS

Bonjour,

J'ai écrit un script qui me permet de rentrer les informations d'un flux RSS dans une base de donnée. Le problème est que je ne sais pas gérer les doublons, à chaque fois que j'actualise m'a page, toutes les actualités sont à nouveau entrés.

Voici le code :

<?php
		try{
			if(!@$fluxrss=simplexml_load_file('http://www.alsacreations.com/rss/actualites.xml')){
			throw new Exception('Flux introuvable');
			}
			if(empty($fluxrss->channel->title) || empty($fluxrss->channel->item->title))
				throw new Exception('Flux invalide');
				
				$i = 0;
				$arreter = 10;
				
				foreach($fluxrss->channel->item as $item){
					
					/*Les Varialbles*/
					$site = 'Alsacréation.fr';
					$link = (string)$item->link;
					$title= (string)$item->title;
					$author= (string)$item->author;
					$date =  date('Y-m-d H:i',strtotime($item->pubDate));
				
					/*Requetter*/
					$req = $bdd->prepare(
					
					'INSERT INTO matable(
					
					site,
					title,
					link,
					pubdate,
					author)
					
					VALUES(
					:site, 
					:title,
					:link, 
					:pubdate,
					:author)'
					
					);
					
					$req->execute(array(
						'site' => $site,
						'title'=> $title,
						'link' => $link,
						'pubdate' => $date,
						'author' => $author
					));
					
					$i++;
					if($i>$arreter)
					break;
				}
			}
			catch(Exception $e){
				echo $e->getMessage();
			}
		?>


Merci pour votre aide.
Modifié par rmim22 (26 Apr 2013 - 11:55)
Bonjour,

Pour dédoublonner, il faut que tu puisses détecter les doublons.
Ce que tu peux faire très simplement, c'est trouver une clé unique.
Comme tu n'en as pas dans le RSS, tu prends le champs title et tu fais un hash dessus.
Dans ta base de données, ajoute une colonne qui te servira de primary key et dans laquelle tu placeras ce hash.
Quand tu feras ton second appel, tu pourras intercepter l'erreur MySQL t'indiquant un doublon dans la base de données et n'enregistrer que les nouveaux champs.
J'espère avoir été clair...

@+

Sam
Merci pour ta réponse.

Etant débutant c'est assez compliqué pour moi.

N'est t'il pas possible de faire simplement une comparaison avec les liens des articlse ? Et ajouter un liens si il n'est pas présent dans la base ?
Modifié par rmim22 (26 Apr 2013 - 15:33)
Modérateur
Salut,


Je ne comprends pas trop l’intérêt du hash. Il y a plus simple :

- Récupérer la date d'édition et le titre
- comparer les valeurs récupérées avec la tables "actualites"
- insérer s'il y a aucune valeur trouvée dans la base
Modifié par niuxe (26 Apr 2013 - 20:25)
Comme le dit kodakgold un hash est une bonne idée car la longeur des index est limités a 767 octets et tu peux éventuellement tomber sur des titles ou des urls qui dépassent cette taille.

Ton idée d'utiliser l'URL est à mon avis meilleure que prendre le titre ou d'autres valeurs car elle sont susceptibles d'être modifiées alors que pour l'URL tu as beaucoup moins de chance que ce soit le cas.

Moi j'ajouterai une colonne url_hash que tu peuples avec un sha1($link). Tu indexes cette colonne en UNIQUE. Le hash sha1 occupant 40 octets, tu n'auras pas de risque de dépassement de la longueur de l'index :


ALTER TABLE matable ADD UNIQUE (
url_hash
)


Après tu n'as pas qu'à faire tes insertions normalement avec INSERT IGNORE, ce qui te permet de ne pas faire l'insertion si ta clé url_hash existe déjà.


$req = $bdd->prepare(
					
					'INSERT IGNORE INTO matable(
					
					site,
					title,
                                        url_hash,
					link,
					pubdate,
					author)
					
					VALUES(
					:site, 
					:title,
					:link, 
                                        :url_hash,
					:pubdate,
					:author)'
					
					);


Voilà.

Un dernier point qui n'a pas à voir avec ta question : sort $req = $bdd->prepare... de ta boucle foreach et place le avant. Car là tu fais ton prépare à chaque itération de boucle et tu exécutes la requête juste après alors que justement les requêtes préparées sont faites pour préparer une fois et exécuter plusieurs fois.
Modérateur
jb_gfx a écrit :
Comme le dit kodakgold un hash est une bonne idée car la longeur des index est limités a 767 octets et tu peux éventuellement tomber sur des titles ou des urls qui dépassent cette taille.



Peux tu développer stp ? Je comprends pas pourquoi cette manip.

Suivant l'exemple ci-dessous, quil y ait un hash ou pas ($strA != $strC), le résultat sera forcément le même :

<?php
    $strA = "hello-world";
    $strB = "hello-world";
    
    echo $strA == $strB ? 'ok' : 'ko';
    $strA = sha1($strA);
    $strB = sha1($strB);
    echo "<hr />";
    echo $strA == $strB ? 'ok' : 'ko';
    
    
    echo "<hr />";
    $strC = "Hello-World";
    echo $strA == $strC ? 'ok' : 'ko';
    $strC = sha1($strC);
    echo "<hr />";
    echo $strA == $strC ? 'ok' : 'ko';
    
?>

Modifié par niuxe (29 Apr 2013 - 09:26)
La taille d'un index dans les bases de données sont limitées en taille. Et donc mettre en clé primaire un titre ou une URL, c'est s'exposer à planter sa fonction.

L'avantage du hash sur ce coup-là, c'est qu'il limite la taille à une valeur fixe, inférieure à la limite de longueur des index. Ce qui permet d'utiliser dans le mysql "insert ignore" qui n'insèrera le nouveau flux que s'il n'existe pas un flux avec le même hash.

Ce qui évite donc de devoir faire en php une comparaison entre l'intégralité de la base de données et le nouveau flux.
Merci pour vos réponses.

Dernière chose, comment faire la vérification que le hash n'est pas déjà contenu dans la base ?

Merci
Tu ne vérifies pas ^^

dans ta requête d'insertion, il suffit d'ajouter un ignore (insert ignore into ma_table ...). Automatiquement, le mysql va ignorer les insertions dont la clé primaire (le hash) correspond à une clé déjà existante.
Maintenant aucun flux ne rentre dans ma base. Pour tester j'ai supprimé toutes les actus contenu dans la base, et aucune ne s’insère dedans en actualisant la page.

<?php
		

	$n=0;
	$tab = array();
			
	// Récupération des sites enregistés dans la BDD
	$site = $bdd->query('SELECT * FROM site LIMIT 0,10');
	while($info = $site->fetch())
	{
		$tab[$n]['flux']= $info['flux'];
		$tab[$n]['nom']= $info['nom'];
			
		$n++;
	}
	$site->closeCursor();
				
			
	$z=0;
	for($z=0;$z<sizeof($tab);$z++)
	{
	        try{
		/*Récupération des données du flux XML*/
		if(!@$fluxrss=simplexml_load_file($tab[$z]['flux'])){
			throw new Exception('Flux introuvable');
		}
		// Vérification du flux XML
		if(empty($fluxrss->channel->title) || empty($fluxrss->channel->item->title))
		throw new Exception('Flux invalide');
					
		$i = 0;
		$arreter = 10;
					
		/*Préparation Requete*/
		$req = $bdd->prepare(
							
		'INSERT INGORE INTO evect(
							
		site,
		title,
		link,
		hash_link,
		pubdate,
		author)
							
		VALUES(
		:site, 
		:title,
		:link,
		:hash_link,
		:pubdate,
		:author)'
							
		);
					
		foreach($fluxrss->channel->item as $item)
		{
						
			/*Assignation des Variables*/
			$site = $tab[$z]['nom'];
			$link = (string)$item->link;
			$hash_link = sha1($link);
			$title= (string)$item->title;
			$author= (string)$item->author;
			$date =  date('Y-m-d H:i',strtotime($item->pubDate));
									
			/*Insertion valeurs*/
			$req->execute(array(
			'site' => $site,
			'title'=> $title,
			'link' => $link,
			'hash_link' => $hash_link,
			'pubdate' => $date,
			'author' => $author
			));
						
			$i++;
			if($i>$arreter)
			break;
		        }
		}
		catch(Exception $e){
		echo $e->getMessage();
	}
}

		
/*Afficher le resultat*/
$reponse = $bdd->query('SELECT * FROM evect ORDER BY pubdate DESC LIMIT 0,100');
while($donnees = $reponse->fetch()) 
{
       echo stripslashes($donnees['title']).'<br/> Le '.stripslashes($donnees['pubdate']).'<br/> Par : '.stripslashes($donnees['site']).'<br/><br/>';
}
$reponse->closeCursor();
			
		?>

Modifié par rmim22 (29 Apr 2013 - 10:19)