debril/feed-io
PHP library to read and write RSS, Atom, and JSONFeed. Supports feed autodiscovery, enclosures, logos, content filtering, and DateTime conversion. Includes CLI tools, PSR-7 responses with cache headers, PSR-3 logging, and PSR-18 HTTP clients.
Installation:
composer require php-feed-io/feed-io
Ensure your project meets PHP 8.1+ requirements (or 7.1+ for v4.x).
Basic Feed Consumption:
use FeedIo\FeedIo;
use FeedIo\Adapter\Guzzle\Client;
use GuzzleHttp\Client as GuzzleClient;
$client = new Client(new GuzzleClient());
$feedIo = new FeedIo($client, new \Psr\Log\NullLogger());
$result = $feedIo->read('https://example.com/feed.atom');
echo $result->getFeed()->getTitle();
First Practical Use Case: Fetch and display the 5 newest items from a feed:
foreach ($result->getFeed() as $index => $item) {
if ($index >= 5) break;
echo $item->getTitle() . "\n";
}
FeedIo, Feed, Item, etc../vendor/bin/feedio read <url>.Since, Chain, and custom filters.getItemsSince() or custom filters to avoid reprocessing old items.$modifiedSince = new \DateTime('2023-01-01');
$result = $feedIo->read('https://blog.example.com/feed', null, $modifiedSince);
foreach ($result->getItemsSince() as $item) {
// Process only new items
$this->storeInDatabase($item);
}
FeedIo\Feed and return as PSR-7 response.$feed = new \FeedIo\Feed();
$feed->setTitle('My Blog Updates');
$feed->setLink('https://blog.example.com');
foreach ($posts as $post) {
$item = $feed->newItem();
$item->setTitle($post->title)
->setLink($post->url)
->setDate($post->published_at);
$feed->add($item);
}
return $feedIo->getPsrResponse($feed, 'atom');
<link> tags or use the CLI.$discoveredFeeds = $feedIo->discover('https://example.com');
foreach ($discoveredFeeds as $feedUrl) {
$this->subscribeToFeed($feedUrl);
}
$item = $feed->newItem();
$media = new \FeedIo\Feed\Item\Media();
$media->setUrl('https://example.com/podcast.mp3')
->setType('audio/mpeg')
->setLength('1200'); // Duration in seconds
$item->addMedia($media);
getNextUpdate() to schedule feed checks efficiently.$nextUpdate = $result->getNextUpdate();
$this->scheduleCronJob($nextUpdate->format('Y-m-d H:i:s'));
Laravel-Specific:
Http::client() for the HTTP adapter:
$client = new \FeedIo\Adapter\Http\Client(Http::client());
Cache::remember() to avoid redundant parsing.$logger = \Log::channel('feed');
$feedIo = new FeedIo($client, $logger);
Queueing Feed Processing:
FeedUpdateJob::dispatch($feedUrl, $modifiedSince)->onQueue('feeds');
Testing:
$mockClient = Mockery::mock(\FeedIo\Adapter\ClientInterface::class);
$mockClient->shouldReceive('get')->andReturn($response);
$feedIo = new FeedIo($mockClient, $logger);
Timezone Handling:
DateTimeBuilder:
$feedIo->getDateTimeBuilder()->setFeedTimezone(new \DateTimeZone('UTC'));
// Don't forget to reset after use!
$feedIo->getDateTimeBuilder()->resetFeedTimezone();
Relative URLs:
/images/logo.png). Newer versions (v5.3.2+) support this, but older versions may fail.$item->setLink('https://example.com' . $relativePath);
HTTP Client Quirks:
Symfony\Component\HttpClient\HttplugClient or Guzzle.Memory Usage:
$items = iterator_to_array($result->getFeed(), false); // Lazy loading
Feed Format Detection:
$result = $feedIo->read('https://example.com/feed', 'atom');
Caching Headers:
getPsrResponse() may not set optimal cache headers for dynamic feeds.$response = $feedIo->getPsrResponse($feed, 'atom');
$response = $response->withAddedHeader('Cache-Control', 'max-age=3600');
Enable Logging:
$logger = \Log::channel('feed');
$feedIo = new FeedIo($client, $logger);
404 Not Found or malformed XML/JSON.Validate Feeds:
Inspect Raw Responses:
$result = $feedIo->read($url);
$rawResponse = $result->getResponse(); // PSR-7 ResponseInterface
Custom Filters:
\FeedIo\Filter\FilterInterface to add logic (e.g., database sync, content moderation):
class DatabaseFilter implements FilterInterface {
public function filter(Feed $feed, array $items) {
return array_filter($items, fn($item) => $this->isValid($item));
}
}
Custom Feed Formats:
\FeedIo\Feed or \FeedIo\Feed\Item to support non-standard elements:
$feed->set('custom,namespace', 'value');
HTTP Client Middleware:
$client = new \FeedIo\Adapter\Http\Client(
Http::withOptions(['timeout' => 10])
);
DateTime Handling:
DateTimeBuilder to customize date parsing:
$feed
How can I help you explore Laravel packages today?