presseportale/app/Support/FeedReaderIdentifier.php
Kevin Adametz 44d0bb6f29 web: Abruf-Protokoll der RSS-Feeds — Reader-Dienst, gemeldete Abonnenten, Admin-Bericht, Panel (Roadmap 3.1)
- feed_fetches: jeder Feed-Abruf mit Art, Schlüssel, Portal, Sprache,
  erkanntem Reader (config/feeds.php, FeedReaderIdentifier), vom Dienst
  gemeldeter Abonnentenzahl und gekürztem User-Agent — keine IP. Schreiben
  per defer() nach der Antwort, auch bei Cache-Treffer.
- Aufbewahrung 395 Tage über press-releases:purge-events;
  FEED_FETCHES_RECORDED_SINCE.
- Admin ▸ Reports ▸ Indexierung & Abrufe: Block „Abrufe der RSS-Feeds"
  (Summen je Feed-Art, je Reader-Dienst, meistabgerufene Feeds;
  FeedFetchReport, Verdichtung in PHP für MySQL und SQLite).
- Panel „Auslieferung": Abrufe je Feed in 30 Tagen; RSS-Seite nennt die
  Zählung ohne IP.
- Tests: FeedFetchLogTest (5), IndexStatusCheckTest erweitert.
- dev/2026-09-01: Nachtrag Protokoll Teil 11, Roadmap 3.1; 0.7 gilt auch
  für Crawler- und Feed-Log.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:00:09 +00:00

54 lines
1.5 KiB
PHP

<?php
namespace App\Support;
/**
* Ordnet den User-Agent eines Feed-Abrufs einem bekannten Reader-Dienst zu
* (config/feeds.php) und liest die vom Dienst gemeldete Abonnentenzahl.
* Null, wenn kein Dienst passt — der Abruf wird trotzdem gezählt, als
* „Sonstige".
*/
class FeedReaderIdentifier
{
public static function identify(?string $userAgent): ?string
{
if ($userAgent === null || trim($userAgent) === '') {
return null;
}
/** @var array<string, array{label: string, patterns: list<string>}> $readers */
$readers = config('feeds.readers', []);
foreach ($readers as $key => $reader) {
foreach ($reader['patterns'] as $pattern) {
if (stripos($userAgent, $pattern) !== false) {
return $key;
}
}
}
return null;
}
/**
* Abonnentenzahl, wie Feedly, Inoreader, NewsBlur, Feedbin & Co. sie im
* User-Agent nennen („12 subscribers"). Null, wenn nichts angegeben ist.
*/
public static function subscribers(?string $userAgent): ?int
{
if ($userAgent === null || preg_match('/(\d{1,7})\s+subscribers?/i', $userAgent, $match) !== 1) {
return null;
}
return (int) $match[1];
}
public static function label(?string $reader): string
{
if ($reader === null) {
return __('Sonstige');
}
return (string) (config('feeds.readers.'.$reader.'.label') ?? $reader);
}
}