From bf0d9ebebd8fd9834956bd6c1046a204b29782eb Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 29 Jul 2025 18:32:57 -0400 Subject: [PATCH] added rss_feed.php --- docs/TODO.md | 4 +- src/classes/rss_feed.php | 132 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/classes/rss_feed.php diff --git a/docs/TODO.md b/docs/TODO.md index 026c923..fc6c9d3 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -41,7 +41,7 @@ [x] → End/Open Tag Matching - [x] → UUIDv7 for APIs? + [x] → UUIDv7 for APIs, etc... [ ] → Rate Limiting @@ -68,6 +68,6 @@ [ ] → Tests - [ ] → RSS Feed + [x] → RSS Feed [x] → Private API for Sensitive Transactions: diff --git a/src/classes/rss_feed.php b/src/classes/rss_feed.php new file mode 100644 index 0000000..895c757 --- /dev/null +++ b/src/classes/rss_feed.php @@ -0,0 +1,132 @@ + + * @copyright (c) 2025, Robert Strutts + * @license MIT + */ + +namespace CodeHydrater; + +class rss_feed { + + public static function generate_rss_feed(array $root, array $items) { + +// Create the XML document + $rss = new \DOMDocument('1.0', 'UTF-8'); + $rss->formatOutput = true; + +// Create the RSS root element + $rssElement = $rss->createElement('rss'); + $rssElement->setAttribute('version', '2.0'); + $rssElement->setAttribute('xmlns:atom', 'http://www.w3.org/2005/Atom'); + $rssRoot = $rss->appendChild($rssElement); + +// Create the channel element + $channel = $rss->createElement('channel'); + $channel = $rssRoot->appendChild($channel); + +// Add atom:link for self-reference + $atomLink = $rss->createElement('atom:link'); + $rss_feed_link = $root['feed_link'] ?? false; + if ($rss_feed_link === false) { + throw new \Exception("Unknown Feed Link"); + } + $atomLink->setAttribute('href', $rss_feed_link); + $atomLink->setAttribute('rel', 'self'); + $atomLink->setAttribute('type', 'application/rss+xml'); + $channel->appendChild($atomLink); + +// Add required channel elements + $title = $root["title"] ?? "News"; + $channel->appendChild($rss->createElement('title', $title)); + $site_link = $root["site_link"] ?? false; + if ($site_link === false) { + throw new \Exception("Unknown Site Link"); + } + $channel->appendChild($rss->createElement('link', $site_link)); + $desc = $root["description"] ?? "Latest news from My Website"; + $channel->appendChild($rss->createElement('description', $desc)); + +// Optional channel elements + $lang = $root['lang'] ?? "en-us"; + $channel->appendChild($rss->createElement('language', $lang)); + $pub_date = $root['pub_date'] ?? date(DATE_RSS); + $channel->appendChild($rss->createElement('pubDate', $pub_date)); + $build_date = $root['last_build_date'] ?? date(DATE_RSS); + $channel->appendChild($rss->createElement('lastBuildDate', $build_date)); + $channel->appendChild($rss->createElement('generator', 'RSS Generator')); + +// Add items to the channel + foreach ($items as $itemData) { + $item = $rss->createElement('item'); + $item = $channel->appendChild($item); + + $item->appendChild($rss->createElement('title', $itemData['title'])); + $item->appendChild($rss->createElement('link', $itemData['link'])); + $item->appendChild($rss->createElement('description', $itemData['description'])); + $item->appendChild($rss->createElement('pubDate', $itemData['pubDate'])); + + // GUID should be a permalink + $guid = $rss->createElement('guid', $itemData['guid']); + $guid->setAttribute('isPermaLink', 'true'); + $item->appendChild($guid); + + // Optional item elements + if (isset($itemData['author'])) { + $item->appendChild($rss->createElement('author', $itemData['author'])); + } + } + + return $rss; + + } + + public static function save_to_xml_file(\DOMDocument $rss, string $filename = "feed") { + if (! defined("BaseDir") ) { + throw new \Exception("BaseDir not Set!"); + } + $safe_file = BaseDir . "/public/" . preg_replace('/[^A-Za-z0-9]/', '', $filename) . ".xml"; + + $result = $rss->save($safe_file); + if ($result === false) { + throw new \Exception("Failed to save RSS feed to file"); + } + +// echo "Saved XML file: " . $safe_file; + + return true; + } + + + public static function output_rss(\DOMDocument $rss): void { + // Set the content type to XML + header('Content-Type: application/rss+xml; charset=utf-8'); + echo $rss->saveXML(); + } +} + + +/** +// Sample items - in a real application, these would come from a database + $items = [ + [ + 'title' => 'First Article', + 'link' => 'http://example.com/article1', + 'description' => 'This is the description of the first article.', + 'pubDate' => date(DATE_RSS, strtotime('-2 days')), + 'guid' => 'http://example.com/article1', + 'author' => 'author@example.com (John Doe)' + ], + [ + 'title' => 'Second Article', + 'link' => 'http://example.com/article2', + 'description' => 'This is the description of the second article.', + 'pubDate' => date(DATE_RSS, strtotime('-1 day')), + 'guid' => 'http://example.com/article2', + 'author' => 'author@example.com (Jane Smith)' + ] + ]; + */ \ No newline at end of file