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

PHP 產生 RSS 2.0 Feed 完整類別:支援自訂標籤、附件與 CDATA

     編輯:PHP 綜合知識

RSS 仍是內容發佈、部落格聚合、播客發布的標準格式。本文提供一組完整、符合 RSS 2.0 規範的 PHP 類別(`RSS` + `RSSItem`),支援頻道層級與項目層級的自訂標籤、發布時間管理、Enclosure 附件(播客必備)、CDATA 內容保護,並附上資料庫整合範例。

類別架構概覽

  • RSS:頻道容器,管理標題、連結、描述、語言、發布時間、自訂標籤、項目集合。
  • RSSItem:單一項目,管理標題、連結、描述、發布時間、GUID、自訂標籤、附件。

核心程式碼(精簡版,完整請見下方)

class RSS {
    public $title = '';
    public $link = '';
    public $description = '';
    public $language = 'zh-TW';
    public $pubDate = '';
    protected $items = [];
    protected $tags = [];

    public function addItem(RSSItem $item): self { $this->items[] = $item; return $this; }
    public function addTag(string $tag, string $value): self { $this->tags[$tag] = $value; return $this; }
    public function setPubDate(string|int $when): self {
        $ts = is_int($when) ? $when : strtotime($when);
        $this->pubDate = $ts ? date('D, d M Y H:i:s', $ts) . ' GMT' : date('D, d M Y H:i:s') . ' GMT';
        return $this;
    }

    public function out(): string {
        $out = $this->header();
        $out .= "<channel>\n";
        $out .= "<title>" . $this->escape($this->title) . "</title>\n";
        $out .= "<link>" . $this->escape($this->link) . "</link>\n";
        $out .= "<description>" . $this->escape($this->description) . "</description>\n";
        $out .= "<language>" . $this->escape($this->language) . "</language>\n";
        $out .= "<pubDate>" . $this->pubDate . "</pubDate>\n";
        foreach ($this->tags as $k => $v) $out .= "<$k>" . $this->escape($v) . "</$k>\n";
        foreach ($this->items as $item) $out .= $item->out();
        $out .= "</channel>\n";
        $out .= $this->footer();
        return str_replace('&', '&', $out); // 最後統一轉義 &
    }

    public function serve(string $contentType = 'application/xml; charset=utf-8'): void {
        header("Content-Type: $contentType");
        echo $this->out();
    }

    protected function header(): string {
        return '<?xml version="1.0" encoding="utf-8"?>' . "\n"
             . '<rss version="2.0" xmlns:dc="https://purl.org/dc/elements/1.1/">' . "\n";
    }
    protected function footer(): string { return '</rss>'; }
    protected function escape(string $s): string { return htmlspecialchars($s, ENT_XML1 | ENT_QUOTES, 'UTF-8'); }
}

class RSSItem {
    public $title = '';
    public $link = '';
    public $description = '';
    public $pubDate = '';
    public $guid = '';
    protected $tags = [];
    protected $enclosure = '';

    public function addTag(string $tag, string $value): self { $this->tags[$tag] = $value; return $this; }
    public function setPubDate(string|int $when): self {
        $ts = is_int($when) ? $when : strtotime($when);
        $this->pubDate = $ts ? date('D, d M Y H:i:s', $ts) . ' GMT' : date('D, d M Y H:i:s') . ' GMT';
        return $this;
    }
    public function enclosure(string $url, string $mimeType, int $length): self {
        $this->enclosure = "<enclosure url='" . $this->escape($url) . "' length='$length' type='" . $this->escape($mimeType) . "' />";
        return $this;
    }
    public function out(): string {
        $out = "<item>\n";
        $out .= "<title>" . $this->escape($this->title) . "</title>\n";
        $out .= "<link>" . $this->escape($this->link) . "</link>\n";
        // 使用 CDATA 保護 HTML 內容
        $out .= "<description><![CDATA[" . $this->description . "]]></description>\n";
        $out .= "<pubDate>" . $this->pubDate . "</pubDate>\n";
        if ($this->enclosure) $out .= $this->enclosure . "\n";
        $out .= "<guid isPermaLink='" . (filter_var($this->guid ?: $this->link, FILTER_VALIDATE_URL) ? 'true' : 'false') . "'>"
             . $this->escape($this->guid ?: $this->link) . "</guid>\n";
        foreach ($this->tags as $k => $v) $out .= "<$k>" . $this->escape($v) . "</$k>\n";
        $out .= "</item>\n";
        return $out;
    }
    protected function escape(string $s): string { return htmlspecialchars($s, ENT_XML1 | ENT_QUOTES, 'UTF-8'); }
}

資料庫整合範例:從 articles 表產生 Feed

<?php
require_once 'RSS.php';

$pdo = new PDO('mysql:host=localhost;dbname=blog;charset=utf8mb4', 'user', 'pass');
$stmt = $pdo->query('SELECT id, title, slug, excerpt, content, created_at FROM articles WHERE status="published" ORDER BY created_at DESC LIMIT 20');

$feed = new RSS();
$feed->title = '我的技術部落格';
$feed->link = 'https://blog.example.com';
$feed->description = '分享 PHP、架構、DevOps 實戰經驗';
$feed->setPubDate(time());

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $item = new RSSItem();
    $item->title = $row['title'];
    $item->link = 'https://blog.example.com/article/' . $row['slug'];
    $item->description = $row['content']; // 完整內容含 HTML
    $item->setPubDate($row['created_at']);
    $item->guid = $item->link;
    // 可選:加入作者、分類等自訂標籤
    $item->addTag('dc:creator', 'Author Name');
    $item->addTag('category', 'PHP');
    $feed->addItem($item);
}

$feed->serve(); // 直接輸出 XML 並設定正確 Content-Type

進階應用:Podcast 專用 Enclosure

$item->enclosure(
    'https://cdn.example.com/episodes/ep001.mp3',
    'audio/mpeg',
    15728640 // 檔案大小 bytes
);
// 產生:

輸出範例(節錄)

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="https://purl.org/dc/elements/1.1/">
<channel>
<title>我的技術部落格</title>
<link>https://blog.example.com</link>
<description>分享 PHP、架構、DevOps 實戰經驗</description>
<language>zh-TW</language>
<pubDate>Mon, 15 Jan 2024 08:30:00 GMT</pubDate>
<item>
<title>PHP 8.2 新特性深度解析</title>
<link>https://blog.example.com/article/php-82-features</link>
<description><![CDATA[<p>PHP 8.2 帶來了 readonly class、DNF 型別...</p>]]></description>
<pubDate>Mon, 15 Jan 2024 08:00:00 GMT</pubDate>
<guid isPermaLink='true'>https://blog.example.com/article/php-82-features</guid>
<dc:creator>Author Name</dc:creator>
<category>PHP</category>
</item>
...
</channel>
</rss>

常見坑點與修正

  • XML 特殊字元:標題、連結等必須 `htmlspecialchars(..., ENT_XML1)`,描述用 CDATA 包裹。
  • 日期格式:RFC 822 / RFC 2822 格式(`D, d M Y H:i:s T`),時區建議用 GMT。
  • GUID 唯一性:若連結固定可作 Permalink,`isPermaLink="true"`;否則用 UUID 或資料庫 ID,設 `false`。
  • 編碼宣告:XML 宣告 `encoding="utf-8"`,資料庫連線 `charset=utf8mb4`,PHP 內部編碼一致。
  • 大量資料記憶體:若項目超過數萬筆,建議改用 XMLWriter 串流輸出,避免記憶體耗盡。

將此類別納入專案共用庫,即可快速為任何內容型網站新增標準 RSS Feed,支援讀者訂閱、聚合平台收錄、播客平台發布等多元場景。

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