debril/feed-io

PHP 库,用于消费和提供 JSONFeed / RSS / Atom 联播

v6.0.3 2023-10-16 14:12 UTC

README

Latest Stable Version Build Status Maintainability Test Coverage

feed-io 是一个 PHP 库,用于消费和提供新闻联播。它具有以下功能:

  • JSONFeed / Atom / RSS 读写支持
  • 通过 HTML 头自动发现联播
  • 命令行界面,用于发现和读取联播
  • 使用精确的缓存头生成 PSR-7 响应
  • 读取联播时支持 HTTP 头,以节省网络流量
  • 读取联播时检测格式(RSS / Atom)
  • 支持封装,以处理外部媒体,如音频内容
  • 支持联播标志(RSS + Atom)
  • PSR 兼容的日志记录
  • 内容过滤,以获取最新的条目
  • DateTime 检测和转换
  • 通用的 HTTP ClientInterface
  • 与所有 PSR-18 兼容的 HTTP 客户端 集成。

此库高度可扩展,旨在适应许多情况,因此如果您在文档中找不到解决方案,请随时在 讨论 中提问。

安装

使用 Composer 将 feed-io 添加到项目的需求中

    composer require debril/feed-io

要求

feed-io 4 需要 PHP 7.1+,feed-io 5 需要 PHP 8.0+。所有版本都依赖于 psr/log 和任何 PSR-18 兼容的 HTTP 客户端。要继续使用,您可能需要 php-http/guzzle7-adapter。它建议使用 monolog 进行日志记录。Monolog 不是唯一适合处理 feed-io 日志的库,您可以使用任何 PSR/Log 兼容的库。

使用

CLI

假设您已使用 Composer 安装了 feed-io,您可以使用其命令行客户端从终端读取联播

./vendor/bin/feedio read https://php.ac.cn/feed.atom

阅读

feed-io 被设计为跨互联网读取联播并发布您自己的联播。其主要类是 FeedIo

// create a simple FeedIo instance, e.g. with the Symfony HTTP Client
$client = new \FeedIo\Adapter\Http\Client(new Symfony\Component\HttpClient\HttplugClient());
$feedIo = \FeedIo\FeedIo($client);

// read a feed
$result = $feedIo->read($url);

// get title
$feedTitle = $result->getFeed()->getTitle();

// iterate through items
foreach( $result->getFeed() as $item ) {
    echo $item->getTitle();
}

如果您需要获取自上次消费联播以来的新条目,请使用结果对象的 getItemsSince() 方法

// read a feed and specify the `$modifiedSince` limit to fetch only items newer than this date
$result = $feedIo->read($url, $feed, $modifiedSince);

// iterate through new items
foreach( $result->getItemsSince() as $item ) {
    echo $item->getTitle();
}

您还可以混合使用多个过滤器,根据您的需求排除项目

// read a feed
$result = $feedIo->read($url, $feed, $modifiedSince);

// remove items older than `$modifiedSince`
$since = new FeedIo\Filter\Since($result->getModifiedSince());

// Your own filter
$database = new Acme\Filter\Database();

$chain = new Chain();
$chain
    ->add($since)
    ->add($database);

// iterate through new items
foreach( $result->getFilteredItems($chain) as $item ) {
    echo $item->getTitle();
}

为了节省带宽,feed-io 估计下一次读取联播并从中获取新条目的相关时间。

$nextUpdate = $result->getNextUpdate();
echo "computed next update: {$nextUpdate->format(\DATE_ATOM)}";

// you may need to access the statistics
$updateStats = $result->getUpdateStats();
echo "average interval in seconds: {$updateStats->getAverageInterval()}";

feed-io 通过首先检测联播在过去的 7 天内是否活跃来确定下一次更新时间。如果没有,我们将其视为休眠。休眠联播的下一次更新日期设置为第二天同一时间。如果联播不是休眠的,我们使用平均间隔和中间间隔,通过将这些间隔加到联播的最后修改日期上,并将结果与当前时间进行比较。如果结果是未来的,则将其作为下一次更新时间返回。如果没有一个是未来的,则我们认为联播将很快更新,因此下一次更新时间是计算时刻后一小时。

请注意:休眠和即将更新的联播的固定延迟可以通过 Result::getNextUpdate() 参数设置,有关详细信息,请参阅 Result

联播发现

网页可以在其头中引用一个或多个联播,feed-io 提供了一种发现它们的方法

// create a simple FeedIo instance, e.g. with the Symfony HTTP Client
$client = new \FeedIo\Adapter\Http\Client(new Symfony\Component\HttpClient\HttplugClient());
$feedIo = \FeedIo\FeedIo($client);

$feeds = $feedIo->discover($url);

foreach( $feeds as $feed ) {
    echo "discovered feed : {$feed}";
}

或者您可以使用feed-io的命令行

./vendor/bin/feedio discover https://a-website.org

您将在输出中获取所有发现的订阅源。

将对象格式化为XML流

// build the feed
$feed = new FeedIo\Feed;
$feed->setTitle('...');

// convert it into Atom
$atomString = $feedIo->toAtom($feed);

// or ...
$atomString = $feedIo->format($feed, 'atom');

添加样式表

$feed = new FeedIo\Feed;
$feed->setTitle('...');
$styleSheet = new StyleSheet('http://url-of-the-xsl-stylesheet.xsl');
$feed->setStyleSheet($styleSheet);

构建包含媒体的订阅源

// build the feed
$feed = new FeedIo\Feed;
$feed->setTitle('...');

$item = $feed->newItem();

// add namespaces
$feed->setNS(
    'itunes', //namespace
    'http://www.itunes.com/dtds/podcast-1.0.dtd' //dtd for the namespace
        );
$feed->set('itunes,title', 'Sample Title'); //OR any other element defined in the namespace.
$item->addElement('itunes:category', 'Education');

// build the media
$media = new \FeedIo\Feed\Item\Media
$media->setUrl('http://yourdomain.tld/medias/some-podcast.mp3');
$media->setType('audio/mpeg');

// add it to the item
$item->addMedia($media);

$feed->add($item);

使用订阅源创建有效的PSR-7响应

您可以直接使用\FeedIo\FeedInstance,并通过\FeedIo\FeedIo::getPsrResponse()转换为PSR-7有效响应

$feed = new \FeedIo\Feed;

// feed the beast ...
$item = new \FeedIo\Feed\Item;
$item->set ...
$feed->add($item);

$atomResponse = $feedIo->getPsrResponse($feed, 'atom');

$jsonResponse = $feedIo->getPsrResponse($feed, 'json');

构建FeedIo实例

要创建新的FeedIo实例,您只需注入两个依赖项

  • 实现FeedIo\Adapter\ClientInterface的HTTP客户端。它可以是一个外部库的包装,如FeedIo\Adapter\Guzzle\Client
  • 实现Psr\Log\LoggerInterface的PSR-3日志记录器
// first dependency : the HTTP client
// here we use Guzzle as a dependency for the client
$guzzle = new GuzzleHttp\Client();
// Guzzle is wrapped in this adapter which is a FeedIo\Adapter\ClientInterface  implementation
$client = new FeedIo\Adapter\Guzzle\Client($guzzle);

// second dependency : a PSR-3 logger
$logger = new Psr\Log\NullLogger();

// now create FeedIo's instance
$feedIo = new FeedIo\FeedIo($client, $logger);

另一个示例,使用配置为写入标准输出的Monolog

// create a simple FeedIo instance, e.g. with the Symfony HTTP Client
$client = new \FeedIo\Adapter\Http\Client(new Symfony\Component\HttpClient\HttplugClient());
$logger = new Monolog\Logger('default', [new Monolog\Handler\StreamHandler('php://stdout')]);
$feedIo = \FeedIo\FeedIo($client, $logger);

注入自定义日志记录器

只要它实现了Psr\Log\LoggerInterface,您就可以注入任何Logger。Monolog可以,但不是唯一的库:https://packagist.org.cn/providers/psr/log-implementation

use FeedIo\FeedIo;
use FeedIo\Adapter\Guzzle\Client;
use GuzzleHttp\Client as GuzzleClient;
use Custom\Logger;

$client = new Client(new GuzzleClient());
$logger = new Logger();

$feedIo = new FeedIo($client, $logger);

注入自定义HTTP客户端

从6.0版本开始,有一个通用HTTP适配器,它可以包装任何符合PST-18规范的HTTP客户端。

use CustomPsr18\Client as CustomClient;

$client = new Custom\Adapter\Http\Client(new CustomClient())
$logger = new Psr\Log\NullLogger();

$feedIo = new FeedIo\FeedIo($client, $logger);

使用工厂配置feed-io

工厂在feed-io 5.2中已被弃用,并在6.0中移除。直接实例化外观并传入所需的HTTP客户端和日志记录器接口。

处理缺失时区

有时您必须消费缺失日期时区的订阅源。在某些用例中,您可能需要指定订阅源的时区以获得准确值,因此feed-io为此提供了解决方案。

$feedIo->getDateTimeBuilder()->setFeedTimezone(new \DateTimeZone($feedTimezone));
$result = $feedIo->read($feedUrl);
$feedIo->getDateTimeBuilder()->resetFeedTimezone();

别忘了在获取结果后重置feedTimezone,否则所有订阅源将位于同一个时区。

使用PHP Storm构建

feed-io的大部分代码都是使用PHP Storm编写的,由Jetbrains提供。