Tiffany B. Brown

a mish-mosh of stuff

Dynamic RSS feeds using PHP, MySQL and Apache

UPDATE: I wrote this code a while ago, and haven’t really updated it since. There may be some a bug within. Depending on your set up, this tutorial may not even work for you. If you’re a copy-and-paster (and can’t debug PHP and MySQL scripts), you may not want to use this tutorial. There are some helpful bits in the comments. Please read them before contacting me.

I will update when I have the time and energy to go through it properly.

PHP and MySQL can be used to create dynamically-generated HTML pages. But with a little more know-how, you can also use this combo with Apache to create a dynamically-updated RSS feed.

Sure, most blogging software packages generate their own feeds. But why use them, when creating your own is so much geekier?

What you’ll need

I’m assuming you’re already using a PHP & MySQL-based publishing system, and that you’ve got database full of content.

You’ll also need the ability to use .htaccess files (or have access to your server’s configuration file).

RSS is pretty simple to pick up. The code in this article will give you a basic feed. If you’d like a more complex feed, consult the RSS 2.0 specification.

Step 1: Create the .htaccess file

RSS files, like all XML files, are static text. To make our feed dynamic, we’re going to tell our server to treat files with an .xml extension as PHP files.

To do that, simply create a file named .htaccess. Add AddType application/x-httpd-php .xml and save it to your server. If you have access to your server’s configuration (httpd.conf) file, you can put the AddType declaration there instead.

Keep in mind that this will cause all files with an .xml extension in that directory (or on your server) to be parsed as PHP.

Step 2: Set the header

By default, PHP sends text with an HTML content type. As a result, your aggregator may not recognize it as a valid RSS / XML file.

Enter the header() function. We’ll put the following header near the top of our script, before any text gets sent to the client.

<? header('Content-type: text/xml'); ?>

Step 3: A basicBegin the feed

A basic RSS document consists of a channel. Within each channel are items. At minimum, each item requires a title, description and link. In this example, we’re also going to add a publication date.

Your feed should start off like this:

<rss version="2.0">
<channel>
<title>Name of your site</title>
<description>A description of your site</description>
<link>http://yoururl.com/</link>
<copyright>Your copyright information</copyright>

Step 4: Retrieve articles from the database

For this example, let’s say we’ve got a table named ‘articles’ with four fields: id, title, body and pubDate (for ‘date published’).

We’ll need a title, description and publication date for each item. We’ll also need each item’s id to create the page link. Our SQL query might look like this (assumes the database host name, user name and such are already available I’m going to assume that you have already established a link to your database):

<?
$q="SELECT id,title,body,UNIX_TIMESTAMP(pubDate) AS pubDate
FROM articles LIMIT 0,15 ORDER BY pubDate DESC";
$doGet=mysql_query($q);
?>

Let’s examine the query. We’re selecting the id, title and body for most recent eight fifteen entries. That’s the maximum number of items that can be included in a valid RSS feed.

We’re also telling MySQL to retrieve the pubDate field as a UNIX time stamp, and save it in an array (or an you can save it as an object if you prefer). We’ll need a UNIX-style time stamp to generate a publication date.

Step 4: Build the feed Add your items

Now we get to the good stuff: Building the actual feed. We’ll take the code above, and add the following lines.


<?

while($item=mysql_fetch_array($doGet))
 {
  $id=$doGet['id'];
  $title=strip_tags($doGet['title']);
  $body=strip_tags($doGet['body']);
  $body=substr($doGet['body'],0,150);
  $=strftime("%a, %d %b %Y %T %Z",$doGet['']);
 }

?>


<?
while($result = mysql_fetch_array($doGet)){
?>
     <item>
        <title> <?=htmlentities(strip_tags($result['title'])); ?></title>
        <description> <?=htmlentities(strip_tags($result['body'],'ENT_QUOTES'));?></description>
        <link>http://yoururl.com/pathtostory/and_page.php?p=<?=$result['id'];?></link>
        <pubDate> <?=strftime( "%a, %d %b %Y %T %Z" , $result['pubDate']); ?></pubDate>
     </item>  
<? } ?>  



The code above does the following:

  1. Stores the query results as an array (using mysql_fetch_array())
  2. Escapes HTML entities in the title and body (using htmlentities())
  3. Strips the HTML tags out of title and body (using strip_tags())
  4. Generates a valid date stamp (using strftime())


That code above is essentially the RSS feed. Using a while loop, we’re making the script output an RSS item for each row returned from the database. We’re also using strip_tags() and htmlentities() to strip HTML from the title and body, and to escape ampersands and quotes.

All that’s left is to add the closing tags for the channel and document.


Step 4: Build the feed

Now we get to the good stuff: Building the actual feed. We’ll take the code above, and add the following lines.

<?
while($item=mysql_fetch_array($doGet)
 {
  $id=$doGet['id'];
  $title=strip_tags($doGet['title']);
  $body=strip_tags($doGet['body']);
  $body=substr($doGet['body'],0,150));
  $=strftime("%a, %d %b %Y %T %Z",$doGet['']);

  // output to client

?>

  <item>
  <title><?print htmlentities($title,’ENT_QUOTES’);?></title>
  <description><?print htmlentities($body,’ENT_QUOTES’);?></description>
  <link>http://your_url/path/and_page.php?article=<?print $id;?></link>
  <><?print $;?></>
  </item>

<? } ?>

</channel>
</rss>

Because RSS feeds can’t contain special characters, you’ll want to convert apostrophes, quotes and similar characters to their respective entities using htmlentities(). Then you’ll need to add the closing tags for the channel and document.

From beginning-to-end, your script should look a bit like this:

<? header('Content-type: text/xml'); ?>

<rss version="2.0">
<channel>
<title>Name of your site</title>
<description>A description of your site</description>
<link>http://your_home_page_url/</link>
<copyright>Your copyright information</copyright>

<?
$q="SELECT id,title,body,UNIX_TIMESTAMP(pubDate) AS pubDate
FROM articles LIMIT 0,15 ORDER BY pubDate DESC";
$doGet=mysql_query($q);

while($result = mysql_fetch_array($doGet)){
?>
     <item>
        <title> <?=htmlentities(strip_tags($result['title'])); ?></title>
        <description> <?=htmlentities(strip_tags($result['body'],'ENT_QUOTES'));?></description>
        <link>http://yoururl.com/pathtostory/and_page.php?p=<?=$result['id'];?></link>
        <pubDate> <?=strftime( "%a, %d %b %Y %T %Z" , $result['pubDate']); ?></pubDate>
     </item>  
<? } ?>  

</channel>
</rss>

By the way, if you wish to have cleaner URIs (instead of filename.php?article=1), read Creating clean URIs with PHP.

Step 5: Validate and announce

Before you make your feed “live,” don’t forget to check it with a validator. An invalid feed can cause problems with aggregators and browsers. There are several web-based validation tools such as Feed Validator that make validation a snap.


UPDATE: You can also let aggregators find your feed automatically.

  • http://www.crackme.co.uk/ ryan partington

    HEY!

    Hope you’re all well

    I’m having problems with one aspect, my header request is being passed to the client!

    More details here: http://www.experts-exchange.com/Web/Web_Servers/Apache/Q_22074448.html I don’t want to spam your board.

    Cheers,
    Parto

  • http://www.crackme.co.uk ryan partington

    HEY!

    Hope you’re all well

    I’m having problems with one aspect, my header request is being passed to the client!

    More details here: http://www.experts-exchange.com/Web/Web_Servers/Apache/Q_22074448.html I don’t want to spam your board.

    Cheers,
    Parto

  • http://www.Property-List.net/ Jay

    Tiffany:
    I have managed to produce an feed using your methods described here, thanks for that.
    Now that I have my info in feed format, I want to tell the Feed Readers how to display it, any advice on how to make the Readers display my info in HTML within the readers (I want to put it in tables.)? My existing attempt works only in one Reader and the rest display the information but in a one line format.
    Your input will be appreciated,
    Jay

  • http://www.Property-List.net Jay

    Tiffany:
    I have managed to produce an feed using your methods described here, thanks for that.
    Now that I have my info in feed format, I want to tell the Feed Readers how to display it, any advice on how to make the Readers display my info in HTML within the readers (I want to put it in tables.)? My existing attempt works only in one Reader and the rest display the information but in a one line format.
    Your input will be appreciated,
    Jay

  • http://www.tiffanybbrown.com/ tiffany

    @Jay: you can use CSS to give it some styling, and you can also escape your HTML (for tables) by enclosing it in a CDATA section.

    But why do you want it to appear in tables (unless it’s tabular data)?

  • http://www.tiffanybbrown.com/ tiffany

    @Jay: you can use CSS to give it some styling, and you can also escape your HTML (for tables) by enclosing it in a CDATA section.

    But why do you want it to appear in tables (unless it’s tabular data)?

  • http://deimosdesigns.com/ JeffyD

    what if some items in the database contain special characters that xml doesn’t like? IS there a script to replace them with xml friendly characters.

  • http://deimosdesigns.com JeffyD

    what if some items in the database contain special characters that xml doesn’t like? IS there a script to replace them with xml friendly characters.

  • http://www.tiffanybbrown.com/ tiffany

    It depends on what those characters are. You can use PHP’s htmlentities() function, or enclose them in a CDATA section.

  • http://www.tiffanybbrown.com/ tiffany

    It depends on what those characters are. You can use PHP’s htmlentities() function, or enclose them in a CDATA section.

  • Jay

    Tiffany:
    You must be some kinda’ Angel or something, thanks for your help with the Feeds.
    Jay

  • Jay

    Tiffany:
    You must be some kinda’ Angel or something, thanks for your help with the Feeds.
    Jay

  • http://www.ihsrealty.com/ Lawrence

    I looked all over for this. Thanks!

  • http://www.ihsrealty.com Lawrence

    I looked all over for this. Thanks!

  • http://shadowedvisions.no-ip.org/ Brian

    Wow. Thank you so much for this. I’ve been looking everywhere for a place to get started with RSS/XML, but this is the only place I’ve found that puts it nice a simple.

  • http://shadowedvisions.no-ip.org Brian

    Wow. Thank you so much for this. I’ve been looking everywhere for a place to get started with RSS/XML, but this is the only place I’ve found that puts it nice a simple.

  • Michael

    Hello,

    Fantastic code.

    I’ve done this myself, but wasn’t too sure in what format to store the “pubDate” variable in my table of the database.

    Should I have one field that stores the time and date of the published feed?

    Obviously this is the format : Tue, 10 Jun 2003 09:41:01 GMT, but is that the way it should be written into the db ?

    Thanks tiffany, you’re a star!

  • Michael

    Hello,

    Fantastic code.

    I’ve done this myself, but wasn’t too sure in what format to store the “pubDate” variable in my table of the database.

    Should I have one field that stores the time and date of the published feed?

    Obviously this is the format : Tue, 10 Jun 2003 09:41:01 GMT, but is that the way it should be written into the db ?

    Thanks tiffany, you’re a star!

  • http://www.tiffanybbrown.com/ tiffany

    @Michael: store it in the DB as a MySQL date or time stamp, then use MySQL’s UNIX_TIMESTAMP function to convert it to a Unix time stamp. Then you can manipulate it using the PHP strftime() function.

    You can also store a Unix timestamp as a number, and skip the UNIX_TIMESTAMP step.

  • http://www.tiffanybbrown.com/ tiffany

    @Michael: store it in the DB as a MySQL date or time stamp, then use MySQL’s UNIX_TIMESTAMP function to convert it to a Unix time stamp. Then you can manipulate it using the PHP strftime() function.

    You can also store a Unix timestamp as a number, and skip the UNIX_TIMESTAMP step.

  • http://www.tyleringram.com/ Tyler Ingram

    Yay I found a place that talks about what the proper header() format is for an XML document, now I can create custom, dynamic RSS feeds for my subscribers.

    Thanks!

  • http://www.tyleringram.com Tyler Ingram

    Yay I found a place that talks about what the proper header() format is for an XML document, now I can create custom, dynamic RSS feeds for my subscribers.

    Thanks!

  • ako

    this cant work for me. When i use .htaccess the script shows white page, and other .xml in my site does not work.
    help?

  • ako

    this cant work for me. When i use .htaccess the script shows white page, and other .xml in my site does not work.
    help?

  • http://www.ksquaredmedia.com/ Keith

    Thank you so much, this was so easy to implement!
    Cheers!

  • http://www.ksquaredmedia.com Keith

    Thank you so much, this was so easy to implement!
    Cheers!

  • http://www.virtualrevolution.net/ Rhyaniwyn

    Thanks for the tutorial. This was exactly what I wanted to do. I was considering using PHP to write my RSS feed to a separate XML file. Using AddType did not occur to me! This was faster and simpler.

    Remember, depending upon your host’s server setup, certain .htaccess options may not be allowed, or .htaccess can be disabled entirely. Some problems can be explained by that. In such cases, doing as “bard” mentioned in comment #3292 may help.

    Putting both the .htaccess with the AddType directive and your RSS feed in a subdirectory are good ideas anyway–parsing all XML files as PHP can interfere with declarations. That is, if you are using other XML files, or plan to in the future.

  • http://www.virtualrevolution.net/ Rhyaniwyn

    Thanks for the tutorial. This was exactly what I wanted to do. I was considering using PHP to write my RSS feed to a separate XML file. Using AddType did not occur to me! This was faster and simpler.

    Remember, depending upon your host’s server setup, certain .htaccess options may not be allowed, or .htaccess can be disabled entirely. Some problems can be explained by that. In such cases, doing as “bard” mentioned in comment #3292 may help.

    Putting both the .htaccess with the AddType directive and your RSS feed in a subdirectory are good ideas anyway–parsing all XML files as PHP can interfere with declarations. That is, if you are using other XML files, or plan to in the future.

  • http://www.phicreativity.com/ Vishakha

    Thanks a lot!!!!
    This worked out for me. Using AddType really helped a lot.

  • http://www.phicreativity.com Vishakha

    Thanks a lot!!!!
    This worked out for me. Using AddType really helped a lot.

  • http://biometria.gov.ar/ Nicolas

    Tiffany:

    Great tutorial, simple and smart. This was so easy to implement. Though I have a problem that was mentioned here before: The data in my database has special characters (i.e.: é) that cause the XML to be not valid. I tried everything but nothing seem to work. Also I have PHP 4.1 so I couldn’t try some of the newer functions, like html_entity_code.
    What should I do? I’m so close!! Do you have an alternative workaround to this problem? thanks a lot from Buenos Aires, ARG.

  • http://biometria.gov.ar Nicolas

    Tiffany:

    Great tutorial, simple and smart. This was so easy to implement. Though I have a problem that was mentioned here before: The data in my database has special characters (i.e.: é) that cause the XML to be not valid. I tried everything but nothing seem to work. Also I have PHP 4.1 so I couldn’t try some of the newer functions, like html_entity_code.
    What should I do? I’m so close!! Do you have an alternative workaround to this problem? thanks a lot from Buenos Aires, ARG.

  • http://www.tiffanybbrown.com/ tiffany

    Nicolas,

    Have you tried html_entities()? That works with PHP 4.x.

    Another possible solution would be to use str_replace(). With that function, you can use an array for both the find and replace parameters.

    Create an array of characters that would need to be replaced and another array with their corresponding entities.

  • http://www.tiffanybbrown.com/ tiffany

    Nicolas,

    Have you tried html_entities()? That works with PHP 4.x.

    Another possible solution would be to use str_replace(). With that function, you can use an array for both the find and replace parameters.

    Create an array of characters that would need to be replaced and another array with their corresponding entities.

  • http://www.cheezylu.com/ Steph

    I’m new to this whole RSS thing and am having problems. Perhaps someone can help… I have done all the steps above and it appears to be ignoring everything between the <code></code> and the <code></code> tags.

    It actually worked once and then when I refreshed the page, all the entries disappeared and I haven’t been able to view them again. Any ideas? I know I must be doing something wrong, but I can’t figure out
    what.

    Here is the RSS page… http://www.aear.org/feed/rss.php

    This page shows the entires that are in the database… http://www.aear.org/stories.php

  • http://www.cheezylu.com Steph

    I’m new to this whole RSS thing and am having problems. Perhaps someone can help… I have done all the steps above and it appears to be ignoring everything between the <code></code> and the <code></code> tags.

    It actually worked once and then when I refreshed the page, all the entries disappeared and I haven’t been able to view them again. Any ideas? I know I must be doing something wrong, but I can’t figure out
    what.

    Here is the RSS page… http://www.aear.org/feed/rss.php

    This page shows the entires that are in the database… http://www.aear.org/stories.php

  • http://www.cheezylu.com/ Steph

    What I meant to say above is… it appears to be ignoring everything between the “End Copyright” and the “End Channel” tags.

  • http://www.cheezylu.com Steph

    What I meant to say above is… it appears to be ignoring everything between the “End Copyright” and the “End Channel” tags.

  • http://www.playvinyl.net/ Tom

    hi. I’m on a windows server, im .htaccess wont work… please can you suggest an alternative?

    thanks
    tom

  • http://www.playvinyl.net Tom

    hi. I’m on a windows server, im .htaccess wont work… please can you suggest an alternative?

    thanks
    tom

  • Randall

    TOM: Rent a cheap Unix server and set it up.

  • Randall

    TOM: Rent a cheap Unix server and set it up.

  • http://www.tiffanybbrown.com/ tiffany

    @randall: no smart-assery allowed :-) .

    @tom: if you can’t use .htaccess, you can just keep a .php extension on the file so your server parses it correctly.

  • http://www.tiffanybbrown.com/ tiffany

    @randall: no smart-assery allowed :-) .

    @tom: if you can’t use .htaccess, you can just keep a .php extension on the file so your server parses it correctly.

  • http://www.tiffanybbrown.com/ tiffany

    Steph, I can’t tell what the problem is by looking at the file. You may have a mis-matched variable name or some other error. Check your server error logs and see if something is wonky.

  • http://www.tiffanybbrown.com/ tiffany

    Steph, I can’t tell what the problem is by looking at the file. You may have a mis-matched variable name or some other error. Check your server error logs and see if something is wonky.

  • Pingback: Database to RSS/XML - WickedFire - Affiliate Marketing Forum - Internet Marketing Webmaster SEO Forum

  • http://www.tropicaan.com/ Matty

    Awesome article! Thanks heaps =)

  • http://www.tropicaan.com Matty

    Awesome article! Thanks heaps =)

  • http://www.cheezylu.com/ Steph

    This is the error I’m getting in my logs…

    “PHP Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource”

    It seems to have a problem with this line…

    “while($result = mysql_fetch_array($doGet)){”

    Thoughts?