Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rss Php Laravel Package

dg/rss-php

dg/rss-php is a lightweight, dependency-free PHP library for reading RSS and Atom feeds. It offers a simple API for fetching and parsing feeds, handles namespaces and enclosures, and works across PHP versions from 5.3 onward.

Deep Wiki
Context7

Getting Started

composer require dg/rss-php

The whole API surface is two static methods. RSS::load($url, $timeout = 10) fetches a remote feed over HTTP(S) and parses it; RSS::loadFile($path) parses a local file. Both return a plain SimpleXMLElement representing the document root — there is no DTO layer, no config file, and no service container binding.

require __DIR__ . '/vendor/autoload.php';

$feed = RSS::load('https://blog.example.com/feed.xml');

foreach ($feed->channel->item as $item) {
    printf("%s — %s\n", (string) $item->title, (string) $item->link);
}

Where to look first: the entire library is effectively one file (src/RSS.php, a few hundred lines). Read it before building on it — there is no hidden magic, and knowing exactly how it fetches and parses saves hours of guessing later.

First use case: a "latest posts" widget or a scheduled import job that pulls a handful of external feeds into your own table. That is the shape this package was designed for.

Implementation Patterns

Wrap it immediately. The static API is untestable and unmockable, so put it behind one class from day one.

final class FeedReader
{
    public function __construct(private int $timeout = 10) {}

    /** @return array<int, array{title:string,link:string,date:?string,guid:string}> */
    public function items(string $url): array
    {
        $feed = RSS::load($url, $this->timeout);

        // RSS 2.0/RDF expose channel->item; Atom exposes entry.
        $nodes = isset($feed->channel->item) ? $feed->channel->item : $feed->entry;

        $out = [];
        foreach ($nodes as $item) {
            $out[] = [
                'title' => trim((string) $item->title),
                'link'  => $this->link($item),
                'date'  => $this->date($item),
                'guid'  => $this->guid($item),
            ];
        }
        return $out;
    }
}

Normalise links — this is the most common breakage. RSS uses a text node; Atom uses <link rel="alternate" href="…"/> and may include several links (self, enclosure, alternate).

private function link(SimpleXMLElement $item): string
{
    if (isset($item->link['href'])) {           // Atom
        foreach ($item->link as $l) {
            $rel = (string) ($l['rel'] ?? 'alternate');
            if ($rel === 'alternate') return (string) $l['href'];
        }
    }
    return (string) $item->link;                 // RSS
}

Normalise dates. pubDate (RFC 822) vs published/updated (RFC 3339). Have a null fallback.

$raw = (string) ($item->pubDate ?? $item->published ?? $item->updated ?? '');
$date = $raw !== '' ? new DateTimeImmutable($raw) : null;

Dedupe on ingest. Use guid/id when present, otherwise hash the stable parts:

$key = $guid ?: sha1($link . $title . ($date?->format('c') ?? ''));
FeedItem::updateOrCreate(['guid' => $key], $attributes);

Add a unique index on guid — feeds re-publish items constantly, and this is what stops duplicate rows.

Namespaced fields. content:encoded, dc:creator, and media:* are invisible unless you ask for the namespace explicitly:

$html  = (string) $item->children('content', true)->encoded;
$thumb = (string) $item->children('media', true)->thumbnail->attributes()['url'];
$author = (string) $item->children('dc', true)->creator;

Caching and scheduling. The fetch is blocking and uncached. In Laravel, run it from a queued job or a scheduled command, persist the rows, and let the rest of the app read your own table. If you genuinely need it in a request cycle, wrap with Cache::remember("feed:$url", 600, fn () => $reader->items($url)).

Gotchas and Tips

  • It's a 2015 release. Unmaintained, no PHP 8 test matrix, no security backport policy. It still works on modern PHP because it is only SimpleXML plus cURL, but pin the version and keep all calls behind one wrapper class so you can swap in a maintained library without touching call sites.
  • No "parse this string" method. You get load($url) or loadFile($path) only. If you need custom HTTP (auth, signed requests, a specific User-Agent), fetch with Laravel's Http::get() and parse with simplexml_load_string() yourself — but you then own all the RSS/Atom differences above.
  • Always cast. $item->title is an object. empty($item->title) is misleading for <title>0</title>, and comparisons silently fail. (string) $item->title everywhere.
  • Attributes vs nodes are not interchangeable. $item->link is a text node in RSS but an attribute-bearing element in Atom; guid vs id; description vs summary. Test against one real RSS 2.0 feed, one Atom feed, and one RDF feed before shipping.
  • Feeds lie. Truncated XML, wrong declared encodings, unescaped ampersands, missing GUIDs, three different date formats in one document. Wrap parsing in try/catch, log the URL plus a snippet of the raw body, and skip the feed rather than failing the whole job.
  • No User-Agent or header configuration. Some hosts return 403 to the default cURL agent. Given the library is a single file, vendoring a copy into your app and editing it is a legitimate and low-risk extension point.
  • Debugging: dump the tree before guessing property names — file_put_contents('/tmp/feed.xml', $feed->asXML()), then read it. Guessing at $item->whatever is the slow path.
  • Treat item bodies as hostile. Descriptions and content:encoded are third-party HTML; sanitise before rendering and never {!! $item->description !!} straight from an external feed.
  • Don't call it per request under load. One fetch per feed per schedule, everything else served from your own persisted rows.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console