Skip to content

AJAX RSS Reader

An RSS (Really Simple Syndication) feed is an XML-based format used to publish frequently updated content like blog posts or news headlines. An RSS Reader fetches and displays content from these feeds. This example shows how to build a simple web-based RSS reader using AJAX, where selecting a feed dynamically loads its content without a full page refresh.

This example uses JavaScript’s fetch API to request data from a PHP backend. The PHP script fetches the selected external RSS feed (XML), parses it, extracts relevant information, and returns it (e.g., as HTML fragments or JSON) to the JavaScript, which then updates the webpage.

Note: Many modern RSS feeds may have CORS (Cross-Origin Resource Sharing) restrictions preventing direct fetching from client-side JavaScript. Fetching via a server-side proxy (like the PHP script shown here) is a common solution.

<!-- Placeholder for a simulated live example -->
<div style="border: 1px solid #ccc; padding: 15px; margin-bottom: 15px;">
<form id="rssForm">
<label for="rssSelect">Select an RSS Feed:</label>
<select name="feeds" id="rssSelect">
<option value="">Select a Feed...</option>
<!-- Note: These URLs might change or become unavailable -->
<option value="NASA">NASA Breaking News</option>
<option value="NYT">New York Times Home Page</option>
<option value="Invalid">Invalid Feed (for testing)</option>
</select>
</form>
<div id="rssOutput" style="margin-top: 15px; padding-top: 10px; border-top: 1px dashed #eee; max-height: 300px; overflow-y: auto;">
**RSS feed content will be listed here...**
</div>
</div>
<script>
document.getElementById('rssSelect').addEventListener('change', function() {
showRSS(this.value);
});
async function showRSS(feedKey) {
const outputElement = document.getElementById("rssOutput");
if (feedKey === "") {
outputElement.innerHTML = "**RSS feed content will be listed here...**";
return;
}
outputElement.innerHTML = "<i>Loading RSS feed...</i>"; // User feedback
try {
// Request the feed content from our PHP proxy script
const url = `get_rss_feed.php?feed=${encodeURIComponent(feedKey)}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// The PHP script returns HTML content directly in this example
const htmlContent = await response.text();
// Display the HTML returned by the PHP script
outputElement.innerHTML = htmlContent;
} catch (error) {
console.error('Fetch error:', error);
outputElement.innerHTML = `<span style='color: red;'>Failed to load RSS feed. ${error.message}</span>`;
}
}
</script>

Example Explained - The HTML & JavaScript (Client-Side)

Section titled “Example Explained - The HTML & JavaScript (Client-Side)”

The HTML contains a dropdown (<select>) allowing the user to choose an RSS feed.

<form id="rssForm">
<label for="rssSelect">Select an RSS Feed:</label>
<select name="feeds" id="rssSelect">
<option value="">Select a Feed...</option>
<option value="NASA">NASA Breaking News</option>
<option value="NYT">New York Times Home Page</option>
<option value="Invalid">Invalid Feed</option>
</select>
</form>
<div id="rssOutput" style="margin-top: 10px; max-height: 300px; overflow-y: auto;">
**RSS feed content will be listed here...**
</div>

When the selection changes:

  1. The showRSS() function is called with the selected feed key (e.g., ‘NASA’, ‘NYT’).
  2. It checks for an empty selection and resets the output area (rssOutput).
  3. Displays a “Loading…” message.
  4. Uses fetch() to send a GET request to the PHP script (get_rss_feed.php), passing the feed key as a query parameter.
  5. Handles potential HTTP errors.
  6. Reads the response body as text (response.text()) because our PHP script will return pre-formatted HTML fragments.
  7. Injects the received HTML content directly into the rssOutput div.
  8. Catches and displays any network or processing errors.
document.getElementById('rssSelect').addEventListener('change', function() {
showRSS(this.value);
});
async function showRSS(feedKey) {
const outputElement = document.getElementById("rssOutput");
if (feedKey === "") { /* ... reset ... */ return; }
outputElement.innerHTML = "<i>Loading RSS feed...</i>";
try {
const response = await fetch(`get_rss_feed.php?feed=${encodeURIComponent(feedKey)}`);
if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); }
const htmlContent = await response.text(); // Expecting HTML from PHP
outputElement.innerHTML = htmlContent;
} catch (error) {
console.error('Fetch error:', error);
outputElement.innerHTML = `<span style='color: red;'>Failed to load RSS feed.</span>`;
}
}

The PHP File (get_rss_feed.php - Server-Side Proxy)

Section titled “The PHP File (get_rss_feed.php - Server-Side Proxy)”

This PHP script acts as a proxy. It takes the feed key from the JavaScript request, looks up the actual RSS feed URL, fetches the external XML feed, parses it using SimpleXML, formats the relevant information into HTML, and sends that HTML back to the JavaScript.

  • Error Handling: Robustly handle cases where the feed URL is invalid, the external server is down, the fetched content isn’t valid XML, or the expected RSS structure is missing.
  • Security: Be cautious about which URLs you allow your script to fetch. Avoid directly using user-supplied URLs without validation.
  • Performance: Fetching and parsing external feeds can be slow. Consider caching results on the server for a period to improve performance and reduce load on the source feed.
  • User Agent: Some feeds might require a specific User-Agent HTTP header. You might need to use cURL instead of file_get_contents to set custom headers.
  1. Define an array mapping feed keys (from the dropdown) to actual RSS feed URLs.
  2. Get the requested feed key from $_GET['feed'].
  3. Check if the key exists in the mapping. If not, return an error message.
  4. Get the corresponding feed URL.
  5. Set up libxml error handling and disable entity loading.
  6. Use @simplexml_load_file() to attempt loading the external feed URL. The @ suppresses PHP warnings on failure, allowing custom error handling.
  7. Check if loading failed ($xml === false). If so, retrieve libxml errors and display an appropriate error message.
  8. If loading succeeded, access the channel information (title, link, description) and item information (title, link, description for each item) using SimpleXML object properties.
  9. Format the extracted information into an HTML string.
  10. Limit the number of displayed items (e.g., the first 5-10).
  11. Echo the generated HTML string.
<?php
// Basic Feed URL Mapping (Add more or use a database)
$feed_urls = [
// URLs are examples and may change/break.
'NASA' => 'https://www.nasa.gov/rss/dyn/breaking_news.rss',
'NYT' => 'https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml',
'Invalid' => 'http://invalid.url/feed.rss' // For testing errors
];
// Get requested feed key
$requested_key = isset($_GET['feed']) ? trim($_GET['feed']) : '';
// Validate key and get URL
if (empty($requested_key) || !array_key_exists($requested_key, $feed_urls)) {
echo "<p style='color: red;'>Error: Invalid or missing feed selected.</p>";
exit;
}
$feed_url = $feed_urls[$requested_key];
// --- Libxml Setup (Error handling & Security) ---
libxml_use_internal_errors(true);
libxml_disable_entity_loader(true);
// --- Fetch and Parse XML ---
// Use @ to suppress warnings on failure, handle manually
// Consider adding timeout context for file_get_contents or using cURL for more control
// Attempt to load the XML file directly from the URL
$xml = @simplexml_load_file($feed_url);
// --- Check for Errors ---
if ($xml === false) {
echo "<p style='color: red;'>Error loading or parsing RSS feed: " . htmlspecialchars($feed_url) . "</p>";
echo "<ul>";
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo "<li>" . htmlspecialchars(trim($error->message)) . " (Line: {$error->line})</li>";
}
echo "</ul>";
libxml_clear_errors();
exit;
}
// --- Process and Format Output ---
$output_html = '';
// Channel Information (Check if elements exist)
$channel_title = isset($xml->channel->title) ? (string)$xml->channel->title : 'Unknown Title';
$channel_link = isset($xml->channel->link) ? (string)$xml->channel->link : '#';
$channel_desc = isset($xml->channel->description) ? (string)$xml->channel->description : '';
$output_html .= "<h3><a href='" . htmlspecialchars($channel_link) . "' target='_blank'>" . htmlspecialchars($channel_title) . "</a></h3>";
if (!empty($channel_desc)) {
$output_html .= "<p><em>" . htmlspecialchars($channel_desc) . "</em></p>";
}
$output_html .= "<hr>";
// Item Information (Loop through items, limit count)
$item_limit = 5; // Show max 5 items
$item_count = 0;
if (isset($xml->channel->item)) {
$output_html .= "<ul>";
foreach ($xml->channel->item as $item) {
if ($item_count >= $item_limit) {
break;
}
$item_title = isset($item->title) ? (string)$item->title : 'No Title';
$item_link = isset($item->link) ? (string)$item->link : '#';
$item_desc = isset($item->description) ? (string)$item->description : ''; // Often contains HTML
$output_html .= "<li>";
$output_html .= "**<a href='" . htmlspecialchars($item_link) . "' target='_blank'>" . htmlspecialchars($item_title) . "</a>**";
// Basic sanitization if displaying description HTML, otherwise use htmlspecialchars
// A proper HTML sanitizer library (like HTML Purifier) is recommended for production
if (!empty($item_desc)) {
$output_html .= "<div>" . strip_tags($item_desc, '<p><br><a><img>**<i><em>**') . "</div>"; // Example: Allow some basic tags
}
$output_html .= "</li>";
$item_count++;
}
$output_html .= "</ul>";
} else {
$output_html .= "<p>No items found in this feed.</p>";
}
// --- Output the generated HTML ---
echo $output_html;
?>

This example demonstrates fetching external XML data via a PHP proxy and dynamically updating the page, a common pattern for interacting with third-party services or overcoming browser restrictions.