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

Feed Laravel Package

zetacomponents/feed

Zeta Components Feed is a PHP library for parsing and generating RSS 1.0, RSS 2.0, and Atom feeds. It provides a clean API to read feed metadata and items, and to build valid feeds, with support for enclosures and common extensions.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify. zetacomponents/feed is a legacy Zeta Components package. It ships on Packagist, so composer require zetacomponents/feed works, but it pulls in zetacomponents/base (the ezcBase autoloader/configuration shim). Before writing any code, confirm two things:

  1. Your PHP version. The package was written for PHP 5.x and works reliably on 5.6–7.4; PHP 8.x is not officially supported (see Gotchas). Run a smoke test on your target runtime.
  2. The dom and libxml extensions are present — they are hard requirements and ezcFeed throws ezcFeedXmlParserException / fatal errors quickly if they are missing or malformed.

Where to look first. Everything relevant lives in three classes:

  • ezcFeed — the façade. You almost never touch anything else directly.
  • ezcFeedParser / ezcFeedGenerator implementations — one per format (rss1, rss2, atom). Registered lazily by format string.
  • ezcFeedElement* classes (ezcFeedLinkElement, ezcFeedPersonElement, ezcFeedCategoryElement, ezcFeedTextElement, …) — these are the objects returned when you read feed properties.

First use case (the 90% one). Consume an external feed and list its items:

require 'vendor/autoload.php';

$feed = ezcFeed::parse('https://example.com/feed.xml');

foreach ($feed->items as $item) {
    printf("%s — %s\n", $item->title, $item->link[0]->href);
}

That’s the whole minimal path: parse() for a URL, parseContent() for a string you already hold (file_get_contents, an HTTP client response, a cached blob). items is a plain array of ezcFeedEntryElement, and title/description/link are objects, not strings — the single most important thing to internalise early.

Implementation Patterns

Always go through ezcFeed::parseContent() for anything you control the transport of. parse() uses its own file reading and is harder to instrument. Fetch with Guzzle/curl/Laravel's Http, cache the raw body, then parseContent($body). This gives you retries, timeouts, caching, and testable fixtures for free.

Property access follows a predictable but object-heavy shape. The common ones:

$feed->title;                // string-ish ezcFeedTextElement; cast to string
$feed->description;          // ezcFeedTextElement
$feed->link[0]->href;        // array of ezcFeedLinkElement
$feed->language;             // may be null depending on source format
$feed->updated;              // ezcFeedDateElement (DateTime-backed)

$item = $feed->items[0];
$item->title;                // ezcFeedTextElement
$item->link[0]->href;
$item->description;          // may be null — always isset/!== null check
$item->id;                   // Atom <id> / RSS <guid>
$item->updated;              // ezcFeedDateElement; ->date gives a DateTime
$item->author[0]->name;      // array of ezcFeedPersonElement
$item->category[0]->term;    // array of ezcFeedCategoryElement

Because elements are objects with __toString, mixing them into sprintf/Laravel Blade output usually "just works" for text fields, but never assume scalar — always reach for the child attribute (href, term, name) when the element is a link/person/category.

Generating feeds — pick the format up front. The constructor argument determines which modules are registered and which properties are legal:

$feed = new ezcFeed('rss2');           // 'rss1' | 'rss2' | 'atom'

$feed->title       = 'My Blog';
$feed->description = 'Latest posts';
$feed->link        = 'https://example.com';
$feed->language    = 'en';
$feed->updated     = new DateTimeImmutable();

foreach ($posts as $post) {
    $item = $feed->add('item');
    $item->title       = $post->title;
    $item->link        = $post->url;
    $item->description = $post->excerpt;
    $item->id          = $post->url;      // guid
    $item->updated     = $post->published_at;
}

header('Content-Type: application/rss+xml; charset=utf-8');
echo $feed->generate('rss2');

->generate('atom') on an rss2-constructed feed is possible but you lose format-specific modules — construct with the format you intend to emit. For a "serve both" endpoint, build the feed twice rather than reusing one instance.

Modules are how you get vendor extensions. iTunes podcasts, Dublin Core, GeoRSS, and content-encoded bodies are optional modules. You attach them explicitly:

$feed->addModule('RSS2');    // or 'Atom', 'DublinCore', 'Content', 'iTunes'
$item->addModule('iTunes');

$feed->itunes->author = 'Me';
$item->itunes->duration = '05:32';

If a property you expect returns null or throws a "module not loaded" style error, the missing addModule() call is almost always the cause.

Parsing is format-tolerant, generation is not. parse() sniffs RSS 1.0/2.0/Atom automatically — you don't tell it which. Use this: accept any feed URL, store the raw XML, and only branch on $feed->type when you actually need format-specific fields.

In Laravel specifically. Wrap parsing in a small service and cache the parsed model, not the raw XML, if the downstream consumer is hot:

$feed = Cache::remember("feed:$url", 300, fn () =>
    ezcFeed::parseContent(Http::timeout(10)->get($url)->body())
);

Catch ezcFeedException (and ezcFeedParseErrorException in particular) at the boundary; malformed third-party feeds are not rare and should degrade to an empty list, not a 500.

Gotchas and Tips

Abandonment is the biggest gotcha. This package has ~11 stars, no recent commits, and a NOASSERTION license line that will make your compliance team ask questions. Treat it as a stable-but-frozen library: pin the version, vendor it, and have a migration path. For new greenfield work, prefer laminas/laminas-feed or willvincent/feeds; use zetacomponents/feed if you're already on Zeta Components or maintaining legacy code.

PHP 8 compatibility is not guaranteed. On 8.x you can hit deprecation notices around dynamic properties, create_function-style patterns in ezcBase, and return-type mismatches. If you must run it on PHP 8, test every code path (parse RSS1, RSS2, Atom; generate all three) — not just the happy path. Consider downgrading the package to a maintained fork if one is available.

Everything is an object, and empty arrays are the trap. $item->link is an array; on malformed or minimal feeds it can be [] or the property can be null. $item->link[0] on an empty array raises a warning/error. Write accessors:

$href = isset($item->link[0]) ? (string) $item->link[0]->href : null;
$desc = isset($item->description) ? (string) $item->description : '';

Do not ?? this — null coalescing won't save you from "undefined array key 0" on an empty array in PHP 8.

ezcFeed::parse() on HTTPS and redirects. The built-in URL reader is thin, doesn't do modern TLS hardening or redirects reliably, and offers no timeout control. Bypass it: fetch with your HTTP client, hand the body to parseContent(). This is also the only sane way to unit-test parsing.

Dates need coercion. $item->updated is an ezcFeedDateElement; use ->date (a DateTime) or (string) it depending on the format. Don't expect a Unix timestamp. When generating, updated must be a DateTimeInterface object or a string the parser can consume — passing an int will throw or produce garbage.

Namespace/entity handling on weird inputs. Non-UTF-8 feeds (Latin-1 from old blogs) parse to mojibake. Normalise encoding before parseContent() — mb_convert_encoding($xml, 'UTF-8', 'auto') — or accept the garbage. Feeds with undeclared namespaces or unescaped ampersands throw ezcFeedParseErrorException; pre-sanitise with a tolerant DOM pass if you ingest many random feeds.

Configuration quirks. ezcBase may attempt to read ezc.ini for autoloading if you use the non-Composer bootstrap. With Composer autoload you can ignore this, but if you see "configuration file not found" errors, ensure you're not triggering the legacy autoloader. If you're embedding this in a Symfony/Laravel app, verify only the Composer autoloader is active for ezcFeed* classes.

Extension points. Custom feed modules can be registered via ezcFeed::registerModule() if you need vendor-specific fields not shipped with the package, and custom parsers/generators via the same registration API. In practice this is rarely worth it — you're better off parsing with this package and shaping the data with your own DTOs, or generating XML by hand for custom formats. Keep the library at the boundary and don't let ezcFeedElement objects leak into your domain layer.

Debugging checklist when a feed "parses but everything is null":

  1. var_dump($feed->type) — confirm detection.
  2. Dump array_keys(get_object_vars($feed)) — see which modules loaded.
  3. Check the raw body for BOM/encoding — strpos($xml, "\xEF\xBB\xBF") === 0 is a classic.
  4. Verify $feed->items is populated — some feeds put content in $feed->modules when the format is non-standard.

Licensing. NOASSERTION in the repository metadata means the license declaration is missing or non-standard. Zeta Components was historically Apache-2.0 (some components BSD), but confirm this in the file headers of the actual package you install before shipping commercially — don't trust the repo metadata.

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