php-feed-io/feed-io
feed-io is a PHP library for reading and writing RSS and Atom feeds. It handles fetching, parsing, and generating feed content with an easy-to-use API, making it simpler to consume external feeds or publish your own in PHP applications.
Installation:
composer require php-feed-io/feed-io
Ensure your project meets PHP 8.1+ requirements (or 8.0+ for v5.x).
Basic Initialization:
use FeedIo\FeedIo;
use FeedIo\Adapter\Guzzle\Client;
use GuzzleHttp\Client as GuzzleClient;
use Psr\Log\NullLogger;
$httpClient = new Client(new GuzzleClient());
$logger = new NullLogger();
$feedIo = new FeedIo($httpClient, $logger);
First Use Case: Fetch and parse a feed (e.g., RSS/Atom/JSONFeed):
$result = $feedIo->read('https://example.com/feed.atom');
echo $result->getFeed()->getTitle();
read(): Parse a feed URL into a Result object.discover(): Extract feed links from HTML headers.toAtom()/toJson(): Generate feed XML/JSON from a Feed object../vendor/bin/feedio read <url> for quick testing.$modifiedSince = new DateTime('2023-01-01');
$result = $feedIo->read($url, null, $modifiedSince);
foreach ($result->getItemsSince($modifiedSince) as $item) {
// Process new items
}
$chain = new FeedIo\Filter\Chain();
$chain->add(new FeedIo\Filter\Since($modifiedSince));
$chain->add(new Acme\Filter\Database()); // Custom filter
foreach ($result->getFilteredItems($chain) as $item) {
// Process filtered items
}
$feed = new FeedIo\Feed();
$feed->setTitle('My Blog');
$item = $feed->newItem()->setTitle('New Post');
$feed->add($item);
$response = $feedIo->getPsrResponse($feed, 'atom');
// Use with Laravel's HTTP responses:
return new Response($response->getBody(), 200, $response->getHeaders());
$feeds = $feedIo->discover('https://example.com');
foreach ($feeds as $feedUrl) {
// Process discovered feeds
}
$media = new FeedIo\Feed\Item\Media();
$media->setUrl('https://example.com/audio.mp3')
->setType('audio/mpeg');
$item->addMedia($media);
// config/feedio.php
return [
'http_client' => \FeedIo\Adapter\Http\Client::class,
'logger' => \Monolog\Logger::class,
];
// app/Providers/FeedIoServiceProvider.php
public function register()
{
$this->app->singleton(FeedIo::class, function ($app) {
$httpClient = new ($app['config']['feedio.http_client'])(new GuzzleHttp\Client());
$logger = new ($app['config']['feedio.logger'])('feedio');
return new FeedIo($httpClient, $logger);
});
}
// Dispatch a job to fetch and process feeds
FetchFeedsJob::dispatch($feedUrl)->onQueue('feeds');
$cacheKey = "feed:{$url}:{$modifiedSince->getTimestamp()}";
$result = Cache::remember($cacheKey, now()->addHours(1), function () use ($feedIo, $url, $modifiedSince) {
return $feedIo->read($url, null, $modifiedSince);
});
// routes/api.php
Route::get('/feed/{url}', function ($url) {
$feedIo = app(FeedIo::class);
$result = $feedIo->read($url);
return $feedIo->getPsrResponse($result->getFeed(), 'json');
});
Timezone Handling:
feedIo->getDateTimeBuilder()->setFeedTimezone() temporarily:
$feedIo->getDateTimeBuilder()->setFeedTimezone(new DateTimeZone('UTC'));
$result = $feedIo->read($url);
$feedIo->getDateTimeBuilder()->resetFeedTimezone(); // Reset to avoid side effects
Redirect Loops:
read().Invalid JSON/Atom:
try {
$result = $feedIo->read($url);
} catch (FeedIo\Exception\InvalidFeedException $e) {
Log::error("Invalid feed at {$url}: " . $e->getMessage());
}
Media/Enclosure Issues:
type and url are set for media objects. Missing types may cause parsing errors.Filter Order:
Chain are applied in order. Place Since filters early to avoid unnecessary processing.Enable Logging:
$logger = new Monolog\Logger('feedio', [
new Monolog\Handler\StreamHandler(storage_path('logs/feedio.log'))
]);
$feedIo = new FeedIo($client, $logger);
Inspect Raw Responses:
$result = $feedIo->read($url);
$response = $result->getResponse();
Log::debug($response->getBody());
CLI Debugging:
./vendor/bin/feedio read --verbose https://example.com/feed
Custom Feed Formats:
FeedIo\Feed\FeedInterface to support custom formats (e.g., custom XML schemas).HTTP Client Adaptation:
FeedIo\Adapter\ClientInterface for custom HTTP clients (e.g., Symfony’s HttpClient):
use FeedIo\Adapter\Http\Client;
$client = new Client(new Symfony\Component\HttpClient\HttplugClient());
DateTime Handling:
FeedIo\DateTime\Builder to customize date parsing (e.g., for legacy feeds).Filter Extensions:
FeedIo\Filter\FilterInterface:
class CustomFilter implements FilterInterface {
public function filter(FeedItem $item, array $options): bool {
return $item->getTitle() !== 'Excluded Post';
}
}
PSR-7 Response Customization:
FeedIo\FeedIo::getPsrResponse() to add headers or modify responses:
$response = $feedIo->getPsrResponse($feed, 'atom');
$response = $response->withHeader('X-Custom-Header', 'value');
Cache Headers:
getNextUpdate() to schedule feed refreshes:
$nextUpdate = $result->getNextUpdate();
Cache::put("feed:{$url}:next_update", $nextUpdate, $nextUpdate->diff(new DateTime()));
Batch Processing:
foreach ($feedUrls as $url) {
FetchFeedJob::dispatch($url)->onQueue('feeds');
}
Selective Fetching:
getModifiedSince() to avoid refetching unchanged feeds:
$lastModified = Cache::get("feed:{$url}:last_modified");
$result = $feedIo->read($url, null, $lastModified);
Cache::put("feed
How can I help you explore Laravel packages today?