Files

83 lines
3.0 KiB
PHP

<?php
require __DIR__ . '/common.php';
/**
* Proxy/cache du flux RSS WordPress natif de silly.be (articles complets
* dans content:encoded, categories, 10 derniers articles). On le re-sert
* sous notre domaine pour garder une URL stable et on corrige atom:link
* rel="self" (il pointe sinon vers silly.be) pour le validateur W3C.
*
* WordPress limite le flux a 10 articles (reglage du site, non modifiable
* d'ici) mais accepte ?paged=N : on concatene NEWS_PAGES pages pour
* obtenir jusqu'a 50 articles.
*/
const NEWS_FEED_URL = 'https://www.silly.be/actualites/feed/';
const NEWS_PAGES = 5; // 5 x 10 = 50 articles
const SELF_URL = 'https://sillycone-village.be/silly-rss/actualites.php';
function build_news_feed(): string
{
$raw = http_get(NEWS_FEED_URL, ['Accept: application/rss+xml, application/xml']);
$doc = new DOMDocument();
if (!@$doc->loadXML($raw)) {
throw new RuntimeException('Flux WordPress illisible (XML invalide)');
}
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
$selfLinks = $xpath->query('/rss/channel/atom:link[@rel="self"]');
if ($selfLinks->length === 0) {
throw new RuntimeException('Reponse inattendue : pas un flux RSS');
}
foreach ($selfLinks as $selfLink) {
$selfLink->setAttribute('href', SELF_URL);
}
// WordPress emet <sy:updatePeriod>\n\thourly\t</sy:updatePeriod> : on retire
// les blancs parasites autour des valeurs.
$xpath->registerNamespace('sy', 'http://purl.org/rss/1.0/modules/syndication/');
foreach ($xpath->query('/rss/channel/sy:*') as $node) {
$node->textContent = trim($node->textContent);
}
// Pages suivantes : un echec (ou une page vide) arrete simplement la
// pagination, la premiere page suffit a servir un flux valide.
$channel = $xpath->query('/rss/channel')->item(0);
$seen = [];
foreach ($xpath->query('/rss/channel/item/guid') as $g) {
$seen[trim($g->textContent)] = true;
}
for ($page = 2; $page <= NEWS_PAGES; $page++) {
try {
$more = new DOMDocument();
$raw = http_get(NEWS_FEED_URL . '?paged=' . $page, ['Accept: application/rss+xml, application/xml']);
if (!@$more->loadXML($raw)) {
break;
}
} catch (Throwable $e) {
break;
}
$added = 0;
$moreXpath = new DOMXPath($more);
foreach ($moreXpath->query('/rss/channel/item') as $item) {
// Le tri de WordPress n'est pas stable entre articles de meme
// date : on dedoublonne par guid aux jonctions de pages.
$guid = trim($moreXpath->evaluate('string(guid)', $item));
if ($guid === '' || isset($seen[$guid])) {
continue;
}
$seen[$guid] = true;
$channel->appendChild($doc->importNode($item, true));
$added++;
}
if ($added === 0) {
break;
}
}
return $doc->saveXML();
}
serve_cached_feed('actualites', 'build_news_feed');