- 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>
54 lines
1.5 KiB
PHP
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);
|
|
}
|
|
}
|