Vu que le site est maintenant hébergé chez un vrai hébergeur, je suis obligé de lancer mon script Perl par un script PHP, appelé regulièrement par le site http://crontab.fr. Je remercie d'ailleurs les administrateurs de Lost-Oasis qui ont accepté d'installer les modules Perl dont j'avais besoin.
Création des tables SQL
-- -- Table structure for table `rss_items` -- CREATE TABLE `rss_items` ( `id` int(11) NOT NULL auto_increment, `id_who` bigint(20) unsigned NOT NULL default '0', `title` varchar(255) default NULL, `link` varchar(255) default NULL, `date` date default NULL, PRIMARY KEY (`id`), UNIQUE KEY `ITEM` (`id_who`,`link`) ) TYPE=MyISAM; -- -- Table structure for table `rss_sites` -- DROP TABLE IF EXISTS `rss_sites`; CREATE TABLE `rss_sites` ( `id` bigint(20) unsigned NOT NULL auto_increment, `name` varchar(25) NOT NULL default '', `url` varchar(255) NOT NULL default '', `lastmodified` varchar(255) default NULL, `etag` varchar(255) default NULL, `inactive` tinyint(3) unsigned NOT NULL default '0', PRIMARY KEY (`id`) ) TYPE=MyISAM;
fetch_rss.pl
C'est le script central, celui qui récupère les RSS, les traite, et les stocke en base de données. Les nouveautés sont: récupération des sites à visiter depuis la base de données, utilisation des headers HTTP, ce qui oblige d'utiliser une API plus complexe, reconnexion à la base de données en cas de perte de la connexion.
#!/usr/bin/perl # use LWP::UserAgent; use XML::LibXML; use DateTime; use DateTime::Format::HTTP; use DateTime::Format::DBI; use DBI; use strict; use warnings; my $db_type = "mysql"; my $db_user = "username"; my $db_pass = "password"; my $db_hostname = "dbhostname"; my $db_database = "database"; my $db_table_items = "rss_items"; my $db_table_sites = "rss_sites"; my $xmlparser = XML::LibXML->new(); my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $dsn = "DBI:$db_type:database=$db_database;host=$db_hostname"; my $dbh = DBI->connect($dsn, $db_user, $db_pass) or die "La connexion à la base de données a échouée : " . $DBI::errstr; $dbh->{mysql_auto_reconnect} = 1 if $db_type eq "mysql"; my $friends = $dbh->selectall_hashref("SELECT id, name, url, lastmodified, etag FROM $db_table_sites WHERE inactive=0", 'id') or die "Erreur lors de la récupération des sites : " . $dbh->errstr; my $dateparser = DateTime::Format::DBI->new($dbh); my $sth = $dbh->prepare("INSERT IGNORE INTO $db_table_items SET id_who=?, title=?, link=?, date=?") or die "Erreur lors de la préparation sql : " . $dbh->errstr; my $sth2 = $dbh->prepare("UPDATE $db_table_sites SET etag=?, lastmodified=? WHERE id=?") or die "Erreur lors de la préparation sql : " . $dbh->errstr; foreach my $friend_id (keys %$friends) { my $friend = $friends->{$friend_id}; next unless $friend->{url}; my %headers = (); $headers{"If-Modified-Since"} = $friend->{lastmodified} if ($friend->{lastmodified}); $headers{"If-None-Match"} = $friend->{etag} if ($friend->{etag}); my $response = $ua->get( $friend->{url}, %headers ); print($friend->{name}, " : 304\n"), next if $response->code == 304; warn("N'a pas réussi à prendre le rss de " . $friend->{name} . " : " . $response->status_line), next unless $response->is_success; my $content = $response->content; my $etag = $response->header("Etag"); my $lastmodified = $response->header("Last-Modified"); $sth2->execute($etag, $lastmodified, $friend_id) or die "L'éxecution SQL a échoué : " . $sth->errstr; my $rss; eval { $rss = $xmlparser->parse_string($content) }; do { warn $friend->{name}, " : ", $@; next; } if $@; my @items = $rss->getElementsByLocalName("item"); foreach my $item (@items) { my ($title, $link, $date); my $child = $item->firstChild(); while ($child) { next unless $child->localname; $title = $child->textContent if $child->localname =~ /^title$/; $link = $child->textContent if $child->localname =~ /^link$/; $date = $child->textContent if $child->localname=~ /^date$/; $date = $child->textContent if $child->localname=~ /^pubDate$/; } continue { $child = $child->nextSibling(); } if ($date) { $date = DateTime::Format::HTTP->parse_datetime($date); } else { $date = DateTime->now(); } $sth->execute($friend_id, $title, $link, $dateparser->format_datetime($date)) or die "L'éxecution SQL a échoué : " . $sth->errstr; } } $sth->finish; $dbh->disconnect();
fetch_rss.php
Ce fichier exécute fetch_rss.pl et affiche le résultat si le script a échoué ou si le paramètre debug est placé à 1.
<? $dir = dirname(FILE); exec("$dir/../scripts/fetch_rss.pl 2>&1", $output, $retval); if ($retval != 0 || $_GET'debug' == 1) { echo "<br>$retval<br>"; echo nl2br(join("\n", $output)); } ?>
Récupération depuis un script
Je récupère ensuite les données avec la requête suivante :
SELECT rs.name who, ri.link link, ri.title title FROM rss_items ri, rss_sites rs WHERE (TO_DAYS(ri.date) > (TO_DAYS(CURDATE()) - 7)) AND rs.id = ri.id_who AND rs.inactive = 0 ORDER BY who ASC, ri.date DESC, ri.id DESC