PHP 怎么PHP订阅源

wen PHP项目 1

本文目录导读:

PHP 怎么PHP订阅源

  1. 生成订阅源(作为发布者)
  2. 读取订阅源(作为订阅者)
  3. 实用技巧
  4. 安全建议
  5. 最佳实践

在 PHP 中实现订阅源(RSS/Atom)功能,通常涉及两种情况:生成订阅源(作为发布者)和读取订阅源(作为订阅者),下面分别介绍。


生成订阅源(作为发布者)

如果你想让用户订阅你的网站内容,需要用 PHP 生成 RSS 或 Atom 格式的 XML 文件。

手动生成 RSS 2.0 示例

<?php类型为 XML
header('Content-Type: application/rss+xml; charset=utf-8');
// 数据库或数组中获取最新文章
$articles = [
    [
        'title' => '文章标题 1',
        'link' => 'https://example.com/article/1',
        'description' => '这是文章摘要...',
        'pubDate' => date('D, d M Y H:i:s O', strtotime('2025-01-01 10:00:00')),
        'author' => '作者名'
    ],
    // 更多文章...
];
// 生成 RSS XML
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<rss version="2.0">
<channel>你的网站标题</title>
    <link>https://example.com</link>
    <description>网站描述</description>
    <language>zh-cn</language>
    <?php foreach ($articles as $article): ?>
    <item>
        <title><?php echo htmlspecialchars($article['title']); ?></title>
        <link><?php echo $article['link']; ?></link>
        <guid><?php echo $article['link']; ?></guid>
        <description><?php echo htmlspecialchars($article['description']); ?></description>
        <pubDate><?php echo $article['pubDate']; ?></pubDate>
        <author><?php echo $article['author']; ?></author>
    </item>
    <?php endforeach; ?>
</channel>
</rss>

使用 PHP 库生成

推荐使用 Laminas FeedSimplePie(读取用)。

用 Laminas Feed 生成:

composer require laminas/laminas-feed
<?php
use Laminas\Feed\Writer\Feed;
$feed = new Feed();
$feed->setTitle('网站标题');
$feed->setLink('https://example.com');
$feed->setDescription('网站描述');
// 添加条目
$entry = $feed->createEntry();
$entry->setTitle('文章标题');
$entry->setLink('https://example.com/article/1');
$entry->setDateModified(time());
$entry->setDescription('#39;);
$feed->addEntry($entry);
// 输出 RSS 2.0
echo $feed->export('rss');

读取订阅源(作为订阅者)

如果你想读取别人的 RSS/Atom 源。

使用 SimplePie(推荐)

SimplePie 是 PHP 中最流行的订阅源解析库。

安装:

composer require simplepie/simplepie

基本用法:

<?php
require_once 'vendor/autoload.php';
use SimplePie\SimplePie;
// 设置缓存目录(需要可写)
$feed = new SimplePie();
$feed->set_feed_url('https://example.com/feed.xml');
$feed->set_cache_location('./cache');
$feed->init();
$feed->handle_content_type();
// 检查是否成功
if ($feed->error()) {
    echo '读取失败: ' . $feed->error();
    exit;
}
// 获取订阅源信息
echo '标题:' . $feed->get_title() . '<br>';
echo '网站:' . $feed->get_link() . '<br>';
echo '描述:' . $feed->get_description() . '<br>';
// 遍历文章
foreach ($feed->get_items() as $item) {
    echo '<h2>' . $item->get_title() . '</h2>';
    echo '<a href="' . $item->get_link() . '">阅读原文</a><br>';
    echo '发布时间:' . $item->get_date('Y-m-d H:i') . '<br>';
    echo $item->get_description() . '<br><hr>';
}

使用 cURL + DOMDocument(原生方法)

<?php
function fetchRss($url) {
    // 使用 cURL 获取内容
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    $xml = curl_exec($ch);
    curl_close($ch);
    return $xml;
}
// 解析 XML
$xmlStr = fetchRss('https://example.com/feed');
$xml = simplexml_load_string($xmlStr, 'SimpleXMLElement', LIBXML_NOCDATA);
// 使用命名空间
$namespaces = $xml->getNamespaces(true);
$content = $xml->channel;
foreach ($content->item as $item) {
    echo '标题:' . $item->title . '<br>';
    echo '链接:' . $item->link . '<br>';
    echo '描述:' . $item->description . '<br>';
    // 如果有扩展命名空间
    if (isset($item->children($namespaces['content']))) {
        $contentExt = $item->children($namespaces['content']);
        echo '全文:' . html_entity_decode((string)$contentExt->encoded) . '<br>';
    }
    echo '<hr>';
}

实用技巧

统一封装读取函数

<?php
class FeedReader {
    private $feed;
    public function __construct($url) {
        $this->feed = new SimplePie();
        $this->feed->set_feed_url($url);
        $this->feed->enable_cache(true);
        $this->feed->set_cache_duration(3600); // 1小时缓存
        $this->feed->init();
    }
    public function getItems($limit = 20) {
        $items = [];
        foreach ($this->feed->get_items(0, $limit) as $item) {
            $items[] = [
                'title' => $item->get_title(),
                'link' => $item->get_link(),
                'description' => $item->get_description(),
                'date' => $item->get_date('Y-m-d H:i:s'),
                'author' => $item->get_author() ? $item->get_author()->get_name() : '',
                'image' => $this->extractImage($item->get_content()),
                'categories' => $this->getCategories($item)
            ];
        }
        return $items;
    }
    private function extractImage($content) {
        if (preg_match('/<img[^>]+src="([^"]+)"/', $content, $matches)) {
            return $matches[1];
        }
        return '';
    }
    private function getCategories($item) {
        $cats = $item->get_categories();
        return $cats ? array_map(function($cat) {
            return $cat->get_label();
        }, $cats) : [];
    }
}
// 使用
$reader = new FeedReader('https://example.com/feed');
$articles = $reader->getItems(10);
foreach ($articles as $article) {
    echo $article['title'] . ' (' . $article['date'] . ')<br>';
}

使用 WordPress 方式(如果使用 WP)

// 获取订阅源
$rss = fetch_feed('https://example.com/feed');
if (!is_wp_error($rss)) {
    $maxitems = $rss->get_item_quantity(5);
    $rss_items = $rss->get_items(0, $maxitems);
    foreach ($rss_items as $item) {
        echo '<a href="' . $item->get_permalink() . '">';
        echo $item->get_title();
        echo '</a>';
    }
}

安全建议

  1. 过滤输出:所有动态内容输出前使用 htmlspecialchars() 防止 XSS。
  2. 设置头信息:正确设置 Content-Typeapplication/rss+xmltext/xml
  3. 缓存:读取外部订阅源一定用缓存避免每次都请求。
  4. 超时处理:设置 cURL 超时,避免卡死页面。
  5. 错误处理:检查 XML 解析结果,处理无效 XML。
  6. CDATA 处理如果含特殊字符,用 CDATA 包裹:
<description><![CDATA[<?php echo $article['description']; ?>]]></description>

最佳实践

  • 生成时:确保每个 item 都有唯一 <guid>
  • 生成时pubDate 使用 RFC 822 格式(date(DATE_RFC2822))。
  • 读取时:注意处理编码问题(UTF-8)。
  • 读取时:处理图片懒加载(部分订阅源用 data-src)。
  • 避免过度调用:大量外部订阅源请求可能导致被封或加载缓慢。

如果需要更高级功能(如 WebSub 实时推送),可以考虑使用 WebSub/PubSubHubbub 协议配合实现。

抱歉,评论功能暂时关闭!