首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 產生 RSS 2.0 / Atom 1.0:RSSBuilder 類別使用與自訂擴充

     編輯:PHP 相關知識

PHP 產生標準 RSS/Atom Feed:RSSBuilder 類別、命名空間擴充、iTunes Podcast 標籤與效能優化

部落格、新聞站、Podcast 需對外提供 Feed。本文示範使用 RSSBuilder 類別產生 RSS 2.0,並擴充支援 Atom 1.0、iTunes、Media RSS 等命名空間。

1. 基本 RSS 2.0 產生

<?php
require_once 'RSSBuilder.php'; // 假設已有此類別

$rss = new RSSBuilder('UTF-8', 'https://example.com', '我的部落格', '技術分享與生活感悟', 'https://example.com/logo.png');
$rss->addDCData('', 'https://example.com', date('r'));

// 文章資料 (通常來自資料庫)
$posts = [
    ['id' => 1, 'title' => 'PHP 8.2 新特性', 'url' => 'https://example.com/post/1', 'desc' => '效能提升...', 'date' => '2024-01-15'],
    ['id' => 2, 'title' => 'Laravel 11 遷移指南', 'url' => 'https://example.com/post/2', 'desc' => '破壞性變更...', 'date' => '2024-01-10'],
];

foreach ($posts as $post) {
    $rss->addItem(
        $post['url'],
        $post['title'],
        $post['url'] . '?from=rss',
        $post['desc'],
        $post['title'],
        $post['date']
    );
}

header('Content-Type: application/xml; charset=UTF-8');
header('Cache-Control: public, max-age=3600');
$rss->outputRSS();

2. RSSBuilder 核心實作 (精簡版)

class RSSBuilder {
    private $encoding, $link, $title, $description, $imageUrl;
    private $items = [];
    private $namespaces = [];

    public function __construct($encoding, $link, $title, $description, $imageUrl = '') {
        $this->encoding = $encoding;
        $this->link = $link;
        $this->title = $title;
        $this->description = $description;
        $this->imageUrl = $imageUrl;
    }

    public function addDCData($creator, $link, $date) {
        $this->namespaces['dc'] = 'https://purl.org/dc/elements/1.1/';
        $this->dcData = compact('creator', 'link', 'date');
    }

    public function addItem($link, $title, $guid, $description, $author, $pubDate) {
        $this->items[] = compact('link', 'title', 'guid', 'description', 'author', 'pubDate');
    }

    public function addNamespace(string $prefix, string $uri) {
        $this->namespaces[$prefix] = $uri;
    }

    public function outputRSS() {
        $xml = new XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        $xml->startDocument('1.0', $this->encoding);
        $xml->startElement('rss');
        $xml->writeAttribute('version', '2.0');
        $xml->writeAttribute('xmlns:dc', 'https://purl.org/dc/elements/1.1/');
        $xml->writeAttribute('xmlns:atom', 'https://www.w3.org/2005/Atom');
        foreach ($this->namespaces as $prefix => $uri) {
            $xml->writeAttribute("xmlns:$prefix", $uri);
        }
        $xml->startElement('channel');
        $xml->writeElement('title', $this->title);
        $xml->writeElement('link', $this->link);
        $xml->writeElement('description', $this->description);
        $xml->writeElement('language', 'zh-TW');
        $xml->writeElement('lastBuildDate', date('r'));
        $xml->writeElement('atom:link', ['href' => $this->link . '/feed', 'rel' => 'self', 'type' => 'application/rss+xml']);
        if ($this->imageUrl) {
            $xml->startElement('image');
            $xml->writeElement('url', $this->imageUrl);
            $xml->writeElement('title', $this->title);
            $xml->writeElement('link', $this->link);
            $xml->endElement();
        }
        if (!empty($this->dcData)) {
            $xml->writeElement('dc:creator', $this->dcData['creator']);
            $xml->writeElement('dc:date', $this->dcData['date']);
        }

        foreach ($this->items as $item) {
            $xml->startElement('item');
            $xml->writeElement('title', $item['title']);
            $xml->writeElement('link', $item['link']);
            $xml->writeElement('guid', ['isPermaLink' => 'true'], $item['guid']);
            $xml->writeElement('description', $item['description']);
            $xml->writeElement('dc:creator', $item['author']);
            $xml->writeElement('pubDate', date('r', strtotime($item['pubDate'])));
            $xml->endElement(); // item
        }
        $xml->endElement(); // channel
        $xml->endElement(); // rss
        echo $xml->outputMemory(true);
    }
}

3. 擴充:iTunes Podcast 標籤

$rss->addNamespace('itunes', 'https://www.itunes.com/dtds/podcast-1.0.dtd');
$rss->addNamespace('content', 'https://purl.org/rss/1.0/modules/content/');

// 在 channel 內加入
$xml->writeElement('itunes:author', '作者名');
$xml->writeElement('itunes:summary', 'Podcast 簡介');
$xml->writeElement('itunes:type', 'episodic');
$xml->writeElement('itunes:owner', [
    'itunes:name' => '擁有者',
    'itunes:email' => 'email@example.com',
]);
$xml->writeElement('itunes:explicit', 'false');
$xml->writeElement('itunes:category', ['text' => 'Technology']);
$xml->writeElement('itunes:image', ['href' => 'https://example.com/cover.jpg']);

// 在 item 內加入
$xml->writeElement('itunes:title', '單集標題');
$xml->writeElement('itunes:summary', '單集簡介');
$xml->writeElement('itunes:duration', '45:30');
$xml->writeElement('itunes:explicit', 'false');
$xml->writeElement('enclosure', [
    'url' => 'https://example.com/ep1.mp3',
    'type' => 'audio/mpeg',
    'length' => '12345678',
]);
$xml->writeElement('content:encoded', '');

4. Atom 1.0 產生

function outputAtom($posts, $siteUrl, $title) {
    $xml = new XMLWriter();
    $xml->openMemory();
    $xml->startDocument('1.0', 'UTF-8');
    $xml->startElement('feed');
    $xml->writeAttribute('xmlns', 'https://www.w3.org/2005/Atom');
    $xml->writeElement('title', $title);
    $xml->writeElement('link', ['href' => $siteUrl, 'rel' => 'alternate']);
    $xml->writeElement('link', ['href' => $siteUrl . '/atom', 'rel' => 'self']);
    $xml->writeElement('updated', date('c'));
    $xml->writeElement('id', $siteUrl);
    $xml->writeElement('author', ['name' => '作者']);

    foreach ($posts as $post) {
        $xml->startElement('entry');
        $xml->writeElement('title', $post['title']);
        $xml->writeElement('link', ['href' => $post['url'], 'rel' => 'alternate']);
        $xml->writeElement('id', $post['url']);
        $xml->writeElement('updated', date('c', strtotime($post['date'])));
        $xml->writeElement('summary', $post['desc']);
        $xml->writeElement('content', ['type' => 'html'], $post['content'] ?? $post['desc']);
        $xml->endElement();
    }
    $xml->endElement();
    header('Content-Type: application/atom+xml; charset=UTF-8');
    echo $xml->outputMemory(true);
}

5. 效能與快取

  • Feed 內容變動不頻繁,建議**靜態化**:定時任務產生 feed.xml、atom.xml 放入 public/,Nginx 直接服務靜態檔。
  • HTTP 快取:Cache-Control: public, max-age=3600、ETag、Last-Modified,支援條件請求。
  • 大量文章分頁:?page=2 或依標準 rel="next" 連結。

6. 驗證工具

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved