Zwar wird behauptet, RSS sei tot und man würde das bedauern, aber nichtsdestotrotz wollte ich letztens RSS nutzen. Nutzen heißt insofern, einen RSS-Feed auszulesen und darzustellen. Das musste auch zwangsläufig mit PHP passieren aufgrund der bereits bestehenden Umgebung. Man sollte meinen, dass dies eine Standardaufgabe sei, schließlich gibt es den Composer und nicht zuletzt Packagist, also Library installieren, Abhängigkeiten auflösen und einfach nur nutzen.
Suchen mit Packagist
Tatsächlich waren die ersten Schritte in der Art recht simpel, ich habe mich erstmal auf Packagist umgeschaut und auf die Suche nach einer passenden RSS-Library begeben. Falls man hier einschreiten und fragen möchte, warum überhaupt Library, schließlich hätte da auch ein Request der Feed-URL und anschließendes Parsen mit SimpleXML, DOM o.ä. gereicht, RSS ist ja nichts Anderes als ein XML-Dialekt, der sich prima mit PHP-eigenen Funktionen bzw. Klassen bearbeiten lässt. Alles richtig, nur wäre das Ergebnis letztlich wieder eine Art RSS-Library gewesen, die die Schritte vom Request, Verarbeitung, Fehlerbehandlung und Ausgabe in irgend einer Form zusammengefasst hätte. Und dem NIH-Syndrom wollte ich diesmal nicht erliegen, wenn es da draußen doch mit Sicherheit etliche, gut gepflegte und viel genutzte RSS-Libraries geben würde.
Finden mit Packagist
Die Suche förderte auch etliche RSS-Libraries zutage. Die Präsentation der Suchergebnisse ist jedoch – sagen wir mal verbesserungswürdig. Dabei fällt mir auf, dass dies bisher bei jeder Suche auf Packagist der Fall war. Man erhält etliche Suchergebnisse, aber die genaue Anzahl wird einem verschwiegen. Allenfalls kann man diese näherungsweise schätzen angesichts der Angaben bei „Package Type“ oder den „Tags“. Viel schlimmer ist jedoch, dass ich die Reihenfolge nicht nachvollziehen kann – nach welchen Kriterien werden die Suchergebnisse angezeigt? Anzahl der Downloads können es nicht sein, ansonsten würde nicht zend-feed mit über 5 Mio. Downloads hinter simplepie stehen (über 1 Mio. Downloads). Dasselbe trifft auf die Bewertungs-„Stars“ zu, denn diese sind munter gemischt. Alphabetische Sortierung fällt ebenfalls weg. Aber noch schlimmer – ich habe auch keine Möglichkeit, die Sortierreihenfolge zu beeinflussen. Vielleicht würde ich gerne die Anzahl der Downloads oder die Bewertung als Kriterium nutzen. Eine solche Funktion ist jedoch nicht vorhanden. Gehe ich davon aus, dass irgend ein interpolierter Wert aus Downloads, Bewertungen, Quersumme des Hex-Codes des Namens oder was auch immer verwendet wird, scheint es sich eher zu lohnen, die erste Ergebnisseite näher zu betrachten als weiter zu blättern.
Konkret fanden sich darunter nicht nur RSS-Libraries zum Lesen von RSS-Feeds, sondern auch zur Generierung und insbesondere zur Einbindung in Frameworks wie Symfony oder Laravel. Da ich Letzteres nicht benötigt habe und ebenso keinen Feed schreiben wollte, blieb die Auswahl zwischen simplepie/simplepie, zendframework/zend-feed, dg/rss-php, debril/feed-io, fastfeed/fastfeed und vielleicht noch yuzuru-s/parse-rss und vinelab/rss.
Ein näherer Blick auf RSS-Libraries
Beginnen wir am Ende der Liste – vinelab/rss. Der Blick auf die github-Seite zeigte, dass die letzten Änderungen drei Jahre zurück liegen, es sind drei offene Issues und drei Pull-Requests vorhanden. Damit würde ich die Library als nicht sonderlich aktiv gepflegt bezeichnen – und alles Weitere hatte sich schon wieder erledigt. Dasselbe gilt für yuzuru-s/parse-rss, einerseits die letzten Änderungen von vor zwei Jahren, andererseits auch der sehr überschaubare Umfang, noch dazu wird ein Filecache implementiert, den ich aber so nicht verwenden konnte, ergo fiel auch diese Library gleich wieder aus der Auswahl. Auch fastfeed habe ich mir aufgrund des Alters und offener Issues bzw. Pull-Requests nicht näher angeschaut. Die Library dg/rss-php schien mir wiederum sehr ähnlich zu parse-rss, zumindest vom Umfang her war es nicht mehr als ein Wrapper um die SimpleXML-Funktionen, darüber hinaus wieder ein in meinem Kontext nicht nutzbarer, aber nicht vermeidbarer File-Cache.
SimplePie
Somit blieben simplepie, zend-feed und feed-io in der engeren Wahl. Die dienstälteste Bibliothek SimplePie ist dabei so etwas wie das eierlegende Wollmilchfrettchen. Immerhin wird sie noch aktiv entwickelt, die letzten Änderungen waren zum Zeitpunkt des Schreibens nur ungefähr zwei Wochen alt. Allerdings merkt man SimplePie das Alter durchaus an – zwar lässt es sich mittels Composer installieren, aber die Anfänge stammen noch aus der Vor-Composer-Ära. Dazu kommt, dass der Umfang wirklich gewaltig ist. Das heißt nicht nur, dass SimplePie etliche Funktionalitäten mitbringt wie zum Beispiel ein Caching-System, das als Backend direkt MySQL, Filesystem, Memcache und Redis unterstützt, sondern dass die zentrale SimplePie-Klassendatei tatsächlich sehr groß ist. Und ich dachte schon, Dateien mit über 3000 Zeilen sind langsam nicht mehr in freier Wildbahn zu finden. Die Dokumentation dazu ist reziprok, und noch dazu meiner Ansicht nach kaum brauchbar. Einzig die API-Dokumentation scheint ein kleiner Lichtblick zu sein. Der Rest ist nicht der Rede wert, das fängt bereits bei der Setup-Seite an, die Composer nicht einmal erwähnt und hört bei den unkommentierten Code-Beispielen noch lange nicht auf, die zwar auch selbsterklärend sind, aber wenn der CSS-Code mehr Raum einnimmt, als die fünf Zeilen zur Benutzung von SimplePie, macht das auf mich einen merkwürdigen Eindruck. Vor allem war es aber der Umfang, der mich abgeschreckt hat, man könnte SimplePie fast schon als eigenes Framework bezeichnen. Insofern habe ich SimplePie erstmal ausgeschlossen.
zend-feed
Auch zend-feed hat zunächst wenig Aufmerksamkeit erhalten. Die Abhängigkeiten sind nicht gerade gering, aber dank Composer schnell aufgelöst. Immerhin ist der Umfang überschaubar, und es fühlte sich wesentlich moderner an als etwa SimplePie. Und zend-feed bedient sich anderer Komponenten des Zend-Framework, um beispielsweise Caching zu realisieren. Dasselbe gilt für HTTP-Requests, wobei sich entweder die entsprechende Komponente des Zend Frameworks nutzen lässt oder aber jeder auf PSR-7-Interface-Ebene kompatible Client. Damit kann zend-feed schon einmal punkten. Dennoch fühlte es sich für mich nicht wirklich gut an, quasi das halbe Zend Framework nutzen zu müssen, wenn es ansonsten in der Umgebung nicht vorkommt. Die Dokumentation ist übrigens in Ordnung, man findet sich leicht zurecht, was wiederum auch daran liegen könnte, dass zend-feed an sich nicht besonders mächtig ist und dementsprechend wenige Funktionalitäten hat – dazu gleich mehr.
Ausgewählt: feed-io
Bleibt also feed-io. Dem ersten Eindruck nach eine kleine, überschaubare, sich an Standards haltende, modern erscheinende Feed-Library. Die Website führt einen über die ersten Schritte gut hinweg, die Installation ist mit Composer schnell erledigt, für alles darüber hinaus muss man jedoch auch hier die API-Doc nutzen oder den Blick in den Quelltext wagen. Merkwürdigerweise ist die Doku auf den Github-Seiten übrigens umfangreicher als die dazu eigens angelegte Documentation-Seite des Web-Auftritts von feed-io. Des Weiteren empfiehlt sich ein Blick in das Beispiel-Verzeichnis. Dass feed-io zwingend PHP 7.1 aufwärts voraussetzt, war für die Anwendung kein Problem.
Die ersten Gehversuche verliefen vielversprechend, ein RSS-Feed konnte schnell verarbeitet werden. Soweit alles gut, oder? Jein. Ein Problem von feed-io ist die mangelnde Unterstützung von Media-RSS. Dabei können Bilder sowohl global im RSS-Channel sein, aber sich auch in den einzelnen Items verbergen. Letztere wollte ich gerne verarbeiten können, und zwar ohne aufwändiges Parsen der möglicherweise in der Description enthaltenen Image-Tags. Genau dafür gibt es die Erweiterung Media-RSS. Zwar unterstützt feed-io sogar einen Teil davon – aber der ist wirklich sehr klein. Und zwar müssen Bilder als „media:thumbnail“-Element eingebunden sein, und zwar nur auf der ersten Ebene innerhalb der Items. Doch je nach Version von RSS und Media-RSS reicht das nicht aus – Media-Elemente können geschachtelt in „media:group“ bzw. „media:content“ vorliegen. Und neben den Thumbnail-Nodes gibt es noch zwei Dutzend andere Element-Typen, die von feed-io gar nicht unterstützt werden. Infolge dessen konnte ich einen Feed mit Thumbnails verarbeiten, einen anderen jedoch überhaupt nicht, da darin das „media:thumbnail“-Element in einem „media:content“-Node verborgen war.
Daraufhin habe ich mir erstmal den Quellcode angesehen. Feed-io geht in etwa so vor, es parst den Feed nach gewissen Regeln und baut daraus Objektinstanzen, unter anderem für Kategorien, Autor, Items und eben auch den Typ Item-Typ namens Media. Dafür wird aber eben auch nur „media:thumbnail“ auf der ersten Ebene innerhalb Items verwendet, und nichts anderes. Alle Elemente, die keinem speziellen Typ zuzuordnen sind, landen aber ebenfalls im Objektbaum, und zwar als allgemeiner Typ „Element“. Ein solches kann wiederum Kind-Elemente beinhalten usw.. Insgesamt also durchaus nicht so schlecht, denn damit lassen sich alle Inhalte wiederfinden. Aber dennoch war die Erfahrung erstmal ernüchternd, denn ansonsten gefiel mir feed-io schon recht gut, aber nun sollte es angesichts der mangelhaften Unterstützung von Media-RSS scheitern? In der Zeit habe ich dann erstmal zend-feed kurz getestet, trotz der eingangs erwähnten Bedenken. Auf Item-Ebene war jedoch überhaupt keine Unterstützung von Media-RSS vorhanden, sondern nur allgemein für das enclosure-Element. Dementsprechend schnell habe ich zend-feed wieder verworfen.
Nun hieß es also, zurück zu feed-io und irgendwie mehr Media-RSS hinein bringen als im Auslieferungszustand vorhanden. Da ich nicht zu tief eingreifen wollte – es wäre auf einen Fork hinaus gelaufen, was wiederum bei Updates zu höherem Aufwand geführt hätte usw., habe ich den Weg gewählt, die vorhandene Objektstruktur zu nutzen und daraus die relevanten Informationen zu extrahieren. Das funktioniert zwar – hier könnte ich nun eine Geschichte über SimpleXML und DOM und Namensräume und so weiter erzählen, aber so richtig schön und elegant fühlt es sich auch nicht an.
Fazit
Eigentlich habe ich kein Fazit. Alle RSS-Feed-Libraries haben doch einige Lücken bzw. unterstützen nur Teile von RSS. Diese Hürden gilt es, je nach Relevanz zu umschiffen. Das hat mich schon ein wenig erstaunt, immerhin ist RSS ein etabliertes Format, ich hätte erwartet, dass es ein oder zwei PHP-Libraries gibt, die so gut wie alle Features abdecken würden. Aber nur Komponenten LEGO-mäßig zusammen stecken wäre ja wiederum auch uninteressant. Zugegeben, für einen „Rant“ war das jetzt vielleicht etwas spärlich. Aber man stelle sich einfach meine Flüche bei der Erkundung der nicht vorhandenen Media-RSS-Unterstützung, des Lesens unterschiedlicher RSS-Feeds, der Fehlersuche usw. vor. Dann passt es wieder.