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
